PageRenderTime 68ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/kirby/lib/kirby.php

https://github.com/jordanstephens/kirbycms
PHP | 3472 lines | 1402 code | 517 blank | 1553 comment | 256 complexity | abe9bf18ff915876ff532432f9b6ef25 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.95
  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 or 'natural' for natural sorting, which is not supported in PHP by sort flags
  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. // natural sorting
  365. if($method === 'natural') {
  366. natsort($helper);
  367. if($direction === SORT_DESC) $helper = array_reverse($helper);
  368. $result = array();
  369. foreach($helper as $key => $val) {
  370. $result[$key] = $array[$key];
  371. }
  372. return $result;
  373. } else {
  374. array_multisort($helper, $direction, $method, $array);
  375. return $array;
  376. }
  377. }
  378. }
  379. /**
  380. *
  381. * Browser
  382. *
  383. * Browser sniffing is bad - I know!
  384. * But sometimes this class is very helpful to
  385. * react on certain browsers and build browser-specific
  386. * css selectors for example. It's up to you to use it.
  387. *
  388. * @package Kirby
  389. */
  390. class browser {
  391. /**
  392. * The entire user agent string
  393. *
  394. * @var string
  395. */
  396. static public $ua = false;
  397. /**
  398. * The readable name of the browser
  399. * For example: "ie"
  400. *
  401. * @var string
  402. */
  403. static public $name = false;
  404. /**
  405. * The readable browser engine name
  406. * For example: "webkit"
  407. *
  408. * @var string
  409. */
  410. static public $engine = false;
  411. /**
  412. * The browser version number
  413. * For example: "3.6"
  414. *
  415. * @var string
  416. */
  417. static public $version = false;
  418. /**
  419. * The platform name
  420. * For example: "mac"
  421. *
  422. * @var string
  423. */
  424. static public $platform = false;
  425. /**
  426. * True or false if it is a mobile device or not
  427. *
  428. * @var boolean
  429. */
  430. static public $mobile = false;
  431. /**
  432. * True or false if it is an iOS device or not
  433. *
  434. * @var boolean
  435. */
  436. static public $ios = false;
  437. /**
  438. * True or false if it is an iPhone or not
  439. *
  440. * @var boolean
  441. */
  442. static public $iphone = false;
  443. /**
  444. * Returns the name of the browser
  445. *
  446. * @param string $ua The user agent string
  447. * @return string The browser name
  448. */
  449. static function name($ua=null) {
  450. self::detect($ua);
  451. return self::$name;
  452. }
  453. /**
  454. * Returns the browser engine
  455. *
  456. * @param string $ua The user agent string
  457. * @return string The browser engine
  458. */
  459. static function engine($ua=null) {
  460. self::detect($ua);
  461. return self::$engine;
  462. }
  463. /**
  464. * Returns the browser version
  465. *
  466. * @param string $ua The user agent string
  467. * @return string The browser version
  468. */
  469. static function version($ua=null) {
  470. self::detect($ua);
  471. return self::$version;
  472. }
  473. /**
  474. * Returns the platform
  475. *
  476. * @param string $ua The user agent string
  477. * @return string The platform name
  478. */
  479. static function platform($ua=null) {
  480. self::detect($ua);
  481. return self::$platform;
  482. }
  483. /**
  484. * Checks if the user agent string is from a mobile device
  485. *
  486. * @param string $ua The user agent string
  487. * @return boolean True: mobile device, false: not a mobile device
  488. */
  489. static function mobile($ua=null) {
  490. self::detect($ua);
  491. return self::$mobile;
  492. }
  493. /**
  494. * Checks if the user agent string is from an iPhone
  495. *
  496. * @param string $ua The user agent string
  497. * @return boolean True: iPhone, false: not an iPhone
  498. */
  499. static function iphone($ua=null) {
  500. self::detect($ua);
  501. return self::$iphone;
  502. }
  503. /**
  504. * Checks if the user agent string is from an iOS device
  505. *
  506. * @param string $ua The user agent string
  507. * @return boolean True: iOS device, false: not an iOS device
  508. */
  509. static function ios($ua=null) {
  510. self::detect($ua);
  511. return self::$ios;
  512. }
  513. /**
  514. * Returns a browser-specific css selector string
  515. *
  516. * @param string $ua The user agent string
  517. * @param boolean $array True: return an array, false: return a string
  518. * @return mixed
  519. */
  520. static function css($ua=null, $array=false) {
  521. self::detect($ua);
  522. $css[] = self::$engine;
  523. $css[] = self::$name;
  524. if(self::$version) $css[] = self::$name . str_replace('.', '_', self::$version);
  525. $css[] = self::$platform;
  526. return ($array) ? $css : implode(' ', $css);
  527. }
  528. /**
  529. * The core detection method, which parses the user agent string
  530. *
  531. * @todo add new browser versions
  532. * @param string $ua The user agent string
  533. * @return array An array with all parsed info
  534. */
  535. static function detect($ua=null) {
  536. $ua = ($ua) ? str::lower($ua) : str::lower(server::get('http_user_agent'));
  537. // don't do the detection twice
  538. if(self::$ua == $ua) return array(
  539. 'name' => self::$name,
  540. 'engine' => self::$engine,
  541. 'version' => self::$version,
  542. 'platform' => self::$platform,
  543. 'agent' => self::$ua,
  544. 'mobile' => self::$mobile,
  545. 'iphone' => self::$iphone,
  546. 'ios' => self::$ios,
  547. );
  548. self::$ua = $ua;
  549. self::$name = false;
  550. self::$engine = false;
  551. self::$version = false;
  552. self::$platform = false;
  553. // browser
  554. if(!preg_match('/opera|webtv/i', self::$ua) && preg_match('/msie\s(\d)/', self::$ua, $array)) {
  555. self::$version = $array[1];
  556. self::$name = 'ie';
  557. self::$engine = 'trident';
  558. } else if(strstr(self::$ua, 'firefox/3.6')) {
  559. self::$version = 3.6;
  560. self::$name = 'fx';
  561. self::$engine = 'gecko';
  562. } else if (strstr(self::$ua, 'firefox/3.5')) {
  563. self::$version = 3.5;
  564. self::$name = 'fx';
  565. self::$engine = 'gecko';
  566. } else if(preg_match('/firefox\/(\d+)/i', self::$ua, $array)) {
  567. self::$version = $array[1];
  568. self::$name = 'fx';
  569. self::$engine = 'gecko';
  570. } else if(preg_match('/opera(\s|\/)(\d+)/', self::$ua, $array)) {
  571. self::$engine = 'presto';
  572. self::$name = 'opera';
  573. self::$version = $array[2];
  574. } else if(strstr(self::$ua, 'konqueror')) {
  575. self::$name = 'konqueror';
  576. self::$engine = 'webkit';
  577. } else if(strstr(self::$ua, 'iron')) {
  578. self::$name = 'iron';
  579. self::$engine = 'webkit';
  580. } else if(strstr(self::$ua, 'chrome')) {
  581. self::$name = 'chrome';
  582. self::$engine = 'webkit';
  583. if(preg_match('/chrome\/(\d+)/i', self::$ua, $array)) { self::$version = $array[1]; }
  584. } else if(strstr(self::$ua, 'applewebkit/')) {
  585. self::$name = 'safari';
  586. self::$engine = 'webkit';
  587. if(preg_match('/version\/(\d+)/i', self::$ua, $array)) { self::$version = $array[1]; }
  588. } else if(strstr(self::$ua, 'mozilla/')) {
  589. self::$engine = 'gecko';
  590. self::$name = 'fx';
  591. }
  592. // platform
  593. if(strstr(self::$ua, 'j2me')) {
  594. self::$platform = 'mobile';
  595. } else if(strstr(self::$ua, 'iphone')) {
  596. self::$platform = 'iphone';
  597. } else if(strstr(self::$ua, 'ipod')) {
  598. self::$platform = 'ipod';
  599. } else if(strstr(self::$ua, 'ipad')) {
  600. self::$platform = 'ipad';
  601. } else if(strstr(self::$ua, 'mac')) {
  602. self::$platform = 'mac';
  603. } else if(strstr(self::$ua, 'darwin')) {
  604. self::$platform = 'mac';
  605. } else if(strstr(self::$ua, 'webtv')) {
  606. self::$platform = 'webtv';
  607. } else if(strstr(self::$ua, 'win')) {
  608. self::$platform = 'win';
  609. } else if(strstr(self::$ua, 'freebsd')) {
  610. self::$platform = 'freebsd';
  611. } else if(strstr(self::$ua, 'x11') || strstr(self::$ua, 'linux')) {
  612. self::$platform = 'linux';
  613. }
  614. self::$mobile = (self::$platform == 'mobile') ? true : false;
  615. self::$iphone = (in_array(self::$platform, array('ipod', 'iphone'))) ? true : false;
  616. self::$ios = (in_array(self::$platform, array('ipod', 'iphone', 'ipad'))) ? true : false;
  617. return array(
  618. 'name' => self::$name,
  619. 'engine' => self::$engine,
  620. 'version' => self::$version,
  621. 'platform' => self::$platform,
  622. 'agent' => self::$ua,
  623. 'mobile' => self::$mobile,
  624. 'iphone' => self::$iphone,
  625. 'ios' => self::$ios,
  626. );
  627. }
  628. }
  629. /**
  630. *
  631. * Config
  632. *
  633. * This is the core class to handle
  634. * configuration values/constants.
  635. *
  636. * @package Kirby
  637. */
  638. class c {
  639. /**
  640. * The static config array
  641. * It contains all config values
  642. *
  643. * @var array
  644. */
  645. private static $config = array();
  646. /**
  647. * Gets a config value by key
  648. *
  649. * @param string $key The key to look for. Pass false to get the entire config array
  650. * @param mixed $default The default value, which will be returned if the key has not been found
  651. * @return mixed The found config value
  652. */
  653. static function get($key=null, $default=null) {
  654. if(empty($key)) return self::$config;
  655. return a::get(self::$config, $key, $default);
  656. }
  657. /**
  658. * Sets a config value by key
  659. *
  660. * @param string $key The key to define
  661. * @param mixed $value The value for the passed key
  662. */
  663. static function set($key, $value=null) {
  664. if(is_array($key)) {
  665. // set all new values
  666. self::$config = array_merge(self::$config, $key);
  667. } else {
  668. self::$config[$key] = $value;
  669. }
  670. }
  671. /**
  672. * Loads an additional config file
  673. * Returns the entire configuration array
  674. *
  675. * @param string $file The path to the config file
  676. * @return array The entire config array
  677. */
  678. static function load($file) {
  679. if(file_exists($file)) require_once($file);
  680. return c::get();
  681. }
  682. }
  683. /**
  684. *
  685. * Content
  686. *
  687. * This class handles output buffering,
  688. * content loading and setting content type headers.
  689. *
  690. * @package Kirby
  691. */
  692. class content {
  693. /**
  694. * Starts the output buffer
  695. *
  696. */
  697. static function start() {
  698. ob_start();
  699. }
  700. /**
  701. * Stops the output buffer
  702. * and flush the content or return it.
  703. *
  704. * @param boolean $return Pass true to return the content instead of flushing it
  705. * @return mixed
  706. */
  707. static function end($return=false) {
  708. if($return) {
  709. $content = ob_get_contents();
  710. ob_end_clean();
  711. return $content;
  712. }
  713. ob_end_flush();
  714. }
  715. /**
  716. * Loads content from a passed file
  717. *
  718. * @param string $file The path to the file
  719. * @param boolean $return True: return the content of the file, false: echo the content
  720. * @return mixed
  721. */
  722. static function load($file, $return=true) {
  723. self::start();
  724. require_once($file);
  725. $content = self::end(true);
  726. if($return) return $content;
  727. echo $content;
  728. }
  729. /**
  730. * Simplifies setting content type headers
  731. *
  732. * @param string $ctype The shortcut for the content type. See the keys of the $ctypes array for all available shortcuts
  733. * @param string $charset The charset definition for the content type header. Default is "utf-8"
  734. */
  735. static function type() {
  736. $args = func_get_args();
  737. // shortcuts for content types
  738. $ctypes = array(
  739. 'html' => 'text/html',
  740. 'css' => 'text/css',
  741. 'js' => 'text/javascript',
  742. 'jpg' => 'image/jpeg',
  743. 'png' => 'image/png',
  744. 'gif' => 'image/gif',
  745. 'json' => 'application/json'
  746. );
  747. $ctype = a::get($args, 0, c::get('content_type', 'text/html'));
  748. $ctype = a::get($ctypes, $ctype, $ctype);
  749. $charset = a::get($args, 1, c::get('charset', 'utf-8'));
  750. header('Content-type: ' . $ctype . '; charset=' . $charset);
  751. }
  752. }
  753. /**
  754. *
  755. * Cookie
  756. *
  757. * This class makes cookie handling easy
  758. *
  759. * @package Kirby
  760. */
  761. class cookie {
  762. /**
  763. * Set a new cookie
  764. *
  765. * @param string $key The name of the cookie
  766. * @param string $value The cookie content
  767. * @param int $expires The number of seconds until the cookie expires
  768. * @param string $domain The domain to set this cookie for.
  769. * @return boolean true: the cookie has been created, false: cookie creation failed
  770. */
  771. static function set($key, $value, $expires=3600, $domain='/') {
  772. if(is_array($value)) $value = a::json($value);
  773. $_COOKIE[$key] = $value;
  774. return @setcookie($key, $value, time()+$expires, $domain);
  775. }
  776. /**
  777. * Get a cookie value
  778. *
  779. * @param string $key The name of the cookie
  780. * @param string $default The default value, which should be returned if the cookie has not been found
  781. * @return mixed The found value
  782. */
  783. static function get($key, $default=null) {
  784. return a::get($_COOKIE, $key, $default);
  785. }
  786. /**
  787. * Remove a cookie
  788. *
  789. * @param string $key The name of the cookie
  790. * @param string $domain The domain of the cookie
  791. * @return mixed true: the cookie has been removed, false: the cookie could not be removed
  792. */
  793. static function remove($key, $domain='/') {
  794. $_COOKIE[$key] = false;
  795. return @setcookie($key, false, time()-3600, $domain);
  796. }
  797. }
  798. /**
  799. *
  800. * Database
  801. *
  802. * Database handling sucks - not with this class :)
  803. *
  804. * Configure your database connection like this:
  805. *
  806. * <code>
  807. * c::set('db.host', 'localhost');
  808. * c::set('db.user', 'root');
  809. * c::set('db.password', '');
  810. * c::set('db.name', 'mydb');
  811. * c::set('db.prefix', '');
  812. * </code>
  813. *
  814. * @package Kirby
  815. */
  816. class db {
  817. /**
  818. * Traces all db queries
  819. *
  820. * @var array
  821. */
  822. public static $trace = array();
  823. /**
  824. * The connection resource
  825. *
  826. * @var mixed
  827. */
  828. private static $connection = false;
  829. /**
  830. * The selected database
  831. *
  832. * @var string
  833. */
  834. private static $database = false;
  835. /**
  836. * The used charset
  837. * Default is "utf8"
  838. *
  839. * @var string
  840. */
  841. private static $charset = false;
  842. /**
  843. * The last used query
  844. *
  845. * @var string
  846. */
  847. private static $last_query = false;
  848. /**
  849. * The number of affected rows
  850. * for the last query
  851. *
  852. * @var int
  853. */
  854. private static $affected = 0;
  855. /**
  856. * The core connection method
  857. * Tries to connect to the server
  858. * Selects the database and sets the charset
  859. *
  860. * It will only connect once and return
  861. * that same connection for all following queries
  862. *
  863. * @return mixed
  864. */
  865. static function connect() {
  866. $connection = self::connection();
  867. $args = func_get_args();
  868. $host = a::get($args, 0, c::get('db.host', 'localhost'));
  869. $user = a::get($args, 1, c::get('db.user', 'root'));
  870. $password = a::get($args, 2, c::get('db.password'));
  871. $database = a::get($args, 3, c::get('db.name'));
  872. $charset = a::get($args, 4, c::get('db.charset', 'utf8'));
  873. // don't connect again if it's already done
  874. $connection = (!$connection) ? @mysql_connect($host, $user, $password) : $connection;
  875. // react on connection failures
  876. if(!$connection) return self::error(l::get('db.errors.connect', 'Database connection failed'), true);
  877. self::$connection = $connection;
  878. // select the database
  879. $database = self::database($database);
  880. if(error($database)) return $database;
  881. // set the right charset
  882. $charset = self::charset($charset);
  883. if(error($charset)) return $charset;
  884. return $connection;
  885. }
  886. /**
  887. * Returns the current connection or false
  888. *
  889. * @return mixed
  890. */
  891. static function connection() {
  892. return (is_resource(self::$connection)) ? self::$connection : false;
  893. }
  894. /**
  895. * Disconnects from the server
  896. *
  897. * @return boolean
  898. */
  899. static function disconnect() {
  900. if(!c::get('db.disconnect')) return false;
  901. $connection = self::connection();
  902. if(!$connection) return false;
  903. // kill the connection
  904. $disconnect = @mysql_close($connection);
  905. self::$connection = false;
  906. if(!$disconnect) return self::error(l::get('db.errors.disconnect', 'Disconnecting database failed'));
  907. return true;
  908. }
  909. /**
  910. * Selects a database
  911. *
  912. * @param string $database
  913. * @return mixed
  914. */
  915. static function database($database) {
  916. if(!$database) return self::error(l::get('db.errors.missing_db_name', 'Please provide a database name'), true);
  917. // check if there is a selected database
  918. if(self::$database == $database) return true;
  919. // select a new database
  920. $select = @mysql_select_db($database, self::connection());
  921. if(!$select) return self::error(l::get('db.errors.missing_db', 'Selecting database failed'), true);
  922. self::$database = $database;
  923. return $database;
  924. }
  925. /**
  926. * Sets the charset for all queries
  927. * The default and recommended charset is utf8
  928. *
  929. * @param string $charset
  930. * @return mixed
  931. */
  932. static function charset($charset='utf8') {
  933. // check if there is a assigned charset and compare it
  934. if(self::$charset == $charset) return true;
  935. // set the new charset
  936. $set = @mysql_query('SET NAMES ' . $charset);
  937. if(!$set) return self::error(l::get('db.errors.setting_charset_failed', 'Setting database charset failed'));
  938. // save the new charset to the globals
  939. self::$charset = $charset;
  940. return $charset;
  941. }
  942. /**
  943. * Runs a MySQL query.
  944. * You can use any valid MySQL query here.
  945. * This is also the fallback method if you
  946. * can't use one of the provided shortcut methods
  947. * from this class.
  948. *
  949. * @param string $sql The sql query
  950. * @param boolean $fetch True: apply db::fetch to the result, false: go without db::fetch
  951. * @return mixed
  952. */
  953. static function query($sql, $fetch=true) {
  954. $connection = self::connect();
  955. if(error($connection)) return $connection;
  956. // save the query
  957. self::$last_query = $sql;
  958. // execute the query
  959. $result = @mysql_query($sql, $connection);
  960. self::$affected = @mysql_affected_rows();
  961. self::$trace[] = $sql;
  962. if(!$result) return self::error(l::get('db.errors.query_failed', 'The database query failed'));
  963. if(!$fetch) return $result;
  964. $array = array();
  965. while($r = self::fetch($result)) array_push($array, $r);
  966. return $array;
  967. }
  968. /**
  969. * Executes a MySQL query without result set.
  970. * This is used for queries like update, delete or insert
  971. *
  972. * @param string $sql The sql query
  973. * @return mixed
  974. */
  975. static function execute($sql) {
  976. $connection = self::connect();
  977. if(error($connection)) return $connection;
  978. // save the query
  979. self::$last_query = $sql;
  980. // execute the query
  981. $execute = @mysql_query($sql, $connection);
  982. self::$affected = @mysql_affected_rows();
  983. self::$trace[] = $sql;
  984. if(!$execute) return self::error(l::get('db.errors.query_failed', 'The database query failed'));
  985. $last_id = self::last_id();
  986. return ($last_id === false) ? self::$affected : self::last_id();
  987. }
  988. /**
  989. * Returns the number of affected rows for the last query
  990. *
  991. * @return int
  992. */
  993. static function affected() {
  994. return self::$affected;
  995. }
  996. /**
  997. * Returns the last returned insert id
  998. *
  999. * @return int
  1000. */
  1001. static function last_id() {
  1002. $connection = self::connection();
  1003. return @mysql_insert_id($connection);
  1004. }
  1005. /**
  1006. * Shortcut for mysql_fetch_array
  1007. *
  1008. * @param resource $result the unfetched result from db::query()
  1009. * @param const $type PHP flag for mysql_fetch_array
  1010. * @return array The key/value result array
  1011. */
  1012. static function fetch($result, $type=MYSQL_ASSOC) {
  1013. if(!$result) return array();
  1014. return @mysql_fetch_array($result, $type);
  1015. }
  1016. /**
  1017. * Returns an array of fields in a given table
  1018. *
  1019. * @param string $table The table name
  1020. * @return array The array of field names
  1021. */
  1022. static function fields($table) {
  1023. $connection = self::connect();
  1024. if(error($connection)) return $connection;
  1025. $fields = @mysql_list_fields(self::$database, self::prefix($table), $connection);
  1026. if(!$fields) return self::error(l::get('db.errors.listing_fields_failed', 'Listing fields failed'));
  1027. $output = array();
  1028. $count = @mysql_num_fields($fields);
  1029. for($x=0; $x<$count; $x++) {
  1030. $output[] = @mysql_field_name($fields, $x);
  1031. }
  1032. return $output;
  1033. }
  1034. /**
  1035. * Runs a INSERT query
  1036. *
  1037. * @param string $table The table name
  1038. * @param mixed $input Either a key/value array or a valid MySQL insert string
  1039. * @param boolean $ignore Set this to true to ignore duplicates
  1040. * @return mixed The last inserted id if everything went fine or an error response.
  1041. */
  1042. static function insert($table, $input, $ignore=false) {
  1043. $ignore = ($ignore) ? ' IGNORE' : '';
  1044. return self::execute('INSERT' . ($ignore) . ' INTO ' . self::prefix($table) . ' SET ' . self::values($input));
  1045. }
  1046. /**
  1047. * Runs a INSERT query with values
  1048. *
  1049. * @param string $table The table name
  1050. * @param array $fields an array of field names
  1051. * @param array $values an array of array of keys and values.
  1052. * @return mixed The last inserted id if everything went fine or an error response.
  1053. */
  1054. static function insert_all($table, $fields, $values) {
  1055. $query = 'INSERT INTO ' . self::prefix($table) . ' (' . implode(',', $fields) . ') VALUES ';
  1056. $rows = array();
  1057. foreach($values AS $v) {
  1058. $str = '(\'';
  1059. $sep = '';
  1060. foreach($v AS $input) {
  1061. $str .= $sep . db::escape($input);
  1062. $sep = "','";
  1063. }
  1064. $str .= '\')';
  1065. $rows[] = $str;
  1066. }
  1067. $query .= implode(',', $rows);
  1068. return db::execute($query);
  1069. }
  1070. /**
  1071. * Runs a REPLACE query
  1072. *
  1073. * @param string $table The table name
  1074. * @param mixed $input Either a key/value array or a valid MySQL insert string
  1075. * @return mixed The last inserted id if everything went fine or an error response.
  1076. */
  1077. static function replace($table, $input) {
  1078. return self::execute('REPLACE INTO ' . self::prefix($table) . ' SET ' . self::values($input));
  1079. }
  1080. /**
  1081. * Runs an UPDATE query
  1082. *
  1083. * @param string $table The table name
  1084. * @param mixed $input Either a key/value array or a valid MySQL insert string
  1085. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1086. * @return mixed The number of affected rows or an error response
  1087. */
  1088. static function update($table, $input, $where) {
  1089. return self::execute('UPDATE ' . self::prefix($table) . ' SET ' . self::values($input) . ' WHERE ' . self::where($where));
  1090. }
  1091. /**
  1092. * Runs a DELETE query
  1093. *
  1094. * @param string $table The table name
  1095. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1096. * @return mixed The number of affected rows or an error response
  1097. */
  1098. static function delete($table, $where='') {
  1099. $sql = 'DELETE FROM ' . self::prefix($table);
  1100. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1101. return self::execute($sql);
  1102. }
  1103. /**
  1104. * Returns multiple rows from a table
  1105. *
  1106. * @param string $table The table name
  1107. * @param mixed $select Either an array of fields or a MySQL string of fields
  1108. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1109. * @param string $order Order clause without the order keyword. ie: "added desc"
  1110. * @param int $page a page number
  1111. * @param int $limit a number for rows to return
  1112. * @param boolean $fetch true: apply db::fetch(), false: don't apply db::fetch()
  1113. * @return mixed
  1114. */
  1115. static function select($table, $select='*', $where=null, $order=null, $page=null, $limit=null, $fetch=true) {
  1116. if($limit === 0) return array();
  1117. if(is_array($select)) $select = self::select_clause($select);
  1118. $sql = 'SELECT ' . $select . ' FROM ' . self::prefix($table);
  1119. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1120. if(!empty($order)) $sql .= ' ORDER BY ' . $order;
  1121. if($page !== null && $limit !== null) $sql .= ' LIMIT ' . $page . ',' . $limit;
  1122. return self::query($sql, $fetch);
  1123. }
  1124. /**
  1125. * Returns a single row from a table
  1126. *
  1127. * @param string $table The table name
  1128. * @param mixed $select Either an array of fields or a MySQL string of fields
  1129. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1130. * @param string $order Order clause without the order keyword. ie: "added desc"
  1131. * @return mixed
  1132. */
  1133. static function row($table, $select='*', $where=null, $order=null) {
  1134. $result = self::select($table, $select, $where, $order, 0,1, false);
  1135. return self::fetch($result);
  1136. }
  1137. /**
  1138. * Returns all values from single column of a table
  1139. *
  1140. * @param string $table The table name
  1141. * @param string $column The name of the column
  1142. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1143. * @param string $order Order clause without the order keyword. ie: "added desc"
  1144. * @param int $page a page number
  1145. * @param int $limit a number for rows to return
  1146. * @return mixed
  1147. */
  1148. static function column($table, $column, $where=null, $order=null, $page=null, $limit=null) {
  1149. $result = self::select($table, $column, $where, $order, $page, $limit, false);
  1150. $array = array();
  1151. while($r = self::fetch($result)) array_push($array, a::get($r, $column));
  1152. return $array;
  1153. }
  1154. /**
  1155. * Returns a single field value from a table
  1156. *
  1157. * @param string $table The table name
  1158. * @param string $field The name of the field
  1159. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1160. * @param string $order Order clause without the order keyword. ie: "added desc"
  1161. * @return mixed
  1162. */
  1163. static function field($table, $field, $where=null, $order=null) {
  1164. $result = self::row($table, $field, $where, $order);
  1165. return a::get($result, $field);
  1166. }
  1167. /**
  1168. * Joins two tables and returns data from them
  1169. *
  1170. * @param string $table_1 The table name of the first table
  1171. * @param string $table_2 The table name of the second table
  1172. * @param string $on The MySQL ON clause without the ON keyword. ie: "user_id = comment_user"
  1173. * @param mixed $select Either an array of fields or a MySQL string of fields
  1174. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1175. * @param string $order Order clause without the order keyword. ie: "added desc"
  1176. * @param int $page a page number
  1177. * @param int $limit a number for rows to return
  1178. * @param string $type The join type (JOIN, LEFT, RIGHT, INNER)
  1179. * @return mixed
  1180. */
  1181. static function join($table_1, $table_2, $on, $select, $where=null, $order=null, $page=null, $limit=null, $type="JOIN") {
  1182. return self::select(
  1183. self::prefix($table_1) . ' ' . $type . ' ' .
  1184. self::prefix($table_2) . ' ON ' .
  1185. self::where($on),
  1186. $select,
  1187. self::where($where),
  1188. $order,
  1189. $page,
  1190. $limit
  1191. );
  1192. }
  1193. /**
  1194. * Runs a LEFT JOIN
  1195. *
  1196. * @param string $table_1 The table name of the first table
  1197. * @param string $table_2 The table name of the second table
  1198. * @param string $on The MySQL ON clause without the ON keyword. ie: "user_id = comment_user"
  1199. * @param mixed $select Either an array of fields or a MySQL string of fields
  1200. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1201. * @param string $order Order clause without the order keyword. ie: "added desc"
  1202. * @param int $page a page number
  1203. * @param int $limit a number for rows to return
  1204. * @return mixed
  1205. */
  1206. static function left_join($table_1, $table_2, $on, $select, $where=null, $order=null, $page=null, $limit=null) {
  1207. return self::join($table_1, $table_2, $on, $select, $where, $order, $page, $limit, 'LEFT JOIN');
  1208. }
  1209. /**
  1210. * Counts a number of rows in a table
  1211. *
  1212. * @param string $table The table name
  1213. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1214. * @return int
  1215. */
  1216. static function count($table, $where='') {
  1217. $result = self::row($table, 'count(*)', $where);
  1218. return ($result) ? a::get($result, 'count(*)') : 0;
  1219. }
  1220. /**
  1221. * Gets the minimum value in a column of a table
  1222. *
  1223. * @param string $table The table name
  1224. * @param string $column The name of the column
  1225. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1226. * @return mixed
  1227. */
  1228. static function min($table, $column, $where=null) {
  1229. $sql = 'SELECT MIN(' . $column . ') AS min FROM ' . self::prefix($table);
  1230. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1231. $result = self::query($sql, false);
  1232. $result = self::fetch($result);
  1233. return a::get($result, 'min', 1);
  1234. }
  1235. /**
  1236. * Gets the maximum value in a column of a table
  1237. *
  1238. * @param string $table The table name
  1239. * @param string $column The name of the column
  1240. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1241. * @return mixed
  1242. */
  1243. static function max($table, $column, $where=null) {
  1244. $sql = 'SELECT MAX(' . $column . ') AS max FROM ' . self::prefix($table);
  1245. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1246. $result = self::query($sql, false);
  1247. $result = self::fetch($result);
  1248. return a::get($result, 'max', 1);
  1249. }
  1250. /**
  1251. * Gets the sum of values in a column of a table
  1252. *
  1253. * @param string $table The table name
  1254. * @param string $column The name of the column
  1255. * @param mixed $where Either a key/value array as AND connected where clause or a simple MySQL where clause string
  1256. * @return mixed
  1257. */
  1258. static function sum($table, $column, $where=null) {
  1259. $sql = 'SELECT SUM(' . $column . ') AS sum FROM ' . self::prefix($table);
  1260. if(!empty($where)) $sql .= ' WHERE ' . self::where($where);
  1261. $result = self::query($sql, false);
  1262. $result = self::fetch($result);
  1263. return a::get($result, 'sum', 0);
  1264. }
  1265. /**
  1266. * Adds a prefix to a table name if set in c::set('db.prefix', 'myprefix_');
  1267. * This makes it possible to use table names in all methods without prefix
  1268. * and it will still be applied automatically.
  1269. *
  1270. * @param string $table The name of the table with or without prefix
  1271. * @return string The sanitized table name.
  1272. */
  1273. static function prefix($table) {
  1274. $prefix = c::get('db.prefix');
  1275. if(!$prefix) return $table;
  1276. return (!str::contains($table,$prefix)) ? $prefix . $table : $table;
  1277. }
  1278. /**
  1279. * Strips table specific column prefixes from the result array
  1280. *
  1281. * If you use column names like user_username, user_id, etc.
  1282. * use this method on the result array to strip user_ of all fields
  1283. *
  1284. * @param array $array The result array
  1285. * @return array The result array without those damn prefixes.
  1286. */
  1287. static function simple_fields($array) {
  1288. if(empty($array)) return false;
  1289. $output = array();
  1290. foreach($array AS $key => $value) {
  1291. $key = substr($key, strpos($key, '_')+1);
  1292. $output[$key] = $value;
  1293. }
  1294. return $output;
  1295. }
  1296. /**
  1297. * Makes it possible to use arrays for inputs instead of MySQL strings
  1298. *
  1299. * @param array $input
  1300. * @return string The final MySQL string, which will be used in the queries.
  1301. */
  1302. static function values($input) {
  1303. if(!is_array($input)) return $input;
  1304. $output = array();
  1305. foreach($input AS $key => $value) {
  1306. if($value === 'NOW()')
  1307. $output[] = $key . ' = NOW()';
  1308. elseif(is_array($value))
  1309. $output[] = $key . ' = \'' . a::json($value) . '\'';
  1310. else
  1311. $output[] = $key . ' = \'' . self::escape($value) . '\'';
  1312. }
  1313. return implode(', ', $output);
  1314. }
  1315. /**
  1316. * Escapes unwanted stuff in values like slashes, etc.
  1317. *
  1318. * @param string $value
  1319. * @return string Returns the escaped string
  1320. */
  1321. static function escape($value) {
  1322. $value = str::stripslashes($value);
  1323. return mysql_real_escape_string((string)$value, self::connect());
  1324. }
  1325. /**
  1326. * A simplifier to build search clauses
  1327. *
  1328. * @param string $search The search word
  1329. * @param array $fields An array of fields to search
  1330. * @param string $mode OR or AND
  1331. * @return string Returns the final where clause
  1332. */
  1333. static function search_clause($search, $fields, $mode='OR') {
  1334. if(empty($search)) return false;
  1335. $arr = array();
  1336. foreach($fields AS $f) {
  1337. array_push($arr, $f . ' LIKE \'%' . $search . '%\'');
  1338. //array_push($arr, $f . ' REGEXP "[[:<:]]' . db::escape($search) . '[[:>:]]"');
  1339. }
  1340. return '(' . implode(' ' . trim($mode) . ' ', $arr) . ')';
  1341. }
  1342. /**
  1343. * An easy method to build a part of the where clause to find stuff by its first character
  1344. *
  1345. * @param string $field The name of the field
  1346. * @param string $char The character to search for
  1347. * @return string Returns the where clause part
  1348. */
  1349. static function with($field, $char) {
  1350. return 'LOWER(SUBSTRING(' . $field . ',1,1)) = "' . db::escape($char) . '"';
  1351. }
  1352. /**
  1353. * Builds a select clause from a simple array
  1354. *
  1355. * @param array $field An array of field names
  1356. * @return string The MySQL string
  1357. */
  1358. static function select_clause($fields) {
  1359. return implode(', ', $fields);
  1360. }
  1361. /**
  1362. * A simplifier to build IN clauses
  1363. *
  1364. * @param array $array An array of fieldnames
  1365. * @return string The MySQL string for the where clause
  1366. */
  1367. static function in($array) {
  1368. return '\'' . implode('\',\'', $array) . '\'';
  1369. }
  1370. /**
  1371. * A handler to convert key/value arrays to an where clause
  1372. *
  1373. * @param array $array keys/values for the where clause
  1374. * @param string $method AND or OR
  1375. * @return string The MySQL string for the where clause
  1376. */
  1377. static function where($array, $method='AND') {
  1378. if(!is_array($array)) return $array;
  1379. $output = array();
  1380. foreach($array AS $field => $value) {
  1381. $output[] = $field . ' = \'' . self::escape($value) . '\'';
  1382. $separator = ' ' . $method . ' ';
  1383. }
  1384. return implode(' ' . $method . ' ', $output);
  1385. }
  1386. /**
  1387. * An internal error handler
  1388. *
  1389. * @param string $msg The error/success message to return
  1390. * @param boolean $exit die after this error?
  1391. * @return mixed
  1392. */
  1393. static function error($msg=null, $exit=false) {
  1394. $connection = self::connection();
  1395. $error = (mysql_error()) ? @mysql_error($connection) : false;
  1396. $number = (mysql_errno()) ? @mysql_errno($connection) : 0;
  1397. if(c::get('db.debugging')) {
  1398. if($error) $msg .= ' -> ' . $error . ' (' . $number . ')';
  1399. if(self::$last_query) $msg .= ' Query: ' . self::$last_query;
  1400. } else $msg .= ' - ' . l::get('db.errors.msg', 'This will be fixed soon!');
  1401. if($exit || c::get('db.debugging')) die($msg);
  1402. return array(
  1403. 'status' => 'error',
  1404. 'msg' => $msg
  1405. );
  1406. }
  1407. }
  1408. /**
  1409. *
  1410. * Directory
  1411. *
  1412. * This class makes it easy to create/edit/delete
  1413. * directories on the filesystem
  1414. *
  1415. * @package Kirby
  1416. */
  1417. class dir {
  1418. /**
  1419. * Creates a new directory
  1420. *
  1421. * @param string $dir The path for the new directory
  1422. * @return boolean True: the dir has been created, false: creating failed
  1423. */
  1424. static function make($dir) {
  1425. if(is_dir($dir)) return true;
  1426. if(!@mkdir($dir, 0755)) return false;
  1427. @chmod($dir, 0755);
  1428. return true;
  1429. }
  1430. /**
  1431. * Reads all files from a directory and returns them as an array.
  1432. * It skips unwanted invisible stuff.
  1433. *
  1434. * @param string $dir The path of directory
  1435. * @param array $ignore Optional array with filenames, which should be ignored
  1436. * @return mixed An array of filenames or false
  1437. */
  1438. static function read($dir, $ignore=array()) {
  1439. if(!is_dir($dir)) return false;
  1440. $skip = array_merge(array('.', '..', '.DS_Store'), $ignore);
  1441. return array_diff(scandir($dir),$skip);
  1442. }
  1443. /**
  1444. * Reads a directory and returns a full set of info about it
  1445. *
  1446. * @param string $dir The path of directory
  1447. * @param array $ignore Optional array with filenames, which should be ignored
  1448. * @return mixed An info array or false
  1449. */
  1450. static function inspect($dir, $ignore=array()) {
  1451. if(!is_dir($dir)) return array();
  1452. $files = dir::read($dir, $ignore);
  1453. $modified = filemtime($dir);
  1454. $data = array(
  1455. 'name' => basename($dir),
  1456. 'root' => $dir,
  1457. 'modified' => $modified,
  1458. 'files' => array(),
  1459. 'children' => array()
  1460. );
  1461. foreach($files AS $file) {
  1462. if(is_dir($dir . '/' . $file)) {
  1463. $data['children'][] = $file;
  1464. } else {
  1465. $data['files'][] = $file;
  1466. }
  1467. }
  1468. return $data;
  1469. }
  1470. /**
  1471. * Moves a directory to a new location
  1472. *
  1473. * @param string $old The current path of the directory
  1474. * @param string $new The desired path where the dir should be moved to
  1475. * @return boolean True: the directory has been moved, false: moving failed
  1476. */
  1477. static function move($old, $new) {
  1478. if(!is_dir($old)) return false;
  1479. return (@rename($old, $new) && is_dir($new)) ? true : false;
  1480. }
  1481. /**
  1482. * Deletes a directory
  1483. *
  1484. * @param string $dir The path of the directory
  1485. * @param boolean $keep If set to true, the directory will flushed but not removed.
  1486. * @return boolean True: the directory has been removed, false: removing failed
  1487. */
  1488. static function remove($dir, $keep=false) {
  1489. if(!is_dir($dir)) return false;
  1490. $handle = @opendir($dir);
  1491. $skip = array('.', '..');
  1492. if(!$handle) return false;
  1493. while($item = @readdir($handle)) {
  1494. if(is_dir($dir . '/' . $item) && !in_array($item, $skip)) {
  1495. self::remove($dir . '/' . $item);
  1496. } else if(!in_array($item, $skip)) {
  1497. @unlink($dir . '/' . $item);
  1498. }
  1499. }
  1500. @closedir($handle);
  1501. if(!$keep) return @rmdir($dir);
  1502. return true;
  1503. }
  1504. /**
  1505. * Flushes a d…

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