PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/fruml/library/lib.library.php

https://bitbucket.org/fruml/fruml
PHP | 1044 lines | 616 code | 77 blank | 351 comment | 103 complexity | 78fd898e703491ba5b12906abf96c85b MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-2.0, BSD-2-Clause
  1. <?php
  2. /**
  3. * Library: general helper tools
  4. *
  5. * Library gives access to a number of often used tools.
  6. * A number of Library's methods can be called globally, e.g. Library::dbg()
  7. * can also be called as dbg()
  8. *
  9. * @author Alex Butter <alex.butter@gmail.com>
  10. * @license Fruml License 1.0
  11. *
  12. * @package Library
  13. * @version
  14. */
  15. /**
  16. * Library
  17. *
  18. * The main Libary class
  19. *
  20. * @package Library
  21. */
  22. class Library {
  23. /**
  24. * pretty print the contents of passed variables
  25. *
  26. * @param mixed $data,...
  27. * @return void
  28. * @access public
  29. * @static
  30. * @return void
  31. */
  32. public static function dbg() {
  33. if(Library::ajax() || IS_FLASH) {
  34. $output = array();
  35. $output['success'] = false;
  36. $output['debug'] = true;
  37. $args = func_get_args();
  38. $output['data_display'] = '';
  39. foreach($args as $arg) {
  40. $output['data'][] = $arg;
  41. $output['data_display'] .= '<pre>'.Library::encode(print_r($arg, 1)).'</pre>';
  42. }
  43. echo Library::json($output);
  44. die();
  45. }
  46. if(defined('IS_CLI') && IS_CLI) {
  47. foreach(func_get_args() as $arg) {
  48. var_dump($arg);
  49. }
  50. return;
  51. }
  52. $trace = $orig_trace = debug_backtrace();
  53. $caller = array_shift($trace);
  54. while(empty($caller['file']) || realpath(Library::formatPath($caller['file']))==realpath(Library::formatPath(__FILE__))) {
  55. $caller = array_shift($trace);
  56. }
  57. $function = $caller['function'];
  58. $class = isset($caller['class']) ? $caller['class'].'::' : '' ;
  59. $header = $class.$function.'()';
  60. $header .= !empty($caller['file']) ? ' @ '.self::formatPath($caller['file']) : '' ;
  61. $header .= !empty($caller['line']) ? ', line '.$caller['line'] : '' ;
  62. echo chr(10).'<div style="border: 1px solid #eee; margin: 5px;">'.chr(10);
  63. echo chr(9).'<div style="background-color: #eee; color: #333; font-family: Arial, Helv, Sans; font-size: 12px; padding: 3px;">';
  64. echo '&nbsp;'.$header.'</div>'.chr(10);
  65. if(func_num_args()) {
  66. foreach(func_get_args() as $arg) {
  67. echo chr(9).'<div style="background: white; color: #333; font-family: Arial, Helv, Sans; font-size: 12px; padding: 3px;">'.chr(10);
  68. $dump = Library::prettyPrint($arg);
  69. echo $dump;
  70. }
  71. echo chr(9).'</div>'.chr(10);
  72. } else {
  73. echo chr(9).'<div style="color: #333; font-family: Arial, Helv, Sans; font-size: 12px; padding: 3px;">'.chr(10);
  74. echo 'No parameters passed, nothing to '.$function.'().'.chr(10);
  75. echo chr(9).'</div>'.chr(10);
  76. }
  77. echo '</div>'.chr(10).chr(10);
  78. }
  79. /**
  80. * Output the contents of the passed variables, and stops script executions
  81. *
  82. * @return void
  83. * @access public
  84. * @static
  85. */
  86. public static function dbgd() {
  87. $args = func_get_args();
  88. call_user_func_array(array('Library', 'dbg'), $args);
  89. die();
  90. }
  91. /**
  92. * Returns pretty-printable version of $data.
  93. *
  94. * @return string $data
  95. * @access public
  96. * @static
  97. */
  98. static public function prettyPrint($data) {
  99. // set html_errors to 1 just in case xdebug's installed. It'll give pretty colours :)
  100. $html_errors = ini_get('html_errors');
  101. ini_set('html_errors', 1);
  102. ob_start();
  103. echo '<pre>';
  104. var_dump($data);
  105. echo '</pre>';
  106. ini_set('html_errors', $html_errors);
  107. return ob_get_clean();
  108. }
  109. /**
  110. * Cleans a (file) path and replaces backslashes with forward slashes
  111. *
  112. * @param string $path
  113. * @return string
  114. * @access public
  115. * @static
  116. */
  117. public static function formatPath($path) {
  118. $path = str_replace('\\', '/', $path);
  119. $path = str_replace('///', '/', $path);
  120. $path = str_replace('//', '/', $path);
  121. $path = str_replace('../', '/', $path); // stop directory traversal?
  122. return $path;
  123. }
  124. /**
  125. * Instantiates and returns a dwoo
  126. *
  127. * @return object Dwoo
  128. * @access public
  129. * @static
  130. */
  131. public static function getDwoo() {
  132. self::loadDwoo();
  133. return new Dwoo(CACHE_PATH.'template/', CACHE_PATH.'data/');
  134. }
  135. /**
  136. * Loads the Dwoo autoloader
  137. *
  138. * @return void
  139. * @access public
  140. * @static
  141. */
  142. public static function loadDwoo() {
  143. if(!class_exists('Dwoo', false)) {
  144. require_once VENDOR_PATH.'dwoo/dwooAutoload.php';
  145. }
  146. }
  147. /**
  148. * Loads the a BB Code parser
  149. *
  150. * @return void
  151. * @access public
  152. * @static
  153. */
  154. public static function getBBCodeParser() {
  155. if(!class_exists('ubbParser', false)) {
  156. require_once VENDOR_PATH.'ubbparser/class.ubbparser.php';
  157. }
  158. return new ubbParser();
  159. }
  160. /**
  161. * Parses a string for BB Code
  162. * @return string The parsed string
  163. * @access public
  164. * @static
  165. */
  166. private static $bbcodeParser = false;
  167. public static function parseBBCode($string) {
  168. Library::disableErrorHandling();
  169. if(!self::$bbcodeParser) self::$bbcodeParser = self::getBBCodeParser();
  170. $string = self::$bbcodeParser->parse($string);
  171. Library::enableErrorHandling();
  172. return $string;
  173. }
  174. /**
  175. * Checks if an incoming request is an AJAX request.
  176. *
  177. * @return boolean
  178. * @access public
  179. * @static
  180. */
  181. public static function ajax() {
  182. $ajax = false;
  183. $ajax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']=='XMLHttpRequest' ? true : $ajax ;
  184. $ajax = IS_FLASH ? true : $ajax ;
  185. $ajax = defined('FORCE_HTML') && FORCE_HTML==true ? false : $ajax;
  186. return $ajax;
  187. }
  188. /**
  189. * Force HTML output, even if it's an AJAX request. Useful for getting properly formatted
  190. * dbg and error messages when using something like jQuery's .load() function.
  191. *
  192. * @return void
  193. * @access public
  194. * @static
  195. */
  196. public static function forceHTML() {
  197. if(!defined('FORCE_HTML')) {
  198. define('FORCE_HTML', true);
  199. }
  200. }
  201. /**
  202. * Does a redirect.
  203. *
  204. * @return void
  205. * @access public
  206. * @static
  207. */
  208. public static function redirect($target) {
  209. header('Location: '.$target);
  210. die();
  211. }
  212. /**
  213. * Escapes single quotes, but not double quotes.
  214. *
  215. * @return string
  216. * @access public
  217. * @static
  218. */
  219. public static function escapequotes($string) {
  220. return str_replace('\"', '"', addslashes($string));
  221. }
  222. /**
  223. * json_encode() wrapper, also skips debug output and sends headers
  224. *
  225. * @return string
  226. * @access public
  227. * @static
  228. */
  229. static function json($data) {
  230. if(!defined('SKIP_DEBUG')) define('SKIP_DEBUG', true);
  231. header('Content-Type: application/json');
  232. return json_encode($data);
  233. }
  234. /**
  235. * Writes an entry to the audit log
  236. *
  237. * @return void
  238. * @access public
  239. * @static
  240. */
  241. static public function audit($message, $item_id = NULL, $type = 'info', $data = NULL) {
  242. if(!is_array($data)) {
  243. $data = array();
  244. }
  245. $data['_ip'] = self::getIP();
  246. DB::getInstance()->query("INSERT INTO %tp%log SET
  247. user_id = ?,
  248. type = ?,
  249. controller = ?,
  250. action = ?,
  251. message = ?,
  252. item_id = ?,
  253. data = ?,
  254. log_date = NOW()",
  255. (User::getId()!==false ? User::getId() : NULL),
  256. $type,
  257. CONTROLLER,
  258. ACTION,
  259. $message,
  260. (is_numeric($item_id) ? $item_id : NULL),
  261. serialize($data)
  262. );
  263. }
  264. /**
  265. * Recursive stripslashes function.
  266. *
  267. * @return mixed
  268. * @access public
  269. * @static
  270. */
  271. static function stripslashesDeep($value) {
  272. $value = is_array($value) ? array_map(array('Library', 'stripslashesDeep'), $value) : stripslashes($value) ;
  273. return $value;
  274. }
  275. /**
  276. * Store a message in the session to display on next page load.
  277. *
  278. * @return void
  279. * @access public
  280. * @static
  281. */
  282. static function notify($message) {
  283. Session::save('fruml_dashboard_notification', $message);
  284. }
  285. /**
  286. * Retrieve a message from the session store.
  287. *
  288. * @return string $message
  289. * @access public
  290. * @static
  291. */
  292. static function getNotification() {
  293. $message = Session::get('fruml_dashboard_notification');
  294. Session::delete('fruml_dashboard_notification');
  295. return $message;
  296. }
  297. /**
  298. * Store a message in the session to display in an allert on next page load.
  299. *
  300. * @return void
  301. * @access public
  302. * @static
  303. */
  304. static function notifyAlert($message) {
  305. Session::save('fruml_dashboard_alert', $message);
  306. }
  307. /**
  308. * Retrieve a message from the session to display in an alert.
  309. *
  310. * @return string $message
  311. * @access public
  312. * @static
  313. */
  314. static function getAlertNotification() {
  315. $message = Session::get('fruml_dashboard_alert');
  316. Session::delete('fruml_dashboard_alert');
  317. return $message;
  318. }
  319. /**
  320. * Retrieves the IP address.
  321. *
  322. * @return string IP Address
  323. * @access public
  324. * @static
  325. */
  326. static function getIP() {
  327. if(!empty($_SERVER['HTTP_CLIENT_IP'])) {
  328. $ip = $_SERVER['HTTP_CLIENT_IP'];
  329. } elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  330. $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
  331. } else {
  332. $ip = $_SERVER['REMOTE_ADDR'];
  333. }
  334. return $ip;
  335. }
  336. /**
  337. * Works out a file's mimetype. Tries to do so the nice way (by using finfo). If that fails,
  338. * tries to get the mimetype using a slightly less nice way (by using mime_content_type) and
  339. * if that fails, uses a very dirty lookup table using the file's extension.
  340. *
  341. * @return string $mime
  342. * @access public
  343. * @static
  344. */
  345. static function getMimeType($file) {
  346. $mime = false;
  347. //if(class_exists('finfo', false) && file_exists($file)) {
  348. // $finfo = new finfo(FILEINFO_MIME);
  349. // $fres = $finfo->file($file);
  350. // if (is_string($fres) && !empty($fres)) {
  351. // $mime = $fres;
  352. // }
  353. //} elseif(function_exists('mime_content_type') && file_exists($file)) {
  354. // $mime = mime_content_type($file);
  355. //} else {
  356. $mime_types = array(
  357. 'txt' => 'text/plain',
  358. 'htm' => 'text/html',
  359. 'html' => 'text/html',
  360. 'php' => 'text/html',
  361. 'css' => 'text/css',
  362. 'js' => 'application/javascript',
  363. 'json' => 'application/json',
  364. 'xml' => 'application/xml',
  365. 'swf' => 'application/x-shockwave-flash',
  366. 'flv' => 'video/x-flv',
  367. 'png' => 'image/png',
  368. 'jpe' => 'image/jpeg',
  369. 'jpeg' => 'image/jpeg',
  370. 'jpg' => 'image/jpeg',
  371. 'gif' => 'image/gif',
  372. 'bmp' => 'image/bmp',
  373. 'ico' => 'image/vnd.microsoft.icon',
  374. 'tiff' => 'image/tiff',
  375. 'tif' => 'image/tiff',
  376. 'svg' => 'image/svg+xml',
  377. 'svgz' => 'image/svg+xml',
  378. 'zip' => 'application/zip',
  379. 'rar' => 'application/x-rar-compressed',
  380. 'exe' => 'application/x-msdownload',
  381. 'msi' => 'application/x-msdownload',
  382. 'cab' => 'application/vnd.ms-cab-compressed',
  383. 'mp3' => 'audio/mpeg',
  384. 'qt' => 'video/quicktime',
  385. 'mov' => 'video/quicktime',
  386. 'pdf' => 'application/pdf',
  387. 'psd' => 'image/vnd.adobe.photoshop',
  388. 'ai' => 'application/postscript',
  389. 'eps' => 'application/postscript',
  390. 'ps' => 'application/postscript',
  391. 'doc' => 'application/msword',
  392. 'rtf' => 'application/rtf',
  393. 'xls' => 'application/vnd.ms-excel',
  394. 'ppt' => 'application/vnd.ms-powerpoint',
  395. 'odt' => 'application/vnd.oasis.opendocument.text',
  396. 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
  397. );
  398. $ext = Library::getExtension($file);
  399. if(isset($mime_types[$ext])) {
  400. return $mime_types[$ext];
  401. }
  402. //}
  403. if($mime===false) {
  404. $mime = 'application/octet-stream';
  405. }
  406. return $mime;
  407. }
  408. /**
  409. * Returns the extension on a file (or other string)
  410. *
  411. * @param string $string
  412. * @return string $ext
  413. * @access public
  414. * @static
  415. */
  416. static function getExtension($string) {
  417. return substr(strrchr($string, "."), 1);
  418. }
  419. /**
  420. * Returns a string's length.
  421. *
  422. * @param $data The string to get the length of.
  423. * @return int The length of the string.
  424. */
  425. static function length($data) {
  426. if(function_exists('mb_strlen')) {
  427. return mb_strlen($data, 'utf-8');
  428. } else {
  429. return strlen(utf8_decode($data));
  430. }
  431. }
  432. /**
  433. * Cleans up a filename. Don't supply a file path, as that will be cleaned up beyond all recognition (cubar?).
  434. *
  435. * @param $string The string to sanitize.
  436. * @return string The sanitized file name.
  437. */
  438. static function sanitizeFilename($string) {
  439. $extension = Library::getExtension($string);
  440. $simple = str_replace('.'.$extension, '', $string);
  441. $simple = trim($simple);
  442. $simple = str_replace(" ", "-", $simple);
  443. $simple = str_replace("--", "-", $simple);
  444. $string = htmlentities($string);
  445. $string = preg_replace("/&([a-z])[a-z]+;/i", "$1", $string);
  446. $simple = preg_replace("/[^a-zA-Z0-9_-]/", "", $simple);
  447. if($extension != '') {
  448. $simple .= '.'.$extension;
  449. }
  450. return strtolower($simple);
  451. }
  452. /**
  453. * Works out the max upload size for files based on ini settings.
  454. * @param boolean $as_int Indicates whether the max upload size should be returned as integer.
  455. * @return string The max possible upload size.
  456. */
  457. static function getMaxUploadSize($as_int=false) {
  458. $post_max_size = ini_get('post_max_size');
  459. $unit = strtoupper(substr($post_max_size, -1));
  460. $multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1)));
  461. $post_size = $multiplier*(int)$post_max_size;
  462. $upload_max_size = ini_get('upload_max_filesize');
  463. $unit = strtoupper(substr($upload_max_size, -1));
  464. $multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1)));
  465. $upload_size = $multiplier*(int)$upload_max_size;
  466. $max_size = min($post_size, $upload_size);
  467. if($as_int) {
  468. return $max_size;
  469. } else {
  470. return strtoupper(Library::humanSize($max_size, '%1.0f'));
  471. }
  472. }
  473. /**
  474. * Formats a bytecount to be readable for humans
  475. * @param $size
  476. * @param $unit
  477. * @param $retstring
  478. * @param $si
  479. * @author Aidan Lister <aidan@php.net>
  480. * @link http://aidanlister.com/repos/v/function.rmdirr.php
  481. * @author Fruml (slight modifications)
  482. * @return unknown_type
  483. */
  484. static function sizeReadable($size, $unit = NULL, $retstring = NULL, $si = true) {
  485. $sizes = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
  486. $mod = 1024;
  487. $ii = count($sizes) - 1;
  488. $unit = array_search((string) $unit, $sizes);
  489. if ($unit === NULL || $unit === false) {
  490. $unit = $ii;
  491. }
  492. if ($retstring === NULL) {
  493. $retstring = '%2.1f';
  494. }
  495. $i = 0;
  496. while ($unit != $i && $size >= 1024 && $i < $ii) {
  497. $size /= $mod;
  498. $i++;
  499. }
  500. return array(sprintf($retstring, $size), $sizes[$i]);
  501. }
  502. /**
  503. * @function humanSize
  504. * Wrapper for sizeReadable, returns a single string.
  505. */
  506. static function humanSize($size, $retstring = NULL) {
  507. $size = Library::sizeReadable($size, NULL, $retstring, NULL);
  508. return $size[0].' '.$size[1];
  509. }
  510. /**
  511. * @function incrementFileName
  512. * Checks to see if a file name contains a counter, and if so, increases it
  513. */
  514. static function incrementFilename($file) {
  515. // split the filename up
  516. $ext_only = false;
  517. $file = explode('/', Library::formatPath($file));
  518. $file_name = array_pop($file);
  519. $ext = Library::getExtension($file_name);
  520. $ext = !empty($ext) ? '.'.$ext : '';
  521. $file_name = str_replace($ext, '', $file_name);
  522. if(empty($file_name)) {
  523. $ext_only = true;
  524. $file_name = $ext;
  525. }
  526. $base_path = implode('/', $file).'/';
  527. // split the file name up using the counter separator (-)
  528. $file_name_parts = explode('-', $file_name);
  529. if(count($file_name_parts)==1) {
  530. $file_name_parts[] = '0';
  531. }
  532. // does the file already have an increment counter?
  533. if(preg_match('/(?<digit>\d+)/', $file_name_parts[count($file_name_parts)-1], $matches)) {
  534. $counter = $matches[0];
  535. $new_counter = $counter + 1;
  536. $file_name_parts[count($file_name_parts)-1] = $new_counter;
  537. $file_name = implode('-', $file_name_parts);
  538. } else {
  539. $file_name .= '-1';
  540. }
  541. $path = $base_path.$file_name;
  542. if(!$ext_only) {
  543. $path .= $ext;
  544. }
  545. return $path;
  546. }
  547. /**
  548. * @function moveTempFile
  549. * moves a file from it's temp to it's permament location
  550. */
  551. public static function moveTempFile($path) {
  552. if(strpos(Library::formatPath(UPLOAD_PATH.$path), Library::formatPath(UPLOAD_PATH.'/temp/'))!==false) {
  553. $filename = basename($path);
  554. $source = Library::formatPath(UPLOAD_PATH.$path);
  555. $destination = Library::formatPath(UPLOAD_PATH.strtolower($filename[0]).'/');
  556. if(!ini_get('safe_mode')) {
  557. if(!file_exists($destination)) {
  558. $old_umask = umask(0);
  559. mkdir($destination, 0777);
  560. umask($old_umask);
  561. }
  562. } else {
  563. $destination = Library::formatPath(UPLOAD_PATH.'/');
  564. }
  565. $destination .= $filename;
  566. while(file_exists($destination)) {
  567. $destination = Library::incrementFileName($destination);
  568. }
  569. Library::disableErrorHandling();
  570. $res = rename($source, $destination);
  571. Library::enableErrorHandling();
  572. if($res===false) {
  573. Error::raise(trans('could.not.move.uploaded.file'));
  574. } else {
  575. return str_replace(UPLOAD_PATH, '', $destination);
  576. }
  577. } else {
  578. return $path;
  579. }
  580. }
  581. /**
  582. * @function disableErrorHandling
  583. * Turn off error handling
  584. */
  585. static function disableErrorHandling() {
  586. error_reporting(0);
  587. $old_error_handling = restore_error_handler();
  588. }
  589. /**
  590. * @function enableErrorHandling
  591. * Turn error handling back on again
  592. */
  593. static function enableErrorHandling() {
  594. error_reporting(E_ALL);
  595. if(!IS_CLI) set_error_handler('catch_errors');
  596. }
  597. /**
  598. * @function loadChains
  599. * Loads the image chains.
  600. */
  601. static $imageChains = array();
  602. static function loadChains() {
  603. if(empty(self::$imageChains)) {
  604. self::$imageChains = Cache::get('imagechains');
  605. if(is_null(self::$imageChains)) {
  606. include_once Library::formatPath(APP_PATH.'include/include.image-chains.php');
  607. $db = DB::getInstance();
  608. $chains = $db->query("SELECT * FROM %tp%transformation AS t LEFT JOIN %tp%transformation_step AS s ON s.t_id=t.id ORDER BY s.t_id, s.`order` ASC;")->fetchAll();
  609. foreach($chains as $chain) {
  610. if(!empty($chain['type'])) {
  611. self::$imageChains[$chain['name']][] = array($chain['type'], unserialize($chain['parameters']), $chain['id']);
  612. } else {
  613. self::$imageChains[$chain['name']] = array();
  614. }
  615. }
  616. Cache::write('imagechains', self::$imageChains);
  617. }
  618. }
  619. }
  620. /**
  621. * @function isImage
  622. * Checks a file's extension to see if it's an image.
  623. */
  624. static function isImage($path) {
  625. $ext = strtolower(self::getExtension($path));
  626. $images = array('png', 'jpg', 'jpeg', 'gif');
  627. return in_array($ext, $images);
  628. }
  629. /**
  630. * @function getChain
  631. * Returns an image chain
  632. */
  633. static function getChain($name, $default = true) {
  634. self::loadChains();
  635. if(isset(self::$imageChains[$name])) {
  636. return self::$imageChains[$name];
  637. } elseif($default) {
  638. return self::$imageChains['default'];
  639. } else {
  640. return false;
  641. }
  642. }
  643. static function updateImagePath($data) {
  644. $data['path'] = BASE.str_replace(ROOT_PATH, '', $data['path']);
  645. return $data;
  646. }
  647. /**
  648. * Encodes $data for display in a form, uses htmlspeciarchars().
  649. * @param $data The data to encode.
  650. * @param $quote_type Quote type to use when encoding, defaults to ENT_QUOTES.
  651. * @return unknown_type
  652. */
  653. static function encode($data, $quote_type=ENT_QUOTES) {
  654. return htmlspecialchars($data, $quote_type, 'UTF-8');
  655. }
  656. /**
  657. * Recursively delete a directory and it's contents
  658. * @author Aidan Lister <aidan@php.net>
  659. * @link http://aidanlister.com/repos/v/function.rmdirr.php
  660. * @param $dirname
  661. * @return Boolean indicating success at deleting the directory.
  662. */
  663. static function rmdirr($dirname) {
  664. if (!file_exists($dirname)) {
  665. return false;
  666. }
  667. if (is_file($dirname) || is_link($dirname)) {
  668. return unlink($dirname);
  669. }
  670. $dir = dir($dirname);
  671. while (false !== $entry = $dir->read()) {
  672. if ($entry == '.' || $entry == '..') {
  673. continue;
  674. }
  675. Library::rmdirr($dirname . DIRECTORY_SEPARATOR . $entry);
  676. }
  677. $dir->close();
  678. return rmdir($dirname);
  679. }
  680. /**
  681. * Tells Fruml not to output debug information.
  682. * @return void
  683. */
  684. public static function skipDebug() {
  685. if(!defined('SKIP_DEBUG')) {
  686. define('SKIP_DEBUG', true);
  687. }
  688. }
  689. /**
  690. * Pads a string.
  691. * @param $value The string to pad.
  692. * @param $len The length to pad the string to.
  693. * @param $char The character to pad with.
  694. * @return The padded string.
  695. */
  696. static function stringPad($value, $len=2, $char = '0') {
  697. return str_pad($value, $len, $char, STR_PAD_LEFT);
  698. }
  699. /**
  700. * Loads a widget class file and returns the name of the actual widget class.
  701. * @param $name The id of the widget (e.g. weather).
  702. * @return String representing the widget's class name (e.g. WeatherWidget).
  703. */
  704. static function loadWidget($name) {
  705. $widget_path = WIDGET_PATH . strtolower($name) . '/widget.' . strtolower($name) . '.php';
  706. $widget_name = ucfirst($name).'Widget';
  707. if(class_exists($widget_name, false)) {
  708. return $widget_name;
  709. }
  710. if(file_exists($widget_path)) {
  711. require_once $widget_path;
  712. return $widget_name;
  713. } else {
  714. return false;
  715. }
  716. }
  717. /**
  718. * Simple wrapper for retrieving remote files. Wrapped here for error_reporting issues. Tries to use cURL if available.
  719. * @param $url The URL to retrieve.
  720. * @return The contents of the remote file or false in case of failure (dns, timeout, bad url etc).
  721. */
  722. static function getRemoteFile($url, $convert_utf8 = false) {
  723. self::disableErrorHandling();
  724. if(function_exists('curl_init')) {
  725. $ch = curl_init();
  726. curl_setopt($ch, CURLOPT_URL, $url);
  727. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  728. curl_setopt($ch, CURLOPT_HEADER, 0);
  729. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  730. curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
  731. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
  732. $res = curl_exec($ch);
  733. $response = curl_getinfo($ch);
  734. curl_close($ch);
  735. if($convert_utf8 && isset($response['content_type'])) {
  736. $ct = $response['content_type'];
  737. preg_match('#charset=(.*)#i', $ct, $m);
  738. if(isset($m[1])) {
  739. switch (strtolower($m[1])) {
  740. case 'utf-8':
  741. break;
  742. case 'iso-8859-1':
  743. $res = utf8_encode($res);
  744. break;
  745. default:
  746. $res = iconv($m[1], 'utf-8', $res);
  747. }
  748. }
  749. }
  750. } else {
  751. $res = file_get_contents($url);
  752. foreach ($http_response_header as $header) {
  753. if (preg_match('#charset=(.*)#i', $header, $m)) {
  754. switch (strtolower($m[1])) {
  755. case 'utf-8':
  756. break;
  757. case 'iso-8859-1':
  758. $res = utf8_encode($res);
  759. break;
  760. default:
  761. $res = iconv($m[1], 'utf-8', $res);
  762. }
  763. break;
  764. }
  765. }
  766. }
  767. self::enableErrorHandling();
  768. return $res;
  769. }
  770. /**
  771. * Pretty-formats the contents of a file. If GeSHi has been installed, it will be used, otherwise the file's contents are wrapped in a <pre> tag.
  772. * @param $path The file containing the code to highlight
  773. * @return String containing the highlighted code.
  774. */
  775. static function syntaxHighlight($path, $lines = false, $strict = 'maybe') {
  776. if(file_exists(VENDOR_PATH.'geshi/geshi.php') && filesize($path) < 10240) {
  777. require_once VENDOR_PATH.'geshi/geshi.php';
  778. $geshi = new GeSHi('', 'php');
  779. $geshi->set_header_type(GESHI_HEADER_DIV);
  780. $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
  781. $geshi->enable_keyword_links(false);
  782. $geshi->set_tab_width(4);
  783. $geshi->load_from_file($path);
  784. if($strict=='maybe') $strict = GESHI_MAYBE;
  785. $geshi->enable_strict_mode($strict);
  786. $geshi->set_overall_class('code-container');
  787. $geshi->enable_classes();
  788. if($lines!==false) {
  789. $geshi->highlight_lines_extra($lines);
  790. $geshi->set_highlight_lines_extra_style('background-color: #FFDDDD');
  791. }
  792. Library::disableErrorHandling();
  793. $ret = array('code' => $geshi->parse_code(), 'css' => $geshi->get_stylesheet());
  794. Library::enableErrorHandling();
  795. return $ret;
  796. } else {
  797. return array('code' => '<pre class="code-container">'.htmlentities(file_get_contents($path)).'</pre>', 'css' => '');
  798. }
  799. }
  800. /**
  801. * Pretty-formats the passed string. If GeSHi has been installed, it will be used, otherwise the passed string is wrapped in a <pre> tag.
  802. * @param $code The code to highlight
  803. * @return String containing the highlighted code.
  804. */
  805. static function syntaxHighlightCode($code, $type='php', $lines = false, $strict = 'maybe', $start = 0) {
  806. if(file_exists(VENDOR_PATH.'geshi/geshi.php') && Library::length($code) < 10240) {
  807. require_once VENDOR_PATH.'geshi/geshi.php';
  808. $geshi = new GeSHi($code, $type);
  809. $geshi->set_header_type(GESHI_HEADER_DIV);
  810. $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
  811. $geshi->enable_keyword_links(false);
  812. $geshi->set_tab_width(4);
  813. if($strict=='maybe') $strict = GESHI_MAYBE;
  814. $geshi->enable_strict_mode($strict);
  815. $geshi->set_overall_class('code-container');
  816. $geshi->enable_classes();
  817. if($lines!==false) {
  818. $geshi->highlight_lines_extra($lines);
  819. $geshi->start_line_numbers_at($start);
  820. $geshi->set_highlight_lines_extra_style('background-color: #FFDDDD');
  821. }
  822. Library::disableErrorHandling();
  823. $ret = array('code' => $geshi->parse_code(), 'css' => $geshi->get_stylesheet());
  824. Library::enableErrorHandling();
  825. return $ret;
  826. } else {
  827. return array('code' => '<pre class="code-container">'.htmlentities(file_get_contents($code)).'</pre>', 'css' => '');
  828. }
  829. }
  830. /**
  831. * Removes empty entries in an array.
  832. * @param $array The array to unempty.
  833. * @return Array containingno empty entries.
  834. */
  835. static function unempty(Array $array) {
  836. $res = array();
  837. foreach($array as $key => $value) {
  838. if(!empty($value)) {
  839. $res[$key] = $value;
  840. }
  841. }
  842. return $res;
  843. }
  844. /**
  845. * Shortens a string, adds dots
  846. * @param $string The string to shorten
  847. * @param $chars The number of characters to keep
  848. * @param $dots Whether to add dots to the truncated string
  849. * @return String containing the shortened string.
  850. */
  851. static function truncate($string, $chars=30, $dots=true) {
  852. if(strlen($string)>$chars) {
  853. $string = substr($string, 0, $chars);
  854. if($dots) {
  855. $string .= '...';
  856. }
  857. }
  858. return $string;
  859. }
  860. /**
  861. * Pauses execution for a while.
  862. * @param $pause The number of seconds to pause
  863. * @param $debug_only Only pause is DEBUG is set to true
  864. * @return void
  865. */
  866. static function pause($pause=2, $debug_only=true) {
  867. if(($debug_only==true && DEBUG) || !$debug_only) {
  868. sleep($pause);
  869. }
  870. }
  871. /**
  872. * Attempts to change the mode of a file or directory.
  873. * @param $path The path to change the mode of
  874. * @param $mode The mode to apply
  875. * @return Boolean true on success, false on failure
  876. */
  877. static function chmod($path, $mode=0666) {
  878. if(file_exists($path) && is_writable($path)) {
  879. if(function_exists('chmod') && self::is_enabled('chmod')) {
  880. self::disableErrorHandling();
  881. $res = chmod($path, $mode);
  882. self::enableErrorHandling();
  883. return $res;
  884. }
  885. }
  886. return false;
  887. }
  888. /**
  889. * Checks the disable_functions ini parameter to see if a function is disabled
  890. * @param $function The function to test for
  891. * @return Boolean true on success, false on failure
  892. */
  893. static function is_enabled($function) {
  894. $disabled_functions = explode(',', ini_get('disable_functions'));
  895. return !in_array($function, $disabled_functions);
  896. }
  897. /**
  898. * Loads a library
  899. * @param $name The name of the library to load
  900. * @return An instantiated library of type 'name'
  901. */
  902. static function loadLibrary($name) {
  903. $path = LIB_PATH.'lib.'.strtolower($name).'.php';
  904. if(file_exists($path)) {
  905. include_once $path;
  906. return new $name();
  907. } else {
  908. Error::raise(sprintf(trans('Cannot load library `%s` - the library file cannot be found.'), $name));
  909. }
  910. }
  911. }
  912. /**
  913. * Alias of {@link Libary::dbg()}
  914. *
  915. * @param mixed $data,...
  916. *
  917. * @see Library::dbg()
  918. */
  919. function dbg() {
  920. $args = func_get_args();
  921. call_user_func_array(array('Library', 'dbg'), $args);
  922. }
  923. /**
  924. * Alias of {@link Libary::dbgd()}
  925. *
  926. * @param mixed $data,...
  927. * @see Library::dbgd()
  928. */
  929. function dbgd() {
  930. $args = func_get_args();
  931. call_user_func_array(array('Library', 'dbgd'), $args);
  932. }
  933. if(!IS_CLI) {
  934. function catch_errors($errno, $errstr, $errfile, $errline) {
  935. Error::raise('<strong>'.$errstr . '</strong><br /><span class="mono">'.$errfile.':'.$errline.'</span>', $errtype='PHP', $errno, $errfile, $errline);
  936. }
  937. set_error_handler('catch_errors');
  938. // base function for unhandled (eep!) exceptions
  939. function unhandled_exception_handler($exception) {
  940. Error::raise('Unhandled Exception: '.$exception->getMessage(), $errtype='PHP', $exception->getCode(), $exception->getFile(), $exception->getLine());
  941. }
  942. set_exception_handler('unhandled_exception_handler');
  943. }
  944. /**
  945. * Check for question mark or ampersand in url.
  946. * @return Returns a question mark or an ampersand, depending on NICE_URLS setting
  947. */
  948. function qamp($entity = true) {
  949. if(NICE_URLS) {
  950. return '?';
  951. } else {
  952. return $entity ? '&amp;' : '&' ;
  953. }
  954. }
  955. // translation functions
  956. $GLOBALS['trans_bound_domains'] = array();
  957. function trans($string) {
  958. return T_($string);
  959. }
  960. function p_trans($domain, $string) {
  961. if(!in_array($domain, $GLOBALS['trans_bound_domains'])) {
  962. T_bindtextdomain($domain, I18N_PATH);
  963. T_bind_textdomain_codeset($domain, 'utf8');
  964. $GLOBALS['trans_bound_domains'][] = $domain;
  965. }
  966. return T_dgettext($domain, $string);
  967. }