PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/adodb/drivers/adodb-mssql_n.inc.php

https://github.com/dongsheng/moodle
PHP | 246 lines | 119 code | 36 blank | 91 comment | 22 complexity | 41ae2eac67e2520e97217abbfc1507a8 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, GPL-3.0, Apache-2.0, LGPL-2.1
  1. <?php
  2. /// $Id $
  3. ///////////////////////////////////////////////////////////////////////////
  4. // //
  5. // NOTICE OF COPYRIGHT //
  6. // //
  7. // ADOdb - Database Abstraction Library for PHP //
  8. // //
  9. // Latest version is available at https://adodb.org //
  10. // //
  11. // Copyright (c) 2000-2014 John Lim (jlim\@natsoft.com.my) //
  12. // All rights reserved. //
  13. // Released under both BSD license and LGPL library license. //
  14. // Whenever there is any discrepancy between the two licenses, //
  15. // the BSD license will take precedence //
  16. // //
  17. // Moodle - Modular Object-Oriented Dynamic Learning Environment //
  18. // http://moodle.com //
  19. // //
  20. // Copyright (C) 2001-3001 Martin Dougiamas http://dougiamas.com //
  21. // (C) 2001-3001 Eloy Lafuente (stronk7) http://contiento.com //
  22. // //
  23. // This program is free software; you can redistribute it and/or modify //
  24. // it under the terms of the GNU General Public License as published by //
  25. // the Free Software Foundation; either version 2 of the License, or //
  26. // (at your option) any later version. //
  27. // //
  28. // This program is distributed in the hope that it will be useful, //
  29. // but WITHOUT ANY WARRANTY; without even the implied warranty of //
  30. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
  31. // GNU General Public License for more details: //
  32. // //
  33. // http://www.gnu.org/copyleft/gpl.html //
  34. // //
  35. ///////////////////////////////////////////////////////////////////////////
  36. /**
  37. * MSSQL Driver with auto-prepended "N" for correct unicode storage
  38. * of SQL literal strings. Intended to be used with MSSQL drivers that
  39. * are sending UCS-2 data to MSSQL (FreeTDS and ODBTP) in order to get
  40. * true cross-db compatibility from the application point of view.
  41. */
  42. // security - hide paths
  43. if (!defined('ADODB_DIR')) die();
  44. // one useful constant
  45. if (!defined('SINGLEQUOTE')) define('SINGLEQUOTE', "'");
  46. include_once(ADODB_DIR.'/drivers/adodb-mssql.inc.php');
  47. class ADODB_mssql_n extends ADODB_mssql {
  48. var $databaseType = "mssql_n";
  49. function _query($sql,$inputarr=false)
  50. {
  51. $sql = $this->_appendN($sql);
  52. return ADODB_mssql::_query($sql,$inputarr);
  53. }
  54. /**
  55. * This function will intercept all the literals used in the SQL, prepending the "N" char to them
  56. * in order to allow mssql to store properly data sent in the correct UCS-2 encoding (by freeTDS
  57. * and ODBTP) keeping SQL compatibility at ADOdb level (instead of hacking every project to add
  58. * the "N" notation when working against MSSQL.
  59. *
  60. * The original note indicated that this hack should only be used if ALL the char-based columns
  61. * in your DB are of type nchar, nvarchar and ntext, but testing seems to indicate that SQL server
  62. * doesn't seem to care if the statement is used against char etc fields.
  63. *
  64. * @todo This function should raise an ADOdb error if one of the transformations fail
  65. *
  66. * @param mixed $inboundData Either a string containing an SQL statement
  67. * or an array with resources from prepared statements
  68. *
  69. * @return mixed
  70. */
  71. function _appendN($inboundData) {
  72. $inboundIsArray = false;
  73. if (is_array($inboundData))
  74. {
  75. $inboundIsArray = true;
  76. $inboundArray = $inboundData;
  77. } else
  78. $inboundArray = (array)$inboundData;
  79. /*
  80. * All changes will be placed here
  81. */
  82. $outboundArray = $inboundArray;
  83. foreach($inboundArray as $inboundKey=>$inboundValue)
  84. {
  85. if (is_resource($inboundValue))
  86. {
  87. /*
  88. * Prepared statement resource
  89. */
  90. if ($this->debug)
  91. ADOConnection::outp("{$this->databaseType} index $inboundKey value is resource, continue");
  92. continue;
  93. }
  94. if (strpos($inboundValue, SINGLEQUOTE) === false)
  95. {
  96. /*
  97. * Check we have something to manipulate
  98. */
  99. if ($this->debug)
  100. ADOConnection::outp("{$this->databaseType} index $inboundKey value $inboundValue has no single quotes, continue");
  101. continue;
  102. }
  103. /*
  104. * Check we haven't an odd number of single quotes (this can cause problems below
  105. * and should be considered one wrong SQL). Exit with debug info.
  106. */
  107. if ((substr_count($inboundValue, SINGLEQUOTE) & 1))
  108. {
  109. if ($this->debug)
  110. ADOConnection::outp("{$this->databaseType} internal transformation: not converted. Wrong number of quotes (odd)");
  111. break;
  112. }
  113. /*
  114. * Check we haven't any backslash + single quote combination. It should mean wrong
  115. * backslashes use (bad magic_quotes_sybase?). Exit with debug info.
  116. */
  117. $regexp = '/(\\\\' . SINGLEQUOTE . '[^' . SINGLEQUOTE . '])/';
  118. if (preg_match($regexp, $inboundValue))
  119. {
  120. if ($this->debug)
  121. ADOConnection::outp("{$this->databaseType} internal transformation: not converted. Found bad use of backslash + single quote");
  122. break;
  123. }
  124. /*
  125. * Remove pairs of single-quotes
  126. */
  127. $pairs = array();
  128. $regexp = '/(' . SINGLEQUOTE . SINGLEQUOTE . ')/';
  129. preg_match_all($regexp, $inboundValue, $list_of_pairs);
  130. if ($list_of_pairs)
  131. {
  132. foreach (array_unique($list_of_pairs[0]) as $key=>$value)
  133. $pairs['<@#@#@PAIR-'.$key.'@#@#@>'] = $value;
  134. if (!empty($pairs))
  135. $inboundValue = str_replace($pairs, array_keys($pairs), $inboundValue);
  136. }
  137. /*
  138. * Remove the rest of literals present in the query
  139. */
  140. $literals = array();
  141. $regexp = '/(N?' . SINGLEQUOTE . '.*?' . SINGLEQUOTE . ')/is';
  142. preg_match_all($regexp, $inboundValue, $list_of_literals);
  143. if ($list_of_literals)
  144. {
  145. foreach (array_unique($list_of_literals[0]) as $key=>$value)
  146. $literals['<#@#@#LITERAL-'.$key.'#@#@#>'] = $value;
  147. if (!empty($literals))
  148. $inboundValue = str_replace($literals, array_keys($literals), $inboundValue);
  149. }
  150. /*
  151. * Analyse literals to prepend the N char to them if their contents aren't numeric
  152. */
  153. if (!empty($literals))
  154. {
  155. foreach ($literals as $key=>$value) {
  156. if (!is_numeric(trim($value, SINGLEQUOTE)))
  157. /*
  158. * Non numeric string, prepend our dear N, whilst
  159. * Trimming potentially existing previous "N"
  160. */
  161. $literals[$key] = 'N' . trim($value, 'N');
  162. }
  163. }
  164. /*
  165. * Re-apply literals to the text
  166. */
  167. if (!empty($literals))
  168. $inboundValue = str_replace(array_keys($literals), $literals, $inboundValue);
  169. /*
  170. * Any pairs followed by N' must be switched to N' followed by those pairs
  171. * (or strings beginning with single quotes will fail)
  172. */
  173. $inboundValue = preg_replace("/((<@#@#@PAIR-(\d+)@#@#@>)+)N'/", "N'$1", $inboundValue);
  174. /*
  175. * Re-apply pairs of single-quotes to the text
  176. */
  177. if (!empty($pairs))
  178. $inboundValue = str_replace(array_keys($pairs), $pairs, $inboundValue);
  179. /*
  180. * Print transformation if debug = on
  181. */
  182. if (strcmp($inboundValue,$inboundArray[$inboundKey]) <> 0 && $this->debug)
  183. ADOConnection::outp("{$this->databaseType} internal transformation: {$inboundArray[$inboundKey]} to {$inboundValue}");
  184. if (strcmp($inboundValue,$inboundArray[$inboundKey]) <> 0)
  185. /*
  186. * Place the transformed value into the outbound array
  187. */
  188. $outboundArray[$inboundKey] = $inboundValue;
  189. }
  190. /*
  191. * Any transformations are in the $outboundArray
  192. */
  193. if ($inboundIsArray)
  194. return $outboundArray;
  195. /*
  196. * We passed a string in originally
  197. */
  198. return $outboundArray[0];
  199. }
  200. }
  201. class ADORecordset_mssql_n extends ADORecordset_mssql {
  202. var $databaseType = "mssql_n";
  203. }