MyHelpers.class.inc.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. <?php
  2. /**
  3. * MyHelpers
  4. * various dev/debug helpers, to cleanup or at least re-organize
  5. *
  6. * @package iTopORM
  7. * @author Romain Quetiez <romainquetiez@yahoo.fr>
  8. * @author Denis Flaven <denisflave@free.fr>
  9. * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
  10. * @link www.itop.com
  11. * @since 1.0
  12. * @version 1.1.1.1 $
  13. */
  14. class MyHelpers
  15. {
  16. public static function CheckValueInArray($sDescription, $value, $aData)
  17. {
  18. if (!in_array($value, $aData))
  19. {
  20. self::HandleWrongValue($sDescription, $value, $aData);
  21. }
  22. }
  23. public static function CheckKeyInArray($sDescription, $key, $aData)
  24. {
  25. if (!array_key_exists($key, $aData))
  26. {
  27. self::HandleWrongValue($sDescription, $key, array_keys($aData));
  28. }
  29. }
  30. public static function HandleWrongValue($sDescription, $value, $aData)
  31. {
  32. if (count($aData) == 0)
  33. {
  34. $sArrayDesc = "{}";
  35. }
  36. else
  37. {
  38. $sArrayDesc = "{".implode(", ", $aData)."}";
  39. }
  40. // exit!
  41. throw new CoreException("Wrong value for $sDescription, found '$value' while expecting a value in $sArrayDesc");
  42. }
  43. // getmicrotime()
  44. // format sss.mmmuuupppnnn
  45. public static function getmicrotime()
  46. {
  47. list($usec, $sec) = explode(" ",microtime());
  48. return ((float)$usec + (float)$sec);
  49. }
  50. /*
  51. * MakeSQLComment
  52. * converts hash into text comment which we can use in a (mySQL) query
  53. */
  54. public static function MakeSQLComment ($aHash)
  55. {
  56. if (empty($aHash)) return "";
  57. $sComment = "";
  58. {
  59. foreach($aHash as $sKey=>$sValue)
  60. {
  61. $sComment .= "\n-- ". $sKey ."=>" . $sValue;
  62. }
  63. }
  64. return $sComment;
  65. }
  66. public static function var_dump_html($aWords, $bFullDisplay = false)
  67. {
  68. echo "<pre>\n";
  69. if ($bFullDisplay)
  70. {
  71. print_r($aWords); // full dump!
  72. }
  73. else
  74. {
  75. var_dump($aWords); // truncate things when they are too big
  76. }
  77. echo "\n</pre>\n";
  78. }
  79. public static function arg_dump_html()
  80. {
  81. echo "<pre>\n";
  82. echo "GET:\n";
  83. var_dump($_GET);
  84. echo "POST:\n";
  85. var_dump($_POST);
  86. echo "\n</pre>\n";
  87. }
  88. public static function var_dump_string($var)
  89. {
  90. ob_start();
  91. print_r($var);
  92. $sRet = ob_get_clean();
  93. return $sRet;
  94. }
  95. protected static function first_diff_line($s1, $s2)
  96. {
  97. $aLines1 = explode("\n", $s1);
  98. $aLines2 = explode("\n", $s2);
  99. for ($i = 0 ; $i < min(count($aLines1), count($aLines2)) ; $i++)
  100. {
  101. if ($aLines1[$i] != $aLines2[$i]) return $i;
  102. }
  103. return false;
  104. }
  105. protected static function highlight_line($sMultiline, $iLine, $sHighlightStart = '<b>', $sHightlightEnd = '</b>')
  106. {
  107. $aLines = explode("\n", $sMultiline);
  108. $aLines[$iLine] = $sHighlightStart.$aLines[$iLine].$sHightlightEnd;
  109. return implode("\n", $aLines);
  110. }
  111. protected static function first_diff($s1, $s2)
  112. {
  113. // do not work fine with multiline strings
  114. $iLen1 = strlen($s1);
  115. $iLen2 = strlen($s2);
  116. for ($i = 0 ; $i < min($iLen1, $iLen2) ; $i++)
  117. {
  118. if ($s1[$i] !== $s2[$i]) return $i;
  119. }
  120. return false;
  121. }
  122. protected static function last_diff($s1, $s2)
  123. {
  124. // do not work fine with multiline strings
  125. $iLen1 = strlen($s1);
  126. $iLen2 = strlen($s2);
  127. for ($i = 0 ; $i < min(strlen($s1), strlen($s2)) ; $i++)
  128. {
  129. if ($s1[$iLen1 - $i - 1] !== $s2[$iLen2 - $i - 1]) return array($iLen1 - $i, $iLen2 - $i);
  130. }
  131. return false;
  132. }
  133. protected static function text_cmp_html($sText1, $sText2, $sHighlight)
  134. {
  135. $iDiffPos = self::first_diff_line($sText1, $sText2);
  136. $sDisp1 = self::highlight_line($sText1, $iDiffPos, '<div style="'.$sHighlight.'">', '</div>');
  137. $sDisp2 = self::highlight_line($sText2, $iDiffPos, '<div style="'.$sHighlight.'">', '</div>');
  138. echo "<table style=\"valign=top;\">\n";
  139. echo "<tr>\n";
  140. echo "<td><pre>$sDisp1</pre></td>\n";
  141. echo "<td><pre>$sDisp2</pre></td>\n";
  142. echo "</tr>\n";
  143. echo "</table>\n";
  144. }
  145. protected static function string_cmp_html($s1, $s2, $sHighlight)
  146. {
  147. $iDiffPos = self::first_diff($s1, $s2);
  148. if ($iDiffPos === false)
  149. {
  150. echo "strings are identical";
  151. return;
  152. }
  153. $sStart = substr($s1, 0, $iDiffPos);
  154. $aLastDiff = self::last_diff($s1, $s2);
  155. $sEnd = substr($s1, $aLastDiff[0]);
  156. $sMiddle1 = substr($s1, $iDiffPos, $aLastDiff[0] - $iDiffPos);
  157. $sMiddle2 = substr($s2, $iDiffPos, $aLastDiff[1] - $iDiffPos);
  158. echo "<p>$sStart<span style=\"$sHighlight\">$sMiddle1</span>$sEnd</p>\n";
  159. echo "<p>$sStart<span style=\"$sHighlight\">$sMiddle2</span>$sEnd</p>\n";
  160. }
  161. protected static function object_cmp_html($oObj1, $oObj2, $sHighlight)
  162. {
  163. $sObj1 = self::var_dump_string($oObj1);
  164. $sObj2 = self::var_dump_string($oObj2);
  165. return self::text_cmp_html($sObj1, $sObj2, $sHighlight);
  166. }
  167. public static function var_cmp_html($var1, $var2, $sHighlight = 'color:red; font-weight:bold;')
  168. {
  169. if (is_object($var1))
  170. {
  171. return self::object_cmp_html($var1, $var2, $sHighlight);
  172. }
  173. else if (count(explode("\n", $var1)) > 1)
  174. {
  175. // multiline string
  176. return self::text_cmp_html($var1, $var2, $sHighlight);
  177. }
  178. else
  179. {
  180. return self::string_cmp_html($var1, $var2, $sHighlight);
  181. }
  182. }
  183. public static function get_callstack_html($iLevelsToIgnore = 0, $aCallStack = null)
  184. {
  185. if ($aCallStack == null) $aCallStack = debug_backtrace();
  186. $aCallStack = array_slice($aCallStack, $iLevelsToIgnore);
  187. $aDigestCallStack = array();
  188. $bFirstLine = true;
  189. foreach ($aCallStack as $aCallInfo)
  190. {
  191. $sLine = empty($aCallInfo['line']) ? "" : $aCallInfo['line'];
  192. $sFile = empty($aCallInfo['file']) ? "" : $aCallInfo['file'];
  193. $sClass = empty($aCallInfo['class']) ? "" : $aCallInfo['class'];
  194. $sType = empty($aCallInfo['type']) ? "" : $aCallInfo['type'];
  195. $sFunction = empty($aCallInfo['function']) ? "" : $aCallInfo['function'];
  196. if ($bFirstLine)
  197. {
  198. $bFirstLine = false;
  199. // For this line do not display the "function name" because
  200. // that will be the name of our error handler for sure !
  201. $sFunctionInfo = "N/A";
  202. }
  203. else
  204. {
  205. $args = '';
  206. if (empty($aCallInfo['args'])) $aCallInfo['args'] = array();
  207. foreach ($aCallInfo['args'] as $a)
  208. {
  209. if (!empty($args))
  210. {
  211. $args .= ', ';
  212. }
  213. switch (gettype($a))
  214. {
  215. case 'integer':
  216. case 'double':
  217. $args .= $a;
  218. break;
  219. case 'string':
  220. $a = Str::pure2html(self::beautifulstr($a, 1024, true, true));
  221. $args .= "\"$a\"";
  222. break;
  223. case 'array':
  224. $args .= 'Array('.count($a).')';
  225. break;
  226. case 'object':
  227. $args .= 'Object('.get_class($a).')';
  228. break;
  229. case 'resource':
  230. $args .= 'Resource('.strstr($a, '#').')';
  231. break;
  232. case 'boolean':
  233. $args .= $a ? 'True' : 'False';
  234. break;
  235. case 'NULL':
  236. $args .= 'Null';
  237. break;
  238. default:
  239. $args .= 'Unknown';
  240. }
  241. }
  242. $sFunctionInfo = "$sClass $sType $sFunction($args)";
  243. }
  244. $aDigestCallStack[] = array('File'=>$sFile, 'Line'=>$sLine, 'Function'=>$sFunctionInfo);
  245. }
  246. return self::make_table_from_assoc_array($aDigestCallStack);
  247. }
  248. public static function dump_callstack($iLevelsToIgnore = 0, $aCallStack = null)
  249. {
  250. return self::get_callstack_html($iLevelsToIgnore, $aCallStack);
  251. }
  252. ///////////////////////////////////////////////////////////////////////////////
  253. // Source: New
  254. // Last modif: 2004/12/20 RQU
  255. ///////////////////////////////////////////////////////////////////////////////
  256. public static function make_table_from_assoc_array(&$aData)
  257. {
  258. if (!is_array($aData)) throw new CoreException("make_table_from_assoc_array: Error - the passed argument is not an array");
  259. $aFirstRow = reset($aData);
  260. if (count($aData) == 0) return '';
  261. if (!is_array($aFirstRow)) throw new CoreException("make_table_from_assoc_array: Error - the passed argument is not a bi-dimensional array");
  262. $sOutput = "";
  263. $sOutput .= "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"1\" CELLPADDING=\"1\">\n";
  264. // Table header
  265. //
  266. $sOutput .= " <TR CLASS=celltitle>\n";
  267. foreach ($aFirstRow as $fieldname=>$trash) {
  268. $sOutput .= " <TD><B>".$fieldname."</B></TD>\n";
  269. }
  270. $sOutput .= " </TR>\n";
  271. // Table contents
  272. //
  273. $iCount = 0;
  274. foreach ($aData as $aRow) {
  275. $sStyle = ($iCount++ % 2 ? "STYLE=\"background-color : #eeeeee\"" : "");
  276. $sOutput .= " <TR $sStyle CLASS=cell>\n";
  277. foreach ($aRow as $data) {
  278. if (strlen($data) == 0) {
  279. $data = "&nbsp;";
  280. }
  281. $sOutput .= " <TD>".$data."</TD>\n";
  282. }
  283. $sOutput .= " </TR>\n";
  284. }
  285. $sOutput .= "</TABLE>\n";
  286. return $sOutput;
  287. }
  288. public static function debug_breakpoint($arg)
  289. {
  290. echo "<H1> Debug breakpoint </H1>\n";
  291. MyHelpers::var_dump_html($arg);
  292. MyHelpers::dump_callstack();
  293. exit;
  294. }
  295. public static function debug_breakpoint_notempty($arg)
  296. {
  297. if (empty($arg)) return;
  298. echo "<H1> Debug breakpoint (triggered on non-empty value) </H1>\n";
  299. MyHelpers::var_dump_html($arg);
  300. MyHelpers::dump_callstack();
  301. exit;
  302. }
  303. /**
  304. * utf8... converts non ASCII chars into '?'
  305. * Decided after some complex investigations, to have the tools work fine (Oracle+Perl vs mySQL+PHP...)
  306. */
  307. public static function utf8($strText)
  308. {
  309. return iconv("WINDOWS-1252", "ASCII//TRANSLIT", $strText);
  310. }
  311. /**
  312. * xmlentities()
  313. * ... same as htmlentities, but designed for xml !
  314. */
  315. public static function xmlentities($string)
  316. {
  317. return str_replace( array( '&', '"', "'", '<', '>' ), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;' ), $string );
  318. }
  319. /**
  320. * xmlencode()
  321. * Encodes a string so that for sure it can be output as an xml data string
  322. */
  323. public static function xmlencode($string)
  324. {
  325. return xmlentities(iconv("UTF-8", "UTF-8//IGNORE",$string));
  326. }
  327. ///////////////////////////////////////////////////////////////////////////////
  328. // Source: New - format strings for output
  329. // Last modif: 2005/01/18 RQU
  330. ///////////////////////////////////////////////////////////////////////////////
  331. public static function beautifulstr($sLongString, $iMaxLen, $bShowLen=false, $bShowTooltip=true)
  332. {
  333. if (!is_string($sLongString)) throw new CoreException("beautifulstr: expect a string as 1st argument");
  334. // Nothing to do if the string is short
  335. if (strlen($sLongString) <= $iMaxLen) return $sLongString;
  336. // Truncate the string
  337. $sSuffix = "...";
  338. if ($bShowLen) {
  339. $sSuffix .= "(".strlen($sLongString)." chars)...";
  340. }
  341. $sOutput = substr($sLongString, 0, $iMaxLen - strlen($sSuffix)).$sSuffix;
  342. $sOutput = htmlspecialchars($sOutput);
  343. // Add tooltip if required
  344. //if ($bShowTooltip) {
  345. // $oTooltip = new gui_tooltip($sLongString);
  346. // $sOutput = "<SPAN ".$oTooltip->get_mouseOver_code().">".$sOutput."</SPAN>";
  347. //}
  348. return $sOutput;
  349. }
  350. }
  351. /**
  352. Utility class: static methods for cleaning & escaping untrusted (i.e.
  353. user-supplied) strings.
  354. Any string can (usually) be thought of as being in one of these 'modes':
  355. pure = what the user actually typed / what you want to see on the page /
  356. what is actually stored in the DB
  357. gpc = incoming GET, POST or COOKIE data
  358. sql = escaped for passing safely to RDBMS via SQL (also, data from DB
  359. queries and file reads if you have magic_quotes_runtime on--which
  360. is rare)
  361. html = safe for html display (htmlentities applied)
  362. Always knowing what mode your string is in--using these methods to
  363. convert between modes--will prevent SQL injection and cross-site scripting.
  364. This class refers to its own namespace (so it can work in PHP 4--there is no
  365. self keyword until PHP 5). Do not change the name of the class w/o changing
  366. all the internal references.
  367. Example usage: a POST value that you want to query with:
  368. $username = Str::gpc2sql($_POST['username']);
  369. */
  370. //This sets SQL escaping to use slashes; for Sybase(/MSSQL)-style escaping
  371. // ( ' --> '' ), set to true.
  372. define('STR_SYBASE', false);
  373. class Str
  374. {
  375. public static function gpc2sql($gpc, $maxLength = false)
  376. {
  377. return self::pure2sql(self::gpc2pure($gpc), $maxLength);
  378. }
  379. public static function gpc2html($gpc, $maxLength = false)
  380. {
  381. return self::pure2html(self::gpc2pure($gpc), $maxLength);
  382. }
  383. public static function gpc2pure($gpc)
  384. {
  385. if (ini_get('magic_quotes_sybase')) $pure = str_replace("''", "'", $gpc);
  386. else $pure = get_magic_quotes_gpc() ? stripslashes($gpc) : $gpc;
  387. return $pure;
  388. }
  389. public static function html2pure($html)
  390. {
  391. return html_entity_decode($html);
  392. }
  393. public static function html2sql($html, $maxLength = false)
  394. {
  395. return self::pure2sql(self::html2pure($html), $maxLength);
  396. }
  397. public static function pure2html($pure, $maxLength = false)
  398. {
  399. // Check for HTML entities, but be careful the DB is in UTF-8
  400. return $maxLength
  401. ? htmlentities(substr($pure, 0, $maxLength), ENT_COMPAT, 'UTF-8')
  402. : htmlentities($pure, ENT_COMPAT, 'UTF-8');
  403. }
  404. public static function pure2sql($pure, $maxLength = false)
  405. {
  406. if ($maxLength) $pure = substr($pure, 0, $maxLength);
  407. return (STR_SYBASE)
  408. ? str_replace("'", "''", $pure)
  409. : addslashes($pure);
  410. }
  411. public static function sql2html($sql, $maxLength = false)
  412. {
  413. $pure = self::sql2pure($sql);
  414. if ($maxLength) $pure = substr($pure, 0, $maxLength);
  415. return self::pure2html($pure);
  416. }
  417. public static function sql2pure($sql)
  418. {
  419. return (STR_SYBASE)
  420. ? str_replace("''", "'", $sql)
  421. : stripslashes($sql);
  422. }
  423. public static function xml2pure($xml)
  424. {
  425. // #@# - not implemented
  426. return $xml;
  427. }
  428. public static function pure2xml($pure)
  429. {
  430. return self::xmlencode($pure);
  431. }
  432. protected static function xmlentities($string)
  433. {
  434. return str_replace( array( '&', '"', "'", '<', '>' ), array ( '&amp;' , '&quot;', '&apos;' , '&lt;' , '&gt;' ), $string );
  435. }
  436. /**
  437. * xmlencode()
  438. * Encodes a string so that for sure it can be output as an xml data string
  439. */
  440. protected static function xmlencode($string)
  441. {
  442. return self::xmlentities(iconv("ISO-8859-1", "UTF-8//IGNORE",$string));
  443. }
  444. public static function islowcase($sString)
  445. {
  446. return (strtolower($sString) == $sString);
  447. }
  448. }
  449. ?>