PageRenderTime 64ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/core/misc.php

https://bitbucket.org/navigatecms/navigatecms
PHP | 894 lines | 617 code | 94 blank | 183 comment | 118 complexity | 04fff2c4c26fbfbb427a944c85ce47b4 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-2.1, BSD-3-Clause, AGPL-3.0, Apache-2.0
  1. <?php
  2. /**
  3. *
  4. * Navigate CMS miscellaneous functions
  5. *
  6. * @copyright All rights reserved to each function author.
  7. * @author Various (PHP Community)
  8. * @license GPLv2 License
  9. * @version 1.3 2016-01-05 19:48
  10. * @note if you are the creator of one of this functions and your name is not here send an email to info@navigatecms.com to be properly credited :)
  11. *
  12. */
  13. /* THANK YOU ALL */
  14. /**
  15. * Multi-byte Unserialize
  16. *
  17. * UTF-8 will screw up a serialized string, this function tries to fix the string before unserializing
  18. * (this happens when serialize puts the wrong length for a utf-8 string), for example here:
  19. * 'a:2:{i:0;s:5:"héllö";i:1;s:5:"wörld";}'
  20. *
  21. * @param string UTF-8 or ASCII string to be unserialized
  22. * @return string
  23. *
  24. */
  25. function mb_unserialize($var)
  26. {
  27. $out = $var;
  28. if(!is_object($var) && !is_array($var))
  29. {
  30. $out = unserialize($var);
  31. if(empty($out) && !is_array($out) && !is_object($out))
  32. {
  33. $out = preg_replace_callback(
  34. '!s:(\d+):"(.*?)";!s',
  35. function($matches)
  36. {
  37. return 's:'.strlen($matches[2]).':"'.$matches[2].'";';
  38. },
  39. $var
  40. );
  41. $out = unserialize($out);
  42. }
  43. }
  44. return $out;
  45. }
  46. /**
  47. * Cleans unwanted quotes from the superglobals GET, POST, COOKIE and REQUEST. If PHP has magic_quotes off, no cleaning is done.
  48. * @author Unknown
  49. */
  50. function disable_magic_quotes()
  51. {
  52. if(function_exists("get_magic_quotes_gpc"))
  53. {
  54. if(get_magic_quotes_gpc())
  55. {
  56. function stripslashes_gpc(&$value)
  57. {
  58. $value = stripslashes($value);
  59. }
  60. array_walk_recursive($_GET, 'stripslashes_gpc');
  61. array_walk_recursive($_POST, 'stripslashes_gpc');
  62. array_walk_recursive($_COOKIE, 'stripslashes_gpc');
  63. array_walk_recursive($_REQUEST, 'stripslashes_gpc');
  64. }
  65. }
  66. }
  67. /**
  68. * Return the real IP address of the current visitor
  69. *
  70. * @return bool|mixed The real IP of the visitor or FALSE when an exception is found
  71. */
  72. function core_ip()
  73. {
  74. $ip = false;
  75. if(!empty($_SERVER['HTTP_CLIENT_IP']))
  76. {
  77. $ip = $_SERVER['HTTP_CLIENT_IP'];
  78. }
  79. if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
  80. {
  81. $ips = explode(", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
  82. if($ip)
  83. {
  84. array_unshift($ips, $ip);
  85. $ip = false;
  86. }
  87. for($i = 0; $i < count($ips); $i++)
  88. {
  89. if(!preg_match("/^(10|172\.16|192\.168)\./i", $ips[$i]))
  90. {
  91. if(version_compare(phpversion(), "5.0.0", ">="))
  92. {
  93. if(ip2long($ips[$i]) != false)
  94. {
  95. $ip = $ips[$i];
  96. break;
  97. }
  98. }
  99. else
  100. {
  101. if(ip2long($ips[$i]) != - 1)
  102. {
  103. $ip = $ips[$i];
  104. break;
  105. }
  106. }
  107. }
  108. }
  109. }
  110. return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
  111. }
  112. /**
  113. * Retrieve all the files from a folder and subfolders (uses php glob internally)
  114. *
  115. * rglob("*", GLOB_MARK, NAVIGATE_PATH.'/themes');
  116. * @param string $pattern Glob pattern to filter results
  117. * @param int $flags Glob flags
  118. * @param string $path Absolute path to begin finding files
  119. * @return array Absolute paths to all files found matching the criteria
  120. */
  121. function rglob($pattern = '*', $flags = 0, $path = '')
  122. {
  123. if (!$path && ($dir = dirname($pattern)) != '.')
  124. {
  125. if ($dir == '\\' || $dir == '/') $dir = '';
  126. return rglob(basename($pattern), $flags, $dir . '/');
  127. }
  128. $paths = glob($path . '*', GLOB_ONLYDIR | GLOB_NOSORT);
  129. $files = glob($path . $pattern, $flags);
  130. foreach ($paths as $p) $files = array_merge($files, rglob($pattern, $flags, $p . '/'));
  131. return $files;
  132. }
  133. /**
  134. * extract_tags() [renamed to nvweb_tags_extract]
  135. * Extract specific HTML tags and their attributes from a string.
  136. *
  137. * You can either specify one tag, an array of tag names, or a regular expression that matches the tag name(s).
  138. * If multiple tags are specified you must also set the $selfclosing parameter and it must be the same for
  139. * all specified tags (so you can't extract both normal and self-closing tags in one go).
  140. *
  141. * The function returns a numerically indexed array of extracted tags. Each entry is an associative array
  142. * with these keys :
  143. * tag_name - the name of the extracted tag, e.g. "a" or "img".
  144. * offset - the numberic offset of the first character of the tag within the HTML source.
  145. * contents - the inner HTML of the tag. This is always empty for self-closing tags.
  146. * attributes - a name -> value array of the tag's attributes, or an empty array if the tag has none.
  147. * full_tag - the entire matched tag, e.g. '<a href="http://example.com">example.com</a>'. This key
  148. * will only be present if you set $return_the_entire_tag to true.
  149. *
  150. * @param string $html The HTML code to search for tags.
  151. * @param string|array $tag The tag(s) to extract.
  152. * @param bool $selfclosing Whether the tag is self-closing or not. Setting it to null will force the script to try and make an educated guess.
  153. * @param bool $return_the_entire_tag Return the entire matched tag in 'full_tag' key of the results array.
  154. * @param string $charset The character set of the HTML code. Defaults to UTF-8.
  155. *
  156. * @return array An array of extracted tags, or an empty array if no matching tags were found.
  157. */
  158. function nvweb_tags_extract( $html, $tag, $selfclosing = null, $return_the_entire_tag = false, $charset = 'UTF-8')
  159. {
  160. if ( is_array($tag) ){
  161. $tag = implode('|', $tag);
  162. }
  163. //If the user didn't specify if $tag is a self-closing tag we try to auto-detect it
  164. //by checking against a list of known self-closing tags.
  165. $selfclosing_tags = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta', 'col', 'param' );
  166. if ( is_null($selfclosing) ){
  167. $selfclosing = in_array( $tag, $selfclosing_tags );
  168. }
  169. //The regexp is different for normal and self-closing tags because I can't figure out
  170. //how to make a sufficiently robust unified one.
  171. if ( $selfclosing ){
  172. $tag_pattern =
  173. '@<(?P<tag>'.$tag.') # <tag
  174. (?P<attributes>\s[^>]+)? # attributes, if any
  175. \s*/?> # /> or just >, being lenient here
  176. @xsi';
  177. } else {
  178. $tag_pattern =
  179. '@<(?P<tag>'.$tag.') # <tag
  180. (?P<attributes>\s[^>]+)? # attributes, if any
  181. \s*> # >
  182. (?P<contents>.*?) # tag contents
  183. </(?P=tag)> # the closing </tag>
  184. @xsi';
  185. }
  186. $attribute_pattern =
  187. '@
  188. (?P<name>[a-zA-Z0-9.\-_]+) # attribute name
  189. \s*=\s*
  190. (
  191. (?P<quote>[\"\'])(?P<value_quoted>.*?)(?P=quote) # a quoted value
  192. | # or
  193. (?P<value_unquoted>[^\s"\']+?)(?:\s+|$) # an unquoted value (terminated by whitespace or EOF)
  194. )
  195. @xsi';
  196. //Find all tags
  197. if ( !preg_match_all($tag_pattern, $html, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE ) ){
  198. //Return an empty array if we didn't find anything
  199. return array();
  200. }
  201. $tags = array();
  202. foreach ($matches as $match)
  203. {
  204. //Parse tag attributes, if any
  205. $attributes = array();
  206. if ( !empty($match['attributes'][0]) ){
  207. if ( preg_match_all( $attribute_pattern, $match['attributes'][0], $attribute_data, PREG_SET_ORDER ) ){
  208. //Turn the attribute data into a name->value array
  209. foreach($attribute_data as $attr){
  210. if( !empty($attr['value_quoted']) ){
  211. $value = $attr['value_quoted'];
  212. } else if( !empty($attr['value_unquoted']) ){
  213. $value = $attr['value_unquoted'];
  214. } else {
  215. $value = '';
  216. }
  217. //Passing the value through html_entity_decode is handy when you want
  218. //to extract link URLs or something like that. You might want to remove
  219. //or modify this call if it doesn't fit your situation.
  220. $value = html_entity_decode( $value, ENT_QUOTES, $charset );
  221. $attributes[$attr['name']] = $value;
  222. }
  223. }
  224. }
  225. $tag = array(
  226. 'tag_name' => $match['tag'][0],
  227. 'offset' => $match[0][1],
  228. 'contents' => !empty($match['contents'])?$match['contents'][0]:'', //empty for self-closing tags
  229. 'attributes' => $attributes,
  230. );
  231. if ( $return_the_entire_tag ){
  232. $tag['full_tag'] = $match[0][0];
  233. }
  234. $tags[] = $tag;
  235. }
  236. return $tags;
  237. }
  238. /* strpos that takes an array of values to match against a string */
  239. function stripos_array($haystack, $needles=array(), $offset=0)
  240. {
  241. $chr = array();
  242. foreach($needles as $needle)
  243. {
  244. $res = stripos($haystack, $needle, $offset);
  245. if ($res !== false) $chr[$needle] = $res;
  246. }
  247. if(empty($chr)) return false;
  248. return min($chr);
  249. }
  250. /**
  251. * Sort the elements of an associative array by one of its field values
  252. *
  253. * The function allows passing more than one sorting criteria, for example:
  254. * $sorted = array_orderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
  255. *
  256. * @author: jimpoz@jimpoz.com
  257. *
  258. * @param array $data Array to be sorted
  259. * @param string $field Name of the field to get as base for sorting
  260. * @param integer $sort_type SORT_ASC or SORT_DESC (sort ascending or descending)
  261. * @return array
  262. */
  263. function array_orderby()
  264. {
  265. $args = func_get_args();
  266. $data = array_shift($args);
  267. foreach ($args as $n => $field)
  268. {
  269. if(is_string($field))
  270. {
  271. $tmp = array();
  272. foreach($data as $key => $row)
  273. {
  274. $tmp[$key] = mb_strtolower($row[$field]);
  275. }
  276. $args[$n] = $tmp;
  277. }
  278. }
  279. $args[] = &$data;
  280. call_user_func_array('array_multisort', $args);
  281. return array_pop($args);
  282. }
  283. if(!function_exists('gzdecode'))
  284. {
  285. /**
  286. * gzdecode is not present in PHP before version 6
  287. * @author: Aaron G. 07-Aug-2004 01:29
  288. * @source: http://www.php.net/manual/es/function.gzencode.php
  289. * @param string $data
  290. * @return bool|null|string
  291. */
  292. function gzdecode($data)
  293. {
  294. $len = strlen($data);
  295. if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
  296. return null; // Not GZIP format (See RFC 1952)
  297. }
  298. $method = ord(substr($data,2,1)); // Compression method
  299. $flags = ord(substr($data,3,1)); // Flags
  300. if ($flags & 31 != $flags) {
  301. // Reserved bits are set -- NOT ALLOWED by RFC 1952
  302. return null;
  303. }
  304. // NOTE: $mtime may be negative (PHP integer limitations)
  305. $mtime = unpack("V", substr($data,4,4));
  306. $mtime = $mtime[1];
  307. $xfl = substr($data,8,1);
  308. $os = substr($data,8,1);
  309. $headerlen = 10;
  310. $extralen = 0;
  311. $extra = "";
  312. if ($flags & 4) {
  313. // 2-byte length prefixed EXTRA data in header
  314. if ($len - $headerlen - 2 < 8) {
  315. return false; // Invalid format
  316. }
  317. $extralen = unpack("v",substr($data,8,2));
  318. $extralen = $extralen[1];
  319. if ($len - $headerlen - 2 - $extralen < 8) {
  320. return false; // Invalid format
  321. }
  322. $extra = substr($data,10,$extralen);
  323. $headerlen += 2 + $extralen;
  324. }
  325. $filenamelen = 0;
  326. $filename = "";
  327. if ($flags & 8) {
  328. // C-style string file NAME data in header
  329. if ($len - $headerlen - 1 < 8) {
  330. return false; // Invalid format
  331. }
  332. $filenamelen = strpos(substr($data,8+$extralen),chr(0));
  333. if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
  334. return false; // Invalid format
  335. }
  336. $filename = substr($data,$headerlen,$filenamelen);
  337. $headerlen += $filenamelen + 1;
  338. }
  339. $commentlen = 0;
  340. $comment = "";
  341. if ($flags & 16) {
  342. // C-style string COMMENT data in header
  343. if ($len - $headerlen - 1 < 8) {
  344. return false; // Invalid format
  345. }
  346. $commentlen = strpos(substr($data,8+$extralen+$filenamelen),chr(0));
  347. if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
  348. return false; // Invalid header format
  349. }
  350. $comment = substr($data,$headerlen,$commentlen);
  351. $headerlen += $commentlen + 1;
  352. }
  353. $headercrc = "";
  354. if ($flags & 1) {
  355. // 2-bytes (lowest order) of CRC32 on header present
  356. if ($len - $headerlen - 2 < 8) {
  357. return false; // Invalid format
  358. }
  359. $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
  360. $headercrc = unpack("v", substr($data,$headerlen,2));
  361. $headercrc = $headercrc[1];
  362. if ($headercrc != $calccrc) {
  363. return false; // Bad header CRC
  364. }
  365. $headerlen += 2;
  366. }
  367. // GZIP FOOTER - These be negative due to PHP's limitations
  368. $datacrc = unpack("V",substr($data,-8,4));
  369. $datacrc = $datacrc[1];
  370. $isize = unpack("V",substr($data,-4));
  371. $isize = $isize[1];
  372. // Perform the decompression:
  373. $bodylen = $len-$headerlen-8;
  374. if ($bodylen < 1) {
  375. // This should never happen - IMPLEMENTATION BUG!
  376. return null;
  377. }
  378. $body = substr($data,$headerlen,$bodylen);
  379. $data = "";
  380. if ($bodylen > 0) {
  381. switch ($method) {
  382. case 8:
  383. // Currently the only supported compression method:
  384. $data = gzinflate($body);
  385. break;
  386. default:
  387. // Unknown compression method
  388. return false;
  389. }
  390. } else {
  391. // I'm not sure if zero-byte body content is allowed.
  392. // Allow it for now... Do nothing...
  393. }
  394. // Verifiy decompressed size and CRC32:
  395. // NOTE: This may fail with large data sizes depending on how
  396. // PHP's integer limitations affect strlen() since $isize
  397. // may be negative for large sizes.
  398. if ($isize != strlen($data) || crc32($data) != $datacrc) {
  399. // Bad format! Length or CRC doesn't match!
  400. return false;
  401. }
  402. return $data;
  403. }
  404. }
  405. /**
  406. * Search the first row of an associative that match a key => value criteria
  407. *
  408. * @author: unkwown
  409. * #source: http://www.php.net/manual/en/function.array-search.php#106107
  410. *
  411. * @param array $parents array( 0 => array( 'a' => 3, 'key' => 'value', 'b' => 3), 1 => array( 'a' => 5, 'key' => 'foo') )
  412. * @param array $searched array('key' => 'value')
  413. * @return bool|int|string Index of the parent array (in the example, '0')
  414. */
  415. function array_multidimensional_search($parents, $searched)
  416. {
  417. if (empty($searched) || empty($parents))
  418. {
  419. return false;
  420. }
  421. foreach ($parents as $key => $value)
  422. {
  423. $exists = true;
  424. foreach ($searched as $skey => $svalue)
  425. {
  426. $exists = ($exists && IsSet($parents[$key][$skey]) && $parents[$key][$skey] == $svalue);
  427. }
  428. if($exists)
  429. {
  430. return $key;
  431. }
  432. }
  433. return false;
  434. }
  435. /**
  436. * Calculate the size of a folder and its files
  437. *
  438. * @author: Toni Widodo (toni.widodo@clearsyntax.com)
  439. *
  440. * @param string $dirname
  441. * @return int Size of the folder in bytes
  442. */
  443. function foldersize($dirname)
  444. {
  445. $folderSize = 0;
  446. // open the directory, if the script cannot open the directory then return folderSize = 0
  447. $dir_handle = opendir($dirname);
  448. if (!$dir_handle) return 0;
  449. // traversal for every entry in the directory
  450. while ($file = readdir($dir_handle))
  451. {
  452. // ignore '.' and '..' directory
  453. if ($file != "." && $file != "..")
  454. {
  455. // if entry is directory then go recursive !
  456. if (is_dir($dirname."/".$file))
  457. {
  458. $folderSize += foldersize($dirname.'/'.$file);
  459. }
  460. else // if file then accumulate the size
  461. {
  462. $folderSize += filesize($dirname."/".$file);
  463. }
  464. }
  465. }
  466. // chose the directory
  467. closedir($dir_handle);
  468. // return $dirname folder size
  469. return $folderSize ;
  470. }
  471. /**
  472. * Search for a text in an array, removing the rows which haven't got it
  473. *
  474. * @param array $array
  475. * @param string $text Fragment of text to look for (search is case insensitive)
  476. * @return array $array The filtered array
  477. */
  478. function array_filter_quicksearch($array, $text)
  479. {
  480. $out = array();
  481. $text = mb_strtolower($text);
  482. foreach($array as $key => $value)
  483. {
  484. $keep = false;
  485. if(is_array($value))
  486. $keep = array_filter_quicksearch($value, $text);
  487. else
  488. $keep = (mb_strpos(strtolower($value), $text) !== false);
  489. if($keep)
  490. $out[$key] = $value;
  491. }
  492. $out = array_filter($out);
  493. return $out;
  494. }
  495. /**
  496. * Convert a PHP Date format string to its jQuery UI Date picker compatible version
  497. *
  498. * @author roblynch
  499. * @website http://snipplr.com/view/41329/convert-php-date-style-dateformat-to-the-equivalent-jquery-ui-datepicker-string/
  500. * @param string $dateString
  501. * @return string String in jQuery UI date picker format
  502. */
  503. function php_date_to_jquery_ui_datepicker_format($dateString)
  504. {
  505. $pattern = array(
  506. //day
  507. 'd', //day of the month
  508. 'j', //3 letter name of the day
  509. 'l', //full name of the day
  510. 'z', //day of the year
  511. //month
  512. 'F', //Month name full
  513. 'M', //Month name short
  514. 'n', //numeric month no leading zeros
  515. 'm', //numeric month leading zeros
  516. //year
  517. 'Y', //full numeric year
  518. 'y' //numeric year: 2 digit
  519. );
  520. $replace = array(
  521. 'dd','d','DD','o',
  522. 'MM','M','m','mm',
  523. 'yy','y'
  524. );
  525. foreach($pattern as &$p)
  526. {
  527. $p = '/'.$p.'/';
  528. }
  529. return preg_replace($pattern,$replace,$dateString);
  530. }
  531. function hex2rgb($hexColor)
  532. {
  533. $shorthand = (strlen($hexColor) == 4);
  534. list($r, $g, $b) = $shorthand? sscanf($hexColor, "#%1s%1s%1s") : sscanf($hexColor, "#%2s%2s%2s");
  535. return array(
  536. "r" => hexdec($shorthand? "$r$r" : $r),
  537. "g" => hexdec($shorthand? "$g$g" : $g),
  538. "b" => hexdec($shorthand? "$b$b" : $b)
  539. );
  540. }
  541. /**
  542. * Determines if a command exists on the current environment
  543. *
  544. * source: http://stackoverflow.com/questions/12424787/how-to-check-if-a-shell-command-exists-from-php
  545. *
  546. * @param string $command The command to check
  547. * @return bool True if the command has been found ; otherwise, false.
  548. */
  549. function command_exists($command)
  550. {
  551. $whereIsCommand = (PHP_OS == 'WINNT') ? 'where' : 'which';
  552. $process = proc_open(
  553. "$whereIsCommand $command",
  554. array(
  555. 0 => array("pipe", "r"), //STDIN
  556. 1 => array("pipe", "w"), //STDOUT
  557. 2 => array("pipe", "w"), //STDERR
  558. ),
  559. $pipes
  560. );
  561. if ($process !== false) {
  562. $stdout = stream_get_contents($pipes[1]);
  563. $stderr = stream_get_contents($pipes[2]);
  564. fclose($pipes[1]);
  565. fclose($pipes[2]);
  566. proc_close($process);
  567. return $stdout != '';
  568. }
  569. return false;
  570. }
  571. /**
  572. * Creates a "slug" from a UTF-8 string
  573. *
  574. * source: http://stackoverflow.com/questions/7530238/convert-ascii-and-utf-8-to-non-special-characters-with-one-function
  575. *
  576. * @param string $input The string to convert
  577. * @return string The generated slug
  578. */
  579. function slug($input)
  580. {
  581. $string = html_entity_decode($input, ENT_COMPAT, "UTF-8");
  582. $oldLocale = setlocale(LC_CTYPE, '0');
  583. setlocale(LC_CTYPE, 'en_US.UTF-8');
  584. $string = iconv("UTF-8", "ASCII//TRANSLIT", $string);
  585. setlocale(LC_CTYPE, $oldLocale);
  586. return strtolower(preg_replace('/[^a-zA-Z0-9]+/', '_', $string));
  587. }
  588. function value_or_default($value, $default="")
  589. {
  590. if((is_null($value) || $value=="") && !is_numeric($value))
  591. return $default;
  592. else
  593. return $value;
  594. }
  595. /**
  596. * Returns a alphabetic string for an integer
  597. *
  598. * Example: 1 => a, 2 => b ... then aa, ab, ac... aaa, aab, aac...
  599. *
  600. * @param string $input The intenger to convert
  601. * @return string The generated alphabetic string
  602. */
  603. function number2alphabet($n)
  604. {
  605. for($r = ""; $n >= 0; $n = intval($n / 26) - 1)
  606. $r = chr($n%26 + 0x61) . $r; // upercase --> 0x41
  607. return $r;
  608. }
  609. /**
  610. * Find a tag by ID and append/replace content
  611. *
  612. * source: http://stackoverflow.com/a/17661043/1829145
  613. * Thanks to Rodolfo Buaiz (brasofilo)
  614. *
  615. * @param string $oDoc source html (passed by reference!)
  616. * @param string $s html code to insert
  617. * @param string $sId id of the tag to find
  618. * @param string $sHtml
  619. * @param boolean $bAppend append new code?
  620. * @param boolean $bInsert replace existing contents by the new source code?
  621. * @param boolean $bAddToOuter
  622. * @return boolean
  623. */
  624. function brasofilo_suSetHtmlElementById( &$oDoc, &$s, $sId, $sHtml, $bAppend = false, $bInsert = false, $bAddToOuter = false )
  625. {
  626. if( brasofilo_suIsValidString( $s ) && brasofilo_suIsValidString( $sId ) )
  627. {
  628. $bCreate = true;
  629. if( is_object( $oDoc ))
  630. {
  631. if( !( $oDoc instanceof DOMDocument ))
  632. {
  633. return false;
  634. }
  635. $bCreate = false;
  636. }
  637. if( $bCreate )
  638. {
  639. $oDoc = new DOMDocument();
  640. }
  641. libxml_use_internal_errors(true);
  642. $oDoc->loadHTML($s);
  643. libxml_use_internal_errors(false);
  644. $oNode = $oDoc->getElementById( $sId );
  645. if( is_object( $oNode ))
  646. {
  647. $bReplaceOuter = ( !$bAppend && !$bInsert );
  648. $sId = uniqid('NVCMS_SHEBI-');
  649. $aId = array( "<!-- $sId -->", "<!--$sId-->" );
  650. if( $bReplaceOuter )
  651. {
  652. if( brasofilo_suIsValidString( $sHtml ) )
  653. {
  654. $oNode->parentNode->replaceChild( $oDoc->createComment( $sId ), $oNode );
  655. $s = $oDoc->saveHtml();
  656. $s = str_replace( $aId, $sHtml, $oDoc->saveHtml());
  657. }
  658. else
  659. {
  660. $oNode->parentNode->removeChild( $oNode );
  661. $s = $oDoc->saveHtml();
  662. }
  663. return true;
  664. }
  665. $bReplaceInner = ( $bAppend && $bInsert );
  666. $sThis = null;
  667. if( !$bReplaceInner )
  668. {
  669. $sThis = $oDoc->saveHTML( $oNode );
  670. $sThis = ($bInsert? $sHtml : '').($bAddToOuter? $sThis : (substr($sThis,strpos($sThis,'>')+1,-(strlen($oNode->nodeName)+3)))).($bAppend? $sHtml : '');
  671. }
  672. if( !$bReplaceInner && $bAddToOuter )
  673. {
  674. $oNode->parentNode->replaceChild( $oDoc->createComment( $sId ), $oNode );
  675. $sId = &$aId;
  676. }
  677. else
  678. {
  679. $oNode->nodeValue = $sId;
  680. }
  681. $s = str_replace( $sId, $bReplaceInner?$sHtml:$sThis, $oDoc->saveHtml());
  682. return true;
  683. }
  684. }
  685. return false;
  686. }
  687. function brasofilo_suIsValidString( &$s, &$iLen = null, $minLen = null, $maxLen = null )
  688. {
  689. if( !is_string( $s ) || !isset( $s{0} ))
  690. {
  691. return false;
  692. }
  693. if( $iLen !== null )
  694. {
  695. $iLen = strlen( $s );
  696. }
  697. return (
  698. ( $minLen===null? true : ( $minLen > 0 && isset( $s{$minLen-1} ) ) ) &&
  699. $maxLen===null? true : ( $maxLen >= $minLen && !isset( $s{$maxLen} ) )
  700. );
  701. }
  702. function brasofilo_suAppendHtmlById( &$s, $sId, $sHtml, &$oDoc = null )
  703. {
  704. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, true, false );
  705. }
  706. function brasofilo_suInsertHtmlById( &$s, $sId, $sHtml, &$oDoc = null )
  707. {
  708. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, false, true );
  709. }
  710. function brasofilo_suAddHtmlBeforeById( &$s, $sId, $sHtml, &$oDoc = null )
  711. {
  712. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, false, true, true );
  713. }
  714. function brasofilo_suAddHtmlAfterById( &$s, $sId, $sHtml, &$oDoc = null )
  715. {
  716. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, true, false, true );
  717. }
  718. function brasofilo_suSetHtmlById( &$s, $sId, $sHtml, &$oDoc = null )
  719. {
  720. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, true, true );
  721. }
  722. function brasofilo_suReplaceHtmlElementById( &$s, $sId, $sHtml, &$oDoc = null )
  723. {
  724. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, $sHtml, false, false );
  725. }
  726. function brasofilo_suRemoveHtmlElementById( &$s, $sId, &$oDoc = null )
  727. {
  728. return brasofilo_suSetHtmlElementById( $oDoc, $s, $sId, null, false, false );
  729. }
  730. function stylesheet_parse($css)
  731. {
  732. preg_match_all( '/(?ims)([a-z0-9\s\.\:#_\-@,]+)\{([^\}]*)\}/', $css, $arr);
  733. $result = array();
  734. foreach ($arr[0] as $i => $x){
  735. $selector = trim($arr[1][$i]);
  736. $rules = explode(';', trim($arr[2][$i]));
  737. $rules_arr = array();
  738. foreach ($rules as $strRule){
  739. if (!empty($strRule)){
  740. $rule = explode(":", $strRule);
  741. $rules_arr[trim($rule[0])] = trim($rule[1]);
  742. }
  743. }
  744. $selectors = explode(',', trim($selector));
  745. foreach ($selectors as $strSel){
  746. $result[$strSel] = $rules_arr;
  747. }
  748. }
  749. return $result;
  750. }
  751. // Generates a strong password of N length containing at least one lower case letter,
  752. // one uppercase letter, one digit, and one special character. The remaining characters
  753. // in the password are chosen at random from those four sets.
  754. //
  755. // The available characters in each set are user friendly - there are no ambiguous
  756. // characters such as i, l, 1, o, 0, etc. This, coupled with the $add_dashes option,
  757. // makes it much easier for users to manually type or speak their passwords.
  758. //
  759. // Note: the $add_dashes option will increase the length of the password by
  760. // floor(sqrt(N)) characters.
  761. // created by: tylerhall https://gist.github.com/tylerhall/521810
  762. function generate_password($length = 8, $add_dashes = false, $available_sets = 'luds')
  763. {
  764. $sets = array();
  765. if(strpos($available_sets, 'l') !== false)
  766. $sets[] = 'abcdefghjkmnpqrstuvwxyz';
  767. if(strpos($available_sets, 'u') !== false)
  768. $sets[] = 'ABCDEFGHJKMNPQRSTUVWXYZ';
  769. if(strpos($available_sets, 'd') !== false)
  770. $sets[] = '23456789';
  771. if(strpos($available_sets, 's') !== false)
  772. $sets[] = '!@#$%&*?';
  773. $all = '';
  774. $password = '';
  775. foreach($sets as $set)
  776. {
  777. $password .= $set[array_rand(str_split($set))];
  778. $all .= $set;
  779. }
  780. $all = str_split($all);
  781. for($i = 0; $i < $length - count($sets); $i++)
  782. $password .= $all[array_rand($all)];
  783. $password = str_shuffle($password);
  784. if(!$add_dashes)
  785. return $password;
  786. $dash_len = floor(sqrt($length));
  787. $dash_str = '';
  788. while(strlen($password) > $dash_len)
  789. {
  790. $dash_str .= substr($password, 0, $dash_len) . '-';
  791. $password = substr($password, $dash_len);
  792. }
  793. $dash_str .= $password;
  794. return $dash_str;
  795. }
  796. ?>