AmfphpCharsetConverter.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. /**
  3. * This file is part of amfPHP
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the license that is bundled
  8. * with this package in the file license.txt.
  9. */
  10. /**
  11. * Converts strings to the right encoding in incoming and outgoing packets.
  12. * This plugin can be deactivated if all three tiers (DB, PHP, client) use the same charset, usually utf8.
  13. * This works for nested objects.
  14. *
  15. * @package Amfphp_Plugins_CharsetConverter
  16. * @author Ariel Sommeria-Klein
  17. */
  18. class AmfphpCharsetConverter {
  19. /**
  20. * don't do anything
  21. */
  22. const METHOD_NONE = 'none';
  23. /**
  24. * uses the iconv library for reencoding
  25. */
  26. const METHOD_ICONV = 'iconv';
  27. /**
  28. * uses the mbstring library for reencoding
  29. */
  30. const METHOD_MBSTRING = 'mbstring';
  31. /**
  32. * uses the recode library for reencoding
  33. */
  34. const METHOD_RECODE = 'recode';
  35. /**
  36. * uses the XML function utf8_decode and encode for reencoding - ISO-8859-1 only
  37. */
  38. const METHOD_UTF8_DECODE = 'utf8_decode';
  39. /**
  40. * the reencoding method. One of the METHOD_XXX consts defined above.
  41. * @var String
  42. */
  43. public $method;
  44. /**
  45. * transliterate direction
  46. */
  47. const DIRECTION_PHP_TO_CLIENT = 0;
  48. /**
  49. * transliterate direction
  50. */
  51. const DIRECTION_CLIENT_TO_PHP = 1;
  52. /**
  53. * the Charset that is used in php default utf-8.
  54. * See all the possible codepages for iconv here:
  55. * http://www.gnu.org/software/libiconv/
  56. *
  57. * @var String
  58. */
  59. public $phpCharset;
  60. /**
  61. * the Charset that is used by the client. default utf-8
  62. * See all the possible codepages for iconv here:
  63. * http://www.gnu.org/software/libiconv/
  64. *
  65. * @var String
  66. */
  67. public $clientCharset;
  68. /**
  69. * constructor.
  70. * @param array $config optional key/value pairs in an associative array. Used to override default configuration values.
  71. */
  72. public function __construct(array $config = null) {
  73. //defaults
  74. $this->clientCharset = 'utf-8';
  75. $this->phpCharset = 'utf-8';
  76. $this->method = self::METHOD_NONE;
  77. if($config){
  78. if(isset ($config['clientCharset'])){
  79. $this->clientCharset = $config['clientCharset'];
  80. }
  81. if(isset ($config['phpCharset'])){
  82. $this->phpCharset = $config['phpCharset'];
  83. }
  84. if(isset ($config['method'])){
  85. $this->method = $config['method'];
  86. }
  87. }
  88. //only add filters if conversion is necessary
  89. if($this->method == self::METHOD_NONE){
  90. return;
  91. }
  92. if($this->clientCharset == $this->phpCharset){
  93. return;
  94. }
  95. $filterManager = Amfphp_Core_FilterManager::getInstance();
  96. $filterManager->addFilter(Amfphp_Core_Gateway::FILTER_DESERIALIZED_REQUEST, $this, 'filterDeserializedRequest');
  97. $filterManager->addFilter(Amfphp_Core_Gateway::FILTER_DESERIALIZED_RESPONSE, $this, 'filterDeserializedResponse');
  98. }
  99. /**
  100. * converts untyped objects to their typed counterparts. Loads the class if necessary
  101. * @param mixed $deserializedRequest
  102. * @return mixed
  103. */
  104. public function filterDeserializedRequest($deserializedRequest){
  105. $deserializedRequest = Amfphp_Core_Amf_Util::applyFunctionToContainedObjects($deserializedRequest, array($this, 'convertStringFromClientToPhpCharsets'));
  106. if(class_exists('AmfphpMonitor', false)){
  107. AmfphpMonitor::addTime('Request Charset Conversion');
  108. }
  109. return $deserializedRequest;
  110. }
  111. /**
  112. * looks at the response and sets the explicit type field so that the serializer sends it properly
  113. * @param mixed $deserializedResponse
  114. * @return mixed
  115. */
  116. public function filterDeserializedResponse($deserializedResponse){
  117. $deserializedResponse = Amfphp_Core_Amf_Util::applyFunctionToContainedObjects($deserializedResponse, array($this, 'convertStringFromPhpToClientCharsets'));
  118. if(class_exists('AmfphpMonitor', false)){
  119. AmfphpMonitor::addTime('Response Charset Conversion');
  120. }
  121. return $deserializedResponse;
  122. }
  123. /**
  124. * convert the string. finds the proper encoding depending on direction
  125. * @param String $string data to convert
  126. * @param int $direction one of the DIRECTION_XXX consts described above
  127. * @return String
  128. */
  129. protected function transliterate($string, $direction)
  130. {
  131. if($this->clientCharset == $this->phpCharset){
  132. return $string;
  133. }
  134. $fromCharset = null;
  135. $toCharset = null;
  136. if($direction == self::DIRECTION_CLIENT_TO_PHP){
  137. $fromCharset = $this->clientCharset;
  138. $toCharset = $this->phpCharset;
  139. }else{
  140. $fromCharset = $this->phpCharset;
  141. $toCharset = $this->clientCharset;
  142. }
  143. switch($this->method)
  144. {
  145. case self::METHOD_NONE :
  146. return $string;
  147. case self::METHOD_ICONV:
  148. return iconv($fromCharset, $toCharset, $string);
  149. case self::METHOD_UTF8_DECODE:
  150. return ($direction == self::DIRECTION_CLIENT_TO_PHP ? utf8_decode($string) : utf8_encode($string));
  151. case self::METHOD_MBSTRING:
  152. return mb_convert_encoding($string, $fromCharset, $toCharset);
  153. case self::METHOD_RECODE:
  154. return recode_string($fromCharset . '..' . $toCharset, $string);
  155. default:
  156. return $string;
  157. }
  158. }
  159. /**
  160. * converts the strings
  161. * note: This is not a recursive function. Rather the recursion is handled by Amfphp_Core_Amf_Util::applyFunctionToContainedObjects.
  162. * must be public so that Amfphp_Core_Amf_Util::applyFunctionToContainedObjects can call it
  163. * @param mixed $obj
  164. * @return mixed
  165. */
  166. public function convertStringFromClientToPhpCharsets($obj){
  167. if(!is_string($obj)){
  168. return $obj;
  169. }
  170. return $this->transliterate($obj, self::DIRECTION_CLIENT_TO_PHP);
  171. }
  172. /**
  173. * note: This is not a recursive function. Rather the recusrion is handled by Amfphp_Core_Amf_Util::applyFunctionToContainedObjects.
  174. * must be public so that Amfphp_Core_Amf_Util::applyFunctionToContainedObjects can call it
  175. *
  176. * @param mixed $obj
  177. * @return mixed
  178. */
  179. public function convertStringFromPhpToClientCharsets($obj){
  180. if(!is_string($obj)){
  181. return $obj;
  182. }
  183. return $this->transliterate($obj, self::DIRECTION_PHP_TO_CLIENT);
  184. }
  185. }
  186. ?>