PageRenderTime 67ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/kirby.php

https://github.com/nikrowell/kirby
PHP | 3409 lines | 1353 code | 509 blank | 1547 comment | 250 complexity | ccdbce8f7d5838457b80f02ace0a3298 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Kirby -- A stripped down and easy to use toolkit for PHP
  4. *
  5. * @version 0.94
  6. * @author Bastian Allgeier <bastian@getkirby.com>
  7. * @link http://toolkit.getkirby.com
  8. * @copyright Copyright 2009-2012 Bastian Allgeier
  9. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  10. * @package Kirby
  11. */
  12. c::set('version', 0.94);
  13. c::set('language', 'en');
  14. c::set('charset', 'utf-8');
  15. c::set('root', dirname(__FILE__));
  16. /**
  17. * Redirects the user to a new URL
  18. *
  19. * @param string $url The URL to redirect to
  20. * @param boolean $code The HTTP status code, which should be sent (301, 302 or 303)
  21. * @package Kirby
  22. */
  23. function go($url=false, $code=false) {
  24. if(empty($url)) $url = c::get('url', '/');
  25. // send an appropriate header
  26. if($code) {
  27. switch($code) {
  28. case 301:
  29. header('HTTP/1.1 301 Moved Permanently');
  30. break;
  31. case 302:
  32. header('HTTP/1.1 302 Found');
  33. break;
  34. case 303:
  35. header('HTTP/1.1 303 See Other');
  36. break;
  37. }
  38. }
  39. // send to new page
  40. header('Location:' . $url);
  41. exit();
  42. }
  43. /**
  44. * Returns the status from a Kirby response
  45. *
  46. * @param array $response The Kirby response array
  47. * @return string "error" or "success"
  48. * @package Kirby
  49. */
  50. function status($response) {
  51. return a::get($response, 'status');
  52. }
  53. /**
  54. * Returns the message from a Kirby response
  55. *
  56. * @param array $response The Kirby response array
  57. * @return string The message
  58. * @package Kirby
  59. */
  60. function msg($response) {
  61. return a::get($response, 'msg');
  62. }
  63. /**
  64. * Checks if a Kirby response is an error response or not.
  65. *
  66. * @param array $response The Kirby response array
  67. * @return boolean Returns true if the response is an error, returns false if no error occurred
  68. * @package Kirby
  69. */
  70. function error($response) {
  71. return (status($response) == 'error') ? true : false;
  72. }
  73. /**
  74. * Checks if a Kirby response is a success response.
  75. *
  76. * @param array $response The Kirby response array
  77. * @return boolean Returns true if the response is a success, returns false if an error occurred
  78. * @package Kirby
  79. */
  80. function success($response) {
  81. return !error($response);
  82. }
  83. /**
  84. * Loads additional PHP files
  85. *
  86. * You can set the root directory with c::set('root', 'my/root');
  87. * By default the same directory in which the kirby toolkit file is located will be used.
  88. *
  89. * @param args A list filenames as individual arguments
  90. * @return array Returns a Kirby response array. On error the response array includes the unloadable files (errors).
  91. * @package Kirby
  92. */
  93. function load() {
  94. $root = c::get('root');
  95. $files = func_get_args();
  96. $errors = array();
  97. foreach((array)$files AS $f) {
  98. $file = $root . '/' . $f . '.php';
  99. if(file_exists($file)) {
  100. include_once($file);
  101. } else {
  102. $errors[] = $file;
  103. }
  104. }
  105. if(!empty($errors)) return array(
  106. 'status' => 'error',
  107. 'msg' => 'some files could not be loaded',
  108. 'errors' => $errors
  109. );
  110. return array(
  111. 'status' => 'success',
  112. 'msg' => 'all files have been loaded'
  113. );
  114. }
  115. /**
  116. *
  117. * Array
  118. *
  119. * This class is supposed to simplify array handling
  120. * and make it more consistent.
  121. *
  122. * @package Kirby
  123. */
  124. class a {
  125. /**
  126. * Gets an element of an array by key
  127. *
  128. * @param array $array The source array
  129. * @param mixed $key The key to look for
  130. * @param mixed $default Optional default value, which should be returned if no element has been found
  131. * @return mixed
  132. */
  133. static function get($array, $key, $default=null) {
  134. return (isset($array[ $key ])) ? $array[ $key ] : $default;
  135. }
  136. /**
  137. * Gets all elements for an array of key
  138. *
  139. * @param array $array The source array
  140. * @keys array $keys An array of keys to fetch
  141. * @return array An array of keys and matching values
  142. */
  143. static function getall($array, $keys) {
  144. $result = array();
  145. foreach($keys as $key) $result[$key] = $array[$key];
  146. return $result;
  147. }
  148. /**
  149. * Removes an element from an array
  150. *
  151. * @param array $array The source array
  152. * @param mixed $search The value or key to look for
  153. * @param boolean $key Pass true to search for an key, pass false to search for an value.
  154. * @return array The result array without the removed element
  155. */
  156. static function remove($array, $search, $key=true) {
  157. if($key) {
  158. unset($array[$search]);
  159. } else {
  160. $found_all = false;
  161. while(!$found_all) {
  162. $index = array_search($search, $array);
  163. if($index !== false) {
  164. unset($array[$index]);
  165. } else {
  166. $found_all = true;
  167. }
  168. }
  169. }
  170. return $array;
  171. }
  172. /**
  173. * Injects an element into an array
  174. *
  175. * @param array $array The source array
  176. * @param int $position The position, where to inject the element
  177. * @param mixed $element The element, which should be injected
  178. * @return array The result array including the new element
  179. */
  180. static function inject($array, $position, $element='placeholder') {
  181. $start = array_slice($array, 0, $position);
  182. $end = array_slice($array, $position);
  183. return array_merge($start, (array)$element, $end);
  184. }
  185. /**
  186. * Shows an entire array or object in a human readable way
  187. * This is perfect for debugging
  188. *
  189. * @param array $array The source array
  190. * @param boolean $echo By default the result will be echoed instantly. You can switch that off here.
  191. * @return mixed If echo is false, this will return the generated array output.
  192. */
  193. static function show($array, $echo=true) {
  194. $output = '<pre>';
  195. $output .= htmlspecialchars(print_r($array, true));
  196. $output .= '</pre>';
  197. if($echo==true) echo $output;
  198. return $output;
  199. }
  200. /**
  201. * Converts an array to a JSON string
  202. * It's basically a shortcut for json_encode()
  203. *
  204. * @param array $array The source array
  205. * @return string The JSON string
  206. */
  207. static function json($array) {
  208. return @json_encode( (array)$array );
  209. }
  210. /**
  211. * Converts an array to a XML string
  212. *
  213. * @param array $array The source array
  214. * @param string $tag The name of the root element
  215. * @param boolean $head Include the xml declaration head or not
  216. * @param string $charset The charset, which should be used for the header
  217. * @param int $level The indendation level
  218. * @return string The XML string
  219. */
  220. static function xml($array, $tag='root', $head=true, $charset='utf-8', $tab=' ', $level=0) {
  221. $result = ($level==0 && $head) ? '<?xml version="1.0" encoding="' . $charset . '"?>' . "\n" : '';
  222. $nlevel = ($level+1);
  223. $result .= str_repeat($tab, $level) . '<' . $tag . '>' . "\n";
  224. foreach($array AS $key => $value) {
  225. $key = str::lower($key);
  226. if(is_array($value)) {
  227. $mtags = false;
  228. foreach($value AS $key2 => $value2) {
  229. if(is_array($value2)) {
  230. $result .= self::xml($value2, $key, $head, $charset, $tab, $nlevel);
  231. } else if(trim($value2) != '') {
  232. $value2 = (htmlspecialchars($value2) != $value2) ? '<![CDATA[' . $value2 . ']]>' : $value2;
  233. $result .= str_repeat($tab, $nlevel) . '<' . $key . '>' . $value2 . '</' . $key . '>' . "\n";
  234. }
  235. $mtags = true;
  236. }
  237. if(!$mtags && count($value) > 0) {
  238. $result .= self::xml($value, $key, $head, $charset, $tab, $nlevel);
  239. }
  240. } else if(trim($value) != '') {
  241. $value = (htmlspecialchars($value) != $value) ? '<![CDATA[' . $value . ']]>' : $value;
  242. $result .= str_repeat($tab, $nlevel) . '<' . $key . '>' . $value . '</' . $key . '>' . "\n";
  243. }
  244. }
  245. return $result . str_repeat($tab, $level) . '</' . $tag . '>' . "\n";
  246. }
  247. /**
  248. * Extracts a single column from an array
  249. *
  250. * @param array $array The source array
  251. * @param string $key The key name of the column to extract
  252. * @return array The result array with all values from that column.
  253. */
  254. static function extract($array, $key) {
  255. $output = array();
  256. foreach($array AS $a) if(isset($a[$key])) $output[] = $a[ $key ];
  257. return $output;
  258. }
  259. /**
  260. * Shuffles an array and keeps the keys
  261. *
  262. * @param array $array The source array
  263. * @return array The shuffled result array
  264. */
  265. static function shuffle($array) {
  266. $keys = array_keys($array);
  267. shuffle($keys);
  268. return array_merge(array_flip($keys), $array);
  269. }
  270. /**
  271. * Returns the first element of an array
  272. *
  273. * I always have to lookup the names of that function
  274. * so I decided to make this shortcut which is
  275. * easier to remember.
  276. *
  277. * @param array $array The source array
  278. * @return mixed The first element
  279. */
  280. static function first($array) {
  281. return array_shift($array);
  282. }
  283. /**
  284. * Returns the last element of an array
  285. *
  286. * I always have to lookup the names of that function
  287. * so I decided to make this shortcut which is
  288. * easier to remember.
  289. *
  290. * @param array $array The source array
  291. * @return mixed The last element
  292. */
  293. static function last($array) {
  294. return array_pop($array);
  295. }
  296. /**
  297. * Search for elements in an array by regular expression
  298. *
  299. * @param array $array The source array
  300. * @param string $search The regular expression
  301. * @return array The array of results
  302. */
  303. static function search($array, $search) {
  304. return preg_grep('#' . preg_quote($search) . '#i' , $array);
  305. }
  306. /**
  307. * Checks if an array contains a certain string
  308. *
  309. * @param array $array The source array
  310. * @param string $search The string to search for
  311. * @return boolean true: the array contains the string, false: it doesn't
  312. */
  313. static function contains($array, $search) {
  314. $search = self::search($array, $search);
  315. return (empty($search)) ? false : true;
  316. }
  317. /**
  318. * Fills an array up with additional elements to certain amount.
  319. *
  320. * @param array $array The source array
  321. * @param int $limit The number of elements the array should contain after filling it up.
  322. * @param mixed $fill The element, which should be used to fill the array
  323. * @return array The filled-up result array
  324. */
  325. static function fill($array, $limit, $fill='placeholder') {
  326. if(count($array) < $limit) {
  327. $diff = $limit-count($array);
  328. for($x=0; $x<$diff; $x++) $array[] = $fill;
  329. }
  330. return $array;
  331. }
  332. /**
  333. * Checks for missing elements in an array
  334. *
  335. * This is very handy to check for missing
  336. * user values in a request for example.
  337. *
  338. * @param array $array The source array
  339. * @param array $required An array of required keys
  340. * @return array An array of missing fields. If this is empty, nothing is missing.
  341. */
  342. static function missing($array, $required=array()) {
  343. $missing = array();
  344. foreach($required AS $r) {
  345. if(empty($array[$r])) $missing[] = $r;
  346. }
  347. return $missing;
  348. }
  349. /**
  350. * Sorts a multi-dimensional array by a certain column
  351. *
  352. * @param array $array The source array
  353. * @param string $field The name of the column
  354. * @param string $direction desc (descending) or asc (ascending)
  355. * @param const $method A PHP sort method flag.
  356. * @return array The sorted array
  357. */
  358. static function sort($array, $field, $direction='desc', $method=SORT_REGULAR) {
  359. $direction = (strtolower($direction) == 'desc') ? SORT_DESC : SORT_ASC;
  360. $helper = array();
  361. foreach($array as $key => $row) {
  362. $helper[$key] = (is_object($row)) ? (method_exists($row, $field)) ? str::lower($row->$field()) : str::lower($row->$field) : str::lower($row[$field]);
  363. }
  364. array_multisort($helper, $direction, $method, $array);
  365. return $array;
  366. }
  367. }
  368. /**
  369. *
  370. * Browser
  371. *
  372. * Browser sniffing is bad - I know!
  373. * But sometimes this class is very helpful to
  374. * react on certain browsers and build browser-specific
  375. * css selectors for example. It's up to you to use it.
  376. *
  377. * @package Kirby
  378. */
  379. class browser {
  380. /**
  381. * The entire user agent string
  382. *
  383. * @var string
  384. */
  385. static public $ua = false;
  386. /**
  387. * The readable name of the browser
  388. * For example: "ie"
  389. *
  390. * @var string
  391. */
  392. static public $name = false;
  393. /**
  394. * The readable browser engine name
  395. * For example: "webkit"
  396. *
  397. * @var string
  398. */
  399. static public $engine = false;
  400. /**
  401. * The browser version number
  402. * For example: "3.6"
  403. *
  404. * @var string
  405. */
  406. static public $version = false;
  407. /**
  408. * The platform name
  409. * For example: "mac"
  410. *
  411. * @var string
  412. */
  413. static public $platform = false;
  414. /**
  415. * True or false if it is a mobile device or not
  416. *
  417. * @var boolean
  418. */
  419. static public $mobile = false;
  420. /**
  421. * True or false if it is an iOS device or not
  422. *
  423. * @var boolean
  424. */
  425. static public $ios = false;
  426. /**
  427. * True or false if it is an iPhone or not
  428. *
  429. * @var boolean
  430. */
  431. static public $iphone = false;
  432. /**
  433. * Returns the name of the browser
  434. *
  435. * @param string $ua The user agent string
  436. * @return string The browser name
  437. */
  438. static function name($ua=null) {
  439. self::detect($ua);
  440. return self::$name;
  441. }
  442. /**
  443. * Returns the browser engine
  444. *
  445. * @param string $ua The user agent string
  446. * @return string The browser engine
  447. */
  448. static function engine($ua=null) {
  449. self::detect($ua);
  450. return self::$engine;
  451. }
  452. /**
  453. * Returns the browser version
  454. *
  455. * @param string $ua The user agent string
  456. * @return string The browser version
  457. */
  458. static function version($ua=null) {
  459. self::detect($ua);
  460. return self::$version;
  461. }
  462. /**
  463. * Returns the platform
  464. *
  465. * @param string $ua The user agent string
  466. * @return string The platform name
  467. */
  468. static function platform($ua=null) {
  469. self::detect($ua);
  470. return self::$platform;
  471. }
  472. /**
  473. * Checks if the user agent string is from a mobile device
  474. *
  475. * @param string $ua The user agent string
  476. * @return boolean True: mobile device, false: not a mobile device
  477. */
  478. static function mobile($ua=null) {
  479. self::detect($ua);
  480. return self::$mobile;
  481. }
  482. /**
  483. * Checks if the user agent string is from an iPhone
  484. *
  485. * @param string $ua The user agent string
  486. * @return boolean True: iPhone, false: not an iPhone
  487. */
  488. static function iphone($ua=null) {
  489. self::detect($ua);
  490. return self::$iphone;
  491. }
  492. /**
  493. * Checks if the user agent string is from an iOS device
  494. *
  495. * @param string $ua The user agent string
  496. * @return boolean True: iOS device, false: not an iOS device
  497. */
  498. static function ios($ua=null) {
  499. self::detect($ua);
  500. return self::$ios;
  501. }
  502. /**
  503. * Returns a browser-specific css selector string
  504. *
  505. * @param string $ua The user agent string
  506. * @param boolean $array True: return an array, false: return a string
  507. * @return mixed
  508. */
  509. static function css($ua=null, $array=false) {
  510. self::detect($ua);
  511. $css[] = self::$engine;
  512. $css[] = self::$name;
  513. if(self::$version) $css[] = self::$name . str_replace('.', '_', self::$version);
  514. $css[] = self::$platform;
  515. return ($array) ? $css : implode(' ', $css);
  516. }
  517. /**
  518. * The core detection method, which parses the user agent string
  519. *
  520. * @todo add new browser versions
  521. * @param string $ua The user agent string
  522. * @return array An array with all parsed info
  523. */
  524. static function detect($ua=null) {
  525. $ua = ($ua) ? str::lower($ua) : str::lower(server::get('http_user_agent'));
  526. // don't do the detection twice
  527. if(self::$ua == $ua) return array(
  528. 'name' => self::$name,
  529. 'engine' => self::$engine,
  530. 'version' => self::$version,
  531. 'platform' => self::$platform,
  532. 'agent' => self::$ua,
  533. 'mobile' => self::$mobile,
  534. 'iphone' => self::$iphone,
  535. 'ios' => self::$ios,
  536. );
  537. self::$ua = $ua;
  538. self::$name = false;
  539. self::$engine = false;
  540. self::$version = false;
  541. self::$platform = false;
  542. // browser
  543. if(!preg_match('/opera|webtv/i', self::$ua) && preg_match('/msie\s(\d)/', self::$ua, $array)) {
  544. self::$version = $array[1];
  545. self::$name = 'ie';
  546. self::$engine = 'trident';
  547. } else if(strstr(self::$ua, 'firefox/3.6')) {
  548. self::$version = 3.6;
  549. self::$name = 'fx';
  550. self::$engine = 'gecko';
  551. } else if (strstr(self::$ua, 'firefox/3.5')) {
  552. self::$version = 3.5;
  553. self::$name = 'fx';
  554. self::$engine = 'gecko';
  555. } else if(preg_match('/firefox\/(\d+)/i', self::$ua, $array)) {
  556. self::$version = $array[1];
  557. self::$name = 'fx';
  558. self::$engine = 'gecko';
  559. } else if(preg_match('/opera(\s|\/)(\d+)/', self::$ua, $array)) {
  560. self::$engine = 'presto';
  561. self::$name = 'opera';
  562. self::$version = $array[2];
  563. } else if(strstr(self::$ua, 'konqueror')) {
  564. self::$name = 'konqueror';
  565. self::$engine = 'webkit';
  566. } else if(strstr(self::$ua, 'iron')) {
  567. self::$name = 'iron';
  568. self::$engine = 'webkit';
  569. } else if(strstr(self::$ua, 'chrome')) {
  570. self::$name = 'chrome';
  571. self::$engine = 'webkit';
  572. if(preg_match('/chrome\/(\d+)/i', self::$ua, $array)) { self::$version = $array[1]; }
  573. } else if(strstr(self::$ua, 'applewebkit/')) {
  574. self::$name = 'safari';
  575. self::$engine = 'webkit';
  576. if(preg_match('/version\/(\d+)/i', self::$ua, $array)) { self::$version = $array[1]; }
  577. } else if(strstr(self::$ua, 'mozilla/')) {
  578. self::$engine = 'gecko';
  579. self::$name = 'fx';
  580. }
  581. // platform
  582. if(strstr(self::$ua, 'j2me')) {
  583. self::$platform = 'mobile';
  584. } else if(strstr(self::$ua, 'iphone')) {
  585. self::$platform = 'iphone';
  586. } else if(strstr(self::$ua, 'ipod')) {
  587. self::$platform = 'ipod';
  588. } else if(strstr(self::$ua, 'ipad')) {
  589. self::$platform = 'ipad';
  590. } else if(strstr(self::$ua, 'mac')) {
  591. self::$platform = 'mac';
  592. } else if(strstr(self::$ua, 'darwin')) {
  593. self::$platform = 'mac';
  594. } else if(strstr(self::$ua, 'webtv')) {
  595. self::$platform = 'webtv';
  596. } else if(strstr(self::$ua, 'win')) {
  597. self::$platform = 'win';
  598. } else if(strstr(self::$ua, 'freebsd')) {
  599. self::$platform = 'freebsd';
  600. } else if(strstr(self::$ua, 'x11') || strstr(self::$ua, 'linux')) {
  601. self::$platform = 'linux';
  602. }
  603. self::$mobile = (self::$platform == 'mobile') ? true : false;
  604. self::$iphone = (in_array(self::$platform, array('ipod', 'iphone'))) ? true : false;
  605. self::$ios = (in_array(self::$platform, array('ipod', 'iphone', 'ipad'))) ? true : false;
  606. return array(
  607. 'name' => self::$name,
  608. 'engine' => self::$engine,
  609. 'version' => self::$version,
  610. 'platform' => self::$platform,
  611. 'agent' => self::$ua,
  612. 'mobile' => self::$mobile,
  613. 'iphone' => self::$iphone,
  614. 'ios' => self::$ios,
  615. );
  616. }
  617. }
  618. /**
  619. *
  620. * Config
  621. *
  622. * This is the core class to handle
  623. * configuration values/constants.
  624. *
  625. * @package Kirby
  626. */
  627. class c {
  628. /**
  629. * The static config array
  630. * It contains all config values
  631. *
  632. * @var array
  633. */
  634. private static $config = array();
  635. /**
  636. * Gets a config value by key
  637. *
  638. * @param string $key The key to look for. Pass false to get the entire config array
  639. * @param mixed $default The default value, which will be returned if the key has not been found
  640. * @return mixed The found config value
  641. */
  642. static function get($key=null, $default=null) {
  643. if(empty($key)) return self::$config;
  644. return a::get(self::$config, $key, $default);
  645. }
  646. /**
  647. * Sets a config value by key
  648. *
  649. * @param string $key The key to define
  650. * @param mixed $value The value for the passed key
  651. */
  652. static function set($key, $value=null) {
  653. if(is_array($key)) {
  654. // set all new values
  655. self::$config = array_merge(self::$config, $key);
  656. } else {
  657. self::$config[$key] = $value;
  658. }
  659. }
  660. /**
  661. * Loads an additional config file
  662. * Returns the entire configuration array
  663. *
  664. * @param string $file The path to the config file
  665. * @return array The entire config array
  666. */
  667. static function load($file) {
  668. if(file_exists($file)) require_once($file);
  669. return c::get();
  670. }
  671. }
  672. /**
  673. *
  674. * Content
  675. *
  676. * This class handles output buffering,
  677. * content loading and setting content type headers.
  678. *
  679. * @package Kirby
  680. */
  681. class content {
  682. /**
  683. * Starts the output buffer
  684. *
  685. */
  686. static function start() {
  687. ob_start();
  688. }
  689. /**
  690. * Stops the output buffer
  691. * and flush the content or return it.
  692. *
  693. * @param boolean $return Pass true to return the content instead of flushing it
  694. * @return mixed
  695. */
  696. static function end($return=false) {
  697. if($return) {
  698. $content = ob_get_contents();
  699. ob_end_clean();
  700. return $content;
  701. }
  702. ob_end_flush();
  703. }
  704. /**
  705. * Loads content from a passed file
  706. *
  707. * @param string $file The path to the file
  708. * @param boolean $return True: return the content of the file, false: echo the content
  709. * @return mixed
  710. */
  711. static function load($file, $return=true) {
  712. self::start();
  713. require_once($file);
  714. $content = self::end(true);
  715. if($return) return $content;
  716. echo $content;
  717. }
  718. /**
  719. * Simplifies setting content type headers
  720. *
  721. * @param string $ctype The shortcut for the content type. See the keys of the $ctypes array for all available shortcuts
  722. * @param string $charset The charset definition for the content type header. Default is "utf-8"
  723. */
  724. static function type() {
  725. $args = func_get_args();
  726. // shortcuts for content types
  727. $ctypes = array(
  728. 'html' => 'text/html',
  729. 'css' => 'text/css',
  730. 'js' => 'text/javascript',
  731. 'jpg' => 'image/jpeg',
  732. 'png' => 'image/png',
  733. 'gif' => 'image/gif',
  734. 'json' => 'application/json'
  735. );
  736. $ctype = a::get($args, 0, c::get('content_type', 'text/html'));
  737. $ctype = a::get($ctypes, $ctype, $ctype);
  738. $charset = a::get($args, 1, c::get('charset', 'utf-8'));
  739. header('Content-type: ' . $ctype . '; charset=' . $charset);
  740. }
  741. }
  742. /**
  743. *
  744. * Cookie
  745. *
  746. * This class makes cookie handling easy
  747. *
  748. * @package Kirby
  749. */
  750. class cookie {
  751. /**
  752. * Set a new cookie
  753. *
  754. * @param string $key The name of the cookie
  755. * @param string $value The cookie content
  756. * @param int $expires The number of seconds until the cookie expires
  757. * @param string $domain The domain to set this cookie for.
  758. * @return boolean true: the cookie has been created, false: cookie creation failed
  759. */
  760. static function set($key, $value, $expires=3600, $domain='/') {
  761. if(is_array($value)) $value = a::json($value);
  762. $_COOKIE[$key] = $value;
  763. return @setcookie($key, $value, time()+$expires, $domain);
  764. }
  765. /**
  766. * Get a cookie value
  767. *
  768. * @param string $key The name of the cookie
  769. * @param string $default The default value, which should be returned if the cookie has not been found
  770. * @return mixed The found value
  771. */
  772. static function get($key, $default=null) {
  773. return a::get($_COOKIE, $key, $default);
  774. }
  775. /**
  776. * Remove a cookie
  777. *
  778. * @param string $key The name of the cookie
  779. * @param string $domain The domain of the cookie
  780. * @return mixed true: the cookie has been removed, false: the cookie could not be removed
  781. */
  782. static function remove($key, $domain='/') {
  783. $_COOKIE[$key] = false;
  784. return @setcookie($key, false, time()-3600, $domain);
  785. }
  786. }
  787. /**
  788. *
  789. * Database
  790. *
  791. * Database handling sucks - not with this class :)
  792. *
  793. * Configure your database connection like this:
  794. *
  795. * <code>
  796. * c::set('db.host', 'localhost');
  797. * c::set('db.user', 'root');
  798. * c::set('db.password', '');
  799. * c::set('db.name', 'mydb');
  800. * c::set('db.prefix', '');
  801. * </code>
  802. *
  803. * @package Kirby
  804. */
  805. class db {
  806. /**
  807. * Traces all db queries
  808. *
  809. * @var array
  810. */
  811. public static $trace = array();
  812. /**
  813. * The connection resource
  814. *
  815. * @var mixed
  816. */
  817. private static $connection = false;
  818. /**
  819. * The selected database
  820. *
  821. * @var string
  822. */
  823. private static $database = false;
  824. /**
  825. * The used charset
  826. * Default is "utf8"
  827. *
  828. * @var string
  829. */
  830. private static $charset = false;
  831. /**
  832. * The last used query
  833. *
  834. * @var string
  835. */
  836. private static $last_query = false;
  837. /**
  838. * The number of affected rows
  839. * for the last query
  840. *
  841. * @var int
  842. */
  843. private static $affected = 0;
  844. /**
  845. * The core connection method
  846. * Tries to connect to the server
  847. * Selects the database and sets the charset
  848. *
  849. * It will only connect once and return
  850. * that same connection for all following queries
  851. *
  852. * @return mixed
  853. */
  854. static function connect() {
  855. $connection = self::connection();
  856. $args = func_get_args();
  857. $host = a::get($args, 0, c::get('db.host', 'localhost'));
  858. $user = a::get($args, 1, c::get('db.user', 'root'));
  859. $password = a::get($args, 2, c::get('db.password'));
  860. $database = a::get($args, 3, c::get('db.name'));
  861. $charset = a::get($args, 4, c::get('db.charset', 'utf8'));
  862. // don't connect again if it's already done
  863. $connection = (!$connection) ? @mysql_connect($host, $user, $password) : $connection;
  864. // react on connection failures
  865. if(!$connection) return self::error(l::get('db.errors.connect', 'Database connection failed'), true);
  866. self::$connection = $connection;
  867. // select the database
  868. $database = self::database($database);
  869. if(error($database)) return $database;
  870. // set the right charset
  871. $charset = self::charset($charset);
  872. if(error($charset)) return $charset;
  873. return $connection;
  874. }
  875. /**
  876. * Returns the current connection or false
  877. *
  878. * @return mixed
  879. */
  880. static function connection() {
  881. return (is_resource(self::$connection)) ? self::$connection : false;
  882. }
  883. /**
  884. * Disconnects from the server
  885. *
  886. * @return boolean
  887. */
  888. static function disconnect() {
  889. if(!c::get('db.disconnect')) return false;
  890. $connection = self::connection();
  891. if(!$connection) return false;
  892. // kill the connection
  893. $disconnect = @mysql_close($connection);
  894. self::$connection = false;
  895. if(!$disconnect) return self::error(l::get('db.errors.disconnect', 'Disconnecting database failed'));
  896. return true;
  897. }
  898. /**
  899. * Selects a database
  900. *
  901. * @param string $database
  902. * @return mixed
  903. */
  904. static function database($database) {
  905. if(!$database) return self::error(l::get('db.errors.missing_db_name', 'Please provide a database name'), true);
  906. // check if there is a selected database
  907. if(self::$database == $database) return true;
  908. // select a new database
  909. $select = @mysql_select_db($database, self::connection());
  910. if(!$select) return self::error(l::get('db.errors.missing_db', 'Selecting database failed'), true);
  911. self::$database = $database;
  912. return $database;
  913. }
  914. /**
  915. * Sets the charset for all queries
  916. * The default and recommended charset is utf8
  917. *
  918. * @param string $charset
  919. * @return mixed
  920. */
  921. static function charset($charset='utf8') {
  922. // check if there is a assigned charset and compare it
  923. if(self::$charset == $charset) return true;
  924. // set the new charset
  925. $set = @mysql_query('SET NAMES ' . $charset);
  926. if(!$set) return self::error(l::get('db.errors.setting_charset_failed', 'Setting database charset failed'));
  927. // save the new charset to the globals
  928. self::$charset = $charset;
  929. return $charset;
  930. }
  931. /**
  932. * Runs a MySQL query.
  933. * You can use any valid MySQL query here.
  934. * This is also the fallback method if you
  935. * can't use one of the provided shortcut methods
  936. * from this class.
  937. *
  938. * @param string $sql The sql query
  939. * @param boolean $fetch True: apply db::fetch to the result, false: go without db::fetch
  940. * @return mixed
  941. */
  942. static function query($sql, $fetch=true) {
  943. $connection = self::connect();
  944. if(error($connection)) return $connection;
  945. // save the query
  946. self::$last_query = $sql;
  947. // execute the query
  948. $result = @mysql_query($sql, $connection);
  949. self::$affected = @mysql_affected_rows();
  950. self::$trace[] = $sql;
  951. if(!$result) return self::error(l::get('db.errors.query_failed', 'The database query failed'));
  952. if(!$fetch) return $result;
  953. $array = array();
  954. while($r = self::fetch($result)) array_push($array, $r);
  955. return $array;
  956. }
  957. /**
  958. * Executes a MySQL query without result set.
  959. * This is used for queries like update, delete or insert
  960. *
  961. * @param string $sql The sql query
  962. * @return mixed
  963. */
  964. static function execute($sql) {
  965. $connection = self::connect();
  966. if(error($connection)) return $connection;
  967. // save the query
  968. self::$last_query = $sql;
  969. // execute the query
  970. $execute = @mysql_query($sql, $connection);
  971. self::$affected = @mysql_affected_rows();
  972. self::$trace[] = $sql;
  973. if(!$execute) return self::error(l::get('db.errors.query_failed', 'The database query failed'));
  974. $last_id = self::last_id();
  975. return ($last_id === false) ? self::$affected : self::last_id();
  976. }
  977. /**
  978. * Returns the number of affected rows for the last query
  979. *
  980. * @return int
  981. */
  982. static function affected() {
  983. return self::$affected;
  984. }
  985. /**
  986. * Returns the last returned insert id
  987. *
  988. * @return int
  989. */
  990. static function last_id() {
  991. $connection = self::connection();
  992. return @mysql_insert_id($connection);
  993. }
  994. /**
  995. * Shortcut for mysql_fetch_array
  996. *
  997. * @param resource $result the unfetched result from db::query()
  998. * @param const $type PHP flag for mysql_fetch_array
  999. * @return array The key/value result array
  1000. */
  1001. static function fetch($result, $type=MYSQL_ASSOC) {
  1002. if(!$result) return array();
  1003. return @mysql_fetch_array($result, $type);
  1004. }
  1005. /**
  1006. * Returns an array of fields in a given table
  1007. *
  1008. * @param string $table The table name
  1009. * @return array The array of field names
  1010. */
  1011. static function fields($table) {
  1012. $connection = self::connect();
  1013. if(error($connection)) return $connection;
  1014. $fields = @mysql_list_fields(self::$database, self::prefix($table), $connection);
  1015. if(!$fields) return self::error(l::get('db.errors.listing_fields_failed', 'Listing fields failed'));
  1016. $output = array();
  1017. $count = @mysql_num_fields($fields);
  1018. for($x=0; $x<$count; $x++) {
  1019. $output[] = @mysql_field_name($fields, $x);
  1020. }
  1021. return $output;
  1022. }
  1023. /**
  1024. * Runs a INSERT query
  1025. *
  1026. * @param string $table The table name
  1027. * @param mixed $input Either a key/value array or a valid MySQL insert string
  1028. * @param boolean $ignore Set this to true to ignore duplicates
  1029. * @return mixed The last inserted id if everything went fine or an error response.
  1030. */
  1031. static function insert($table, $input, $ignore=false) {
  1032. $ignore = ($ignore) ? ' IGNORE' : '';
  1033. return self::execute('INSERT' . ($ignore) . ' INTO ' . self::prefix($table) . ' SET ' . self::values($input));
  1034. }
  1035. /**
  1036. * Runs a INSERT query with values
  1037. *
  1038. * @param string $table The table name
  1039. * @param array $fields an array of field names
  1040. * @param array $values an array of array of keys and values.
  1041. * @return mixed The last inserted id if everything went fine or an error response.
  1042. */
  1043. static function insert_all($table, $fields, $values) {
  1044. $query = 'INSERT INTO ' . self::prefix($table) . ' (' . implode(',', $fields) . ') VALUES ';
  1045. $rows = array();
  1046. foreach($values AS $v) {
  1047. $str = '(\'';
  1048. $sep = '';
  1049. foreach($v AS $input) {
  1050. $str .= $sep . db::escape($input);
  1051. $sep = "','";
  1052. }
  1053. $str .= '\')';
  1054. $rows[] = $str;
  1055. }
  1056. $query .= implode(',', $rows);
  1057. return db::execute($query);
  1058. }
  1059. /**
  1060. * Runs a REPLACE query
  1061. *
  1062. * @param string $table The table name
  1063. * @param mixed $input Either a key/value array or a valid MySQL insert string
  1064. * @return mixed The last inserted id if everything went fine or an error response.
  1065. */
  1066. static function replace($table, $input) {
  1067. return self::execute('REPLACE INTO ' . self::prefix($table) . ' SET ' . self::values($input));
  1068. }
  1069. /**
  1070. * Runs an UPDATE query
  1071. *
  1072. * @param string $table The table name
  1073. * @param mixed $input Either a key/value array or a valid MySQL insert string
  1074. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1075. * @return mixed The number of affected rows or an error response
  1076. */
  1077. static function update($table, $input, $where) {
  1078. return self::execute('UPDATE ' . self::prefix($table) . ' SET ' . self::values($input) . ' WHERE ' . self::where($where));
  1079. }
  1080. /**
  1081. * Runs a DELETE query
  1082. *
  1083. * @param string $table The table name
  1084. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1085. * @return mixed The number of affected rows or an error response
  1086. */
  1087. static function delete($table, $where='') {
  1088. $sql = 'DELETE FROM ' . self::prefix($table);
  1089. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1090. return self::execute($sql);
  1091. }
  1092. /**
  1093. * Returns multiple rows from a table
  1094. *
  1095. * @param string $table The table name
  1096. * @param mixed $select Either an array of fields or a MySQL string of fields
  1097. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1098. * @param string $order Order clause without the order keyword. ie: "added desc"
  1099. * @param int $page a page number
  1100. * @param int $limit a number for rows to return
  1101. * @param boolean $fetch true: apply db::fetch(), false: don't apply db::fetch()
  1102. * @return mixed
  1103. */
  1104. static function select($table, $select='*', $where=null, $order=null, $page=null, $limit=null, $fetch=true) {
  1105. if($limit === 0) return array();
  1106. if(is_array($select)) $select = self::select_clause($select);
  1107. $sql = 'SELECT ' . $select . ' FROM ' . self::prefix($table);
  1108. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1109. if(!empty($order)) $sql .= ' ORDER BY ' . $order;
  1110. if($page !== null && $limit !== null) $sql .= ' LIMIT ' . $page . ',' . $limit;
  1111. return self::query($sql, $fetch);
  1112. }
  1113. /**
  1114. * Returns a single row from a table
  1115. *
  1116. * @param string $table The table name
  1117. * @param mixed $select Either an array of fields or a MySQL string of fields
  1118. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1119. * @param string $order Order clause without the order keyword. ie: "added desc"
  1120. * @return mixed
  1121. */
  1122. static function row($table, $select='*', $where=null, $order=null) {
  1123. $result = self::select($table, $select, $where, $order, 0,1, false);
  1124. return self::fetch($result);
  1125. }
  1126. /**
  1127. * Returns all values from single column of a table
  1128. *
  1129. * @param string $table The table name
  1130. * @param string $column The name of the column
  1131. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1132. * @param string $order Order clause without the order keyword. ie: "added desc"
  1133. * @param int $page a page number
  1134. * @param int $limit a number for rows to return
  1135. * @return mixed
  1136. */
  1137. static function column($table, $column, $where=null, $order=null, $page=null, $limit=null) {
  1138. $result = self::select($table, $column, $where, $order, $page, $limit, false);
  1139. $array = array();
  1140. while($r = self::fetch($result)) array_push($array, a::get($r, $column));
  1141. return $array;
  1142. }
  1143. /**
  1144. * Returns a single field value from a table
  1145. *
  1146. * @param string $table The table name
  1147. * @param string $field The name of the field
  1148. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1149. * @param string $order Order clause without the order keyword. ie: "added desc"
  1150. * @return mixed
  1151. */
  1152. static function field($table, $field, $where=null, $order=null) {
  1153. $result = self::row($table, $field, $where, $order);
  1154. return a::get($result, $field);
  1155. }
  1156. /**
  1157. * Joins two tables and returns data from them
  1158. *
  1159. * @param string $table_1 The table name of the first table
  1160. * @param string $table_2 The table name of the second table
  1161. * @param string $on The MySQL ON clause without the ON keyword. ie: "user_id = comment_user"
  1162. * @param mixed $select Either an array of fields or a MySQL string of fields
  1163. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1164. * @param string $order Order clause without the order keyword. ie: "added desc"
  1165. * @param int $page a page number
  1166. * @param int $limit a number for rows to return
  1167. * @param string $type The join type (JOIN, LEFT, RIGHT, INNER)
  1168. * @return mixed
  1169. */
  1170. static function join($table_1, $table_2, $on, $select, $where=null, $order=null, $page=null, $limit=null, $type="JOIN") {
  1171. return self::select(
  1172. self::prefix($table_1) . ' ' . $type . ' ' .
  1173. self::prefix($table_2) . ' ON ' .
  1174. self::where($on),
  1175. $select,
  1176. self::where($where),
  1177. $order,
  1178. $page,
  1179. $limit
  1180. );
  1181. }
  1182. /**
  1183. * Runs a LEFT JOIN
  1184. *
  1185. * @param string $table_1 The table name of the first table
  1186. * @param string $table_2 The table name of the second table
  1187. * @param string $on The MySQL ON clause without the ON keyword. ie: "user_id = comment_user"
  1188. * @param mixed $select Either an array of fields or a MySQL string of fields
  1189. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1190. * @param string $order Order clause without the order keyword. ie: "added desc"
  1191. * @param int $page a page number
  1192. * @param int $limit a number for rows to return
  1193. * @return mixed
  1194. */
  1195. static function left_join($table_1, $table_2, $on, $select, $where=null, $order=null, $page=null, $limit=null) {
  1196. return self::join($table_1, $table_2, $on, $select, $where, $order, $page, $limit, 'LEFT JOIN');
  1197. }
  1198. /**
  1199. * Counts a number of rows in a table
  1200. *
  1201. * @param string $table The table name
  1202. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1203. * @return int
  1204. */
  1205. static function count($table, $where='') {
  1206. $result = self::row($table, 'count(*)', $where);
  1207. return ($result) ? a::get($result, 'count(*)') : 0;
  1208. }
  1209. /**
  1210. * Gets the minimum value in a column of a table
  1211. *
  1212. * @param string $table The table name
  1213. * @param string $column The name of the column
  1214. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1215. * @return mixed
  1216. */
  1217. static function min($table, $column, $where=null) {
  1218. $sql = 'SELECT MIN(' . $column . ') AS min FROM ' . self::prefix($table);
  1219. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1220. $result = self::query($sql, false);
  1221. $result = self::fetch($result);
  1222. return a::get($result, 'min', 1);
  1223. }
  1224. /**
  1225. * Gets the maximum value in a column of a table
  1226. *
  1227. * @param string $table The table name
  1228. * @param string $column The name of the column
  1229. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1230. * @return mixed
  1231. */
  1232. static function max($table, $column, $where=null) {
  1233. $sql = 'SELECT MAX(' . $column . ') AS max FROM ' . self::prefix($table);
  1234. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1235. $result = self::query($sql, false);
  1236. $result = self::fetch($result);
  1237. return a::get($result, 'max', 1);
  1238. }
  1239. /**
  1240. * Gets the sum of values in a column of a table
  1241. *
  1242. * @param string $table The table name
  1243. * @param string $column The name of the column
  1244. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1245. * @return mixed
  1246. */
  1247. static function sum($table, $column, $where=null) {
  1248. $sql = 'SELECT SUM(' . $column . ') AS sum FROM ' . self::prefix($table);
  1249. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1250. $result = self::query($sql, false);
  1251. $result = self::fetch($result);
  1252. return a::get($result, 'sum', 0);
  1253. }
  1254. /**
  1255. * Adds a prefix to a table name if set in c::set('db.prefix', 'myprefix_');
  1256. * This makes it possible to use table names in all methods without prefix
  1257. * and it will still be applied automatically.
  1258. *
  1259. * @param string $table The name of the table with or without prefix
  1260. * @return string The sanitized table name.
  1261. */
  1262. static function prefix($table) {
  1263. $prefix = c::get('db.prefix');
  1264. if(!$prefix) return $table;
  1265. return (!str::contains($table,$prefix)) ? $prefix . $table : $table;
  1266. }
  1267. /**
  1268. * Strips table specific column prefixes from the result array
  1269. *
  1270. * If you use column names like user_username, user_id, etc.
  1271. * use this method on the result array to strip user_ of all fields
  1272. *
  1273. * @param array $array The result array
  1274. * @return array The result array without those damn prefixes.
  1275. */
  1276. static function simple_fields($array) {
  1277. if(empty($array)) return false;
  1278. $output = array();
  1279. foreach($array AS $key => $value) {
  1280. $key = substr($key, strpos($key, '_')+1);
  1281. $output[$key] = $value;
  1282. }
  1283. return $output;
  1284. }
  1285. /**
  1286. * Makes it possible to use arrays for inputs instead of MySQL strings
  1287. *
  1288. * @param array $input
  1289. * @return string The final MySQL string, which will be used in the queries.
  1290. */
  1291. static function values($input) {
  1292. if(!is_array($input)) return $input;
  1293. $output = array();
  1294. foreach($input AS $key => $value) {
  1295. if($value === 'NOW()')
  1296. $output[] = $key . ' = NOW()';
  1297. elseif(is_array($value))
  1298. $output[] = $key . ' = \'' . a::json($value) . '\'';
  1299. else
  1300. $output[] = $key . ' = \'' . self::escape($value) . '\'';
  1301. }
  1302. return implode(', ', $output);
  1303. }
  1304. /**
  1305. * Escapes unwanted stuff in values like slashes, etc.
  1306. *
  1307. * @param string $value
  1308. * @return string Returns the escaped string
  1309. */
  1310. static function escape($value) {
  1311. $value = str::stripslashes($value);
  1312. return mysql_real_escape_string((string)$value, self::connect());
  1313. }
  1314. /**
  1315. * A simplifier to build search clauses
  1316. *
  1317. * @param string $search The search word
  1318. * @param array $fields An array of fields to search
  1319. * @param string $mode OR or AND
  1320. * @return string Returns the final where clause
  1321. */
  1322. static function search_clause($search, $fields, $mode='OR') {
  1323. if(empty($search)) return false;
  1324. $arr = array();
  1325. foreach($fields AS $f) {
  1326. array_push($arr, $f . ' LIKE \'%' . $search . '%\'');
  1327. //array_push($arr, $f . ' REGEXP "[[:<:]]' . db::escape($search) . '[[:>:]]"');
  1328. }
  1329. return '(' . implode(' ' . trim($mode) . ' ', $arr) . ')';
  1330. }
  1331. /**
  1332. * An easy method to build a part of the where clause to find stuff by its first character
  1333. *
  1334. * @param string $field The name of the field
  1335. * @param string $char The character to search for
  1336. * @return string Returns the where clause part
  1337. */
  1338. static function with($field, $char) {
  1339. return 'LOWER(SUBSTRING(' . $field . ',1,1)) = "' . db::escape($char) . '"';
  1340. }
  1341. /**
  1342. * Builds a select clause from a simple array
  1343. *
  1344. * @param array $field An array of field names
  1345. * @return string The MySQL string
  1346. */
  1347. static function select_clause($fields) {
  1348. return implode(', ', $fields);
  1349. }
  1350. /**
  1351. * A simplifier to build IN clauses
  1352. *
  1353. * @param array $array An array of fieldnames
  1354. * @return string The MySQL string for the where clause
  1355. */
  1356. static function in($array) {
  1357. return '\'' . implode('\',\'', $array) . '\'';
  1358. }
  1359. /**
  1360. * A handler to convert key/value arrays to an where clause
  1361. *
  1362. * @param array $array keys/values for the where clause
  1363. * @param string $method AND or OR
  1364. * @return string The MySQL string for the where clause
  1365. */
  1366. static function where($array, $method='AND') {
  1367. if(!is_array($array)) return $array;
  1368. $output = array();
  1369. foreach($array AS $field => $value) {
  1370. $output[] = $field . ' = \'' . self::escape($value) . '\'';
  1371. $separator = ' ' . $method . ' ';
  1372. }
  1373. return implode(' ' . $method . ' ', $output);
  1374. }
  1375. /**
  1376. * An internal error handler
  1377. *
  1378. * @param string $msg The error/success message to return
  1379. * @param boolean $exit die after this error?
  1380. * @return mixed
  1381. */
  1382. static function error($msg=null, $exit=false) {
  1383. $connection = self::connection();
  1384. $error = (mysql_error()) ? @mysql_error($connection) : false;
  1385. $number = (mysql_errno()) ? @mysql_errno($connection) : 0;
  1386. if(c::get('db.debugging')) {
  1387. if($error) $msg .= ' -> ' . $error . ' (' . $number . ')';
  1388. if(self::$last_query) $msg .= ' Query: ' . self::$last_query;
  1389. } else $msg .= ' - ' . l::get('db.errors.msg', 'This will be fixed soon!');
  1390. if($exit || c::get('db.debugging')) die($msg);
  1391. return array(
  1392. 'status' => 'error',
  1393. 'msg' => $msg
  1394. );
  1395. }
  1396. }
  1397. /**
  1398. *
  1399. * Directory
  1400. *
  1401. * This class makes it easy to create/edit/delete
  1402. * directories on the filesystem
  1403. *
  1404. * @package Kirby
  1405. */
  1406. class dir {
  1407. /**
  1408. * Creates a new directory
  1409. *
  1410. * @param string $dir The path for the new directory
  1411. * @return boolean True: the dir has been created, false: creating failed
  1412. */
  1413. static function make($dir) {
  1414. if(is_dir($dir)) return true;
  1415. if(!@mkdir($dir, 0755)) return false;
  1416. @chmod($dir, 0755);
  1417. return true;
  1418. }
  1419. /**
  1420. * Reads all files from a directory and returns them as an array.
  1421. * It skips unwanted invisible stuff.
  1422. *
  1423. * @param string $dir The path of directory
  1424. * @return mixed An array of filenames or false
  1425. */
  1426. static function read($dir) {
  1427. if(!is_dir($dir)) return false;
  1428. $skip = array('.', '..', '.DS_Store');
  1429. return array_diff(scandir($dir),$skip);
  1430. }
  1431. /**
  1432. * Reads a directory and returns a full set of info about it
  1433. *
  1434. * @param string $dir The path of directory
  1435. * @return mixed An info array or false
  1436. */
  1437. static function inspect($dir) {
  1438. if(!is_dir($dir)) return array();
  1439. $files = dir::read($dir);
  1440. $modified = filemtime($dir);
  1441. $data = array(
  1442. 'name' => basename($dir),
  1443. 'root' => $dir,
  1444. 'modified' => $modified,
  1445. 'files' => array(),
  1446. 'children' => array()
  1447. );
  1448. foreach($files AS $file) {
  1449. if(is_dir($dir . '/' . $file)) {
  1450. $data['children'][] = $file;
  1451. } else {
  1452. $data['files'][] = $file;
  1453. }
  1454. }
  1455. return $data;
  1456. }
  1457. /**
  1458. * Moves a directory to a new location
  1459. *
  1460. * @param string $old The current path of the directory
  1461. * @param string $new The desired path where the dir should be moved to
  1462. * @return boolean True: the directory has been moved, false: moving failed
  1463. */
  1464. static function move($old, $new) {
  1465. if(!is_dir($old)) return false;
  1466. return (@rename($old, $new) && is_dir($new)) ? true : false;
  1467. }
  1468. /**
  1469. * Deletes a directory
  1470. *
  1471. * @param string $dir The path of the directory
  1472. * @param boolean $keep If set to true, the directory will flushed but not removed.
  1473. * @return boolean True: the directory has been removed, false: removing failed
  1474. */
  1475. static function remove($dir, $keep=false) {
  1476. if(!is_dir($dir)) return false;
  1477. $handle = @opendir($dir);
  1478. $skip = array('.', '..');
  1479. if(!$handle) return false;
  1480. while($item = @readdir($handle)) {
  1481. if(is_dir($dir . '/' . $item) && !in_array($item, $skip)) {
  1482. self::remove($dir . '/' . $item);
  1483. } else if(!in_array($item, $skip)) {
  1484. @unlink($dir . '/' . $item);
  1485. }
  1486. }
  1487. @closedir($handle);
  1488. if(!$keep) return @rmdir($dir);
  1489. return true;
  1490. }
  1491. /**
  1492. * Flushes a directory
  1493. *
  1494. * @param string $dir The path of the directory
  1495. * @return boolean True: the directory has been flushed, false: flushing failed
  1496. */
  1497. static function clean($dir) {
  1498. return self::remove($dir, true);
  1499. }
  1500. /**
  1501. * Gets the size of the directory and all subfolders and files
  1502. *
  1503. * @param string $dir The path of the directory
  1504. * @param boolean $recursive
  1505. * @param boolean $nice returns the size in a human readable size
  1506. * @return mixed
  1507. */
  1508. static function size($path, $recursive=true, $nice=false) {
  1509. if(!file_exists($path)) return false;
  1510. if(is_file($path)) return self::size(

Large files files are truncated, but you can click here to view the full file