PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/Router.php

http://shozu.googlecode.com/
PHP | 2292 lines | 1690 code | 122 blank | 480 comment | 67 complexity | ba750d243c3f610c89d046bd20133317 MD5 | raw file

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

  1. <?php
  2. namespace shozu;
  3. // CORE
  4. interface RequestInterface
  5. {
  6. /**
  7. * @return string
  8. */
  9. public function getRequestedUrl();
  10. /**
  11. * @return \DateTime
  12. */
  13. public function getDateTime();
  14. /**
  15. * @return string
  16. */
  17. public function getCookieVar($cookie_name);
  18. /**
  19. * @return string
  20. */
  21. public function getPostVar($post_var_name);
  22. /**
  23. * @return string
  24. */
  25. public function getGetVar($get_var_name);
  26. /**
  27. * @return string
  28. */
  29. public function getServerVar($server_var_name);
  30. /**
  31. * @return string
  32. */
  33. public function getSessionVar($session_var_name);
  34. /**
  35. *
  36. * @param string $uploaded_file_name
  37. * @return Array
  38. */
  39. public function getUploadedFile($uploaded_file_name);
  40. /**
  41. * @return string
  42. */
  43. public function getRequestMethod();
  44. /**
  45. * @return string
  46. */
  47. public function getBody();
  48. /**
  49. *
  50. * @param string $param_name
  51. * @param string $param_value
  52. */
  53. public function setParam($param_name, $param_value);
  54. /**
  55. *
  56. * @param string $param_name
  57. */
  58. public function getParam($param_name);
  59. }
  60. interface ResponseInterface
  61. {
  62. /**
  63. *
  64. * @param string $cookie_var_name
  65. * @param string $cookie_var_value
  66. */
  67. public function setCookieVar($cookie_var_name, $cookie_var_value, $expires = 0);
  68. /**
  69. *
  70. * @param string $session_var_name
  71. * @param mixed $session_var_value
  72. */
  73. public function setSessionVar($session_var_name, $session_var_value);
  74. public function send();
  75. }
  76. interface ActionInterface
  77. {
  78. /**
  79. * @param RequestInterface $request
  80. */
  81. public function __construct(RequestInterface $request);
  82. /**
  83. * @return ResponseInterface
  84. */
  85. public function getResponse();
  86. /**
  87. * @return RequestInterface
  88. */
  89. public function getRequest();
  90. }
  91. class Exception extends \Exception
  92. {
  93. }
  94. class HTTPException extends Exception
  95. {
  96. }
  97. class RouterException extends Exception{}
  98. class Router
  99. {
  100. private $routes = array();
  101. private $event_dispatcher;
  102. private static $instance;
  103. /**
  104. *
  105. * @return Router
  106. */
  107. public static function getInstance()
  108. {
  109. if(is_null(self::$instance))
  110. {
  111. self::$instance = new self;
  112. }
  113. return self::$instance;
  114. }
  115. private function __construct()
  116. {
  117. spl_autoload_register(array(get_called_class(),'autoload'));
  118. }
  119. private function notify($event)
  120. {
  121. if(!is_null($this->event_dispatcher))
  122. {
  123. call_user_func_array(array($this->event_dispatcher, 'notify'), func_get_args());
  124. }
  125. }
  126. public function setEventDispatcher(EventDispatcherInterface $event_dispatcher)
  127. {
  128. $this->event_dispatcher = $event_dispatcher;
  129. return $this;
  130. }
  131. /**
  132. *
  133. * @param string $route
  134. * @param string $action_name
  135. * @return Router
  136. */
  137. public function registerAction($route, $action_name)
  138. {
  139. $parts = explode(' ', $route);
  140. if(!in_array($parts[0], array('GET','POST','DELETE','PUT')))
  141. {
  142. throw new RouterException('unknown request method');
  143. }
  144. foreach($parts as $k=>$v)
  145. {
  146. $v = trim($v);
  147. if(empty($v))
  148. {
  149. unset($parts[$k]);
  150. }
  151. }
  152. $route = implode(' ', $parts);
  153. $this->routes[$route] = $action_name;
  154. return $this;
  155. }
  156. /**
  157. *
  158. * @param string $action_name
  159. * @param RequestInterface $request
  160. * @param array $params
  161. */
  162. public function executeAction($action_name, RequestInterface $request, Array $params = array())
  163. {
  164. foreach($params as $param_name => $param_value)
  165. {
  166. $request->setParam($param_name, $param_value);
  167. }
  168. $action = new $action_name($request);
  169. if(!($action instanceof ActionInterface))
  170. {
  171. throw new RouterException('Not an Action');
  172. }
  173. $this->notify('router.has_action', $action);
  174. $response = $action->getResponse();
  175. if(!($response instanceof ResponseInterface))
  176. {
  177. throw new RouterException('Not a Response');
  178. }
  179. $this->notify('router.has_response', $response);
  180. $response->send();
  181. }
  182. /**
  183. *
  184. * @param RequestInterface $request
  185. */
  186. public function dispatch(RequestInterface $request)
  187. {
  188. $run_this = $this->findAction($request);
  189. $this->executeAction($run_this['action'], $request, $run_this['params']);
  190. }
  191. /**
  192. *
  193. * @param string $action_name
  194. * @param array $params
  195. * @return string
  196. */
  197. public function getUrl($action_name, array $params = array())
  198. {
  199. foreach($this->routes as $route => $a_name)
  200. {
  201. if($action_name == $a_name)
  202. {
  203. foreach($params as $k => $v)
  204. {
  205. $route = str_replace('<'.$k.'>', $v, $route);
  206. }
  207. if(strpos($route, '<'))
  208. {
  209. throw new RouterException('Missing parameter');
  210. }
  211. // remove leading http verb
  212. $parts = explode(' ', $route);
  213. if(in_array($parts[0], array('GET','POST','DELETE','OUT')))
  214. {
  215. unset($parts[0]);
  216. }
  217. return trim(implode('', $parts));
  218. }
  219. }
  220. throw new RouterException('Could not generate URL');
  221. }
  222. private function findAction(RequestInterface $request)
  223. {
  224. $requested_url = $this->getRequestedRoute($request);
  225. $this->notify('has_uri');
  226. $action = '';
  227. $params = array();
  228. if(isset($this->routes[$requested_url]))
  229. {
  230. $action = $this->routes[$requested_url];
  231. }
  232. else
  233. {
  234. foreach($this->routes as $route => $action_name)
  235. {
  236. $regex = '#^' . str_replace('/','\/',preg_replace('/<([a-z0-9]+)>/i', '([a-zA-Z0-9\-\._]+)', $route)) . '$#';
  237. if (preg_match($regex, $requested_url))
  238. {
  239. $action = $action_name;
  240. $params = $this->extractParams($route, $requested_url, $regex);
  241. break;
  242. }
  243. }
  244. }
  245. if(empty($action))
  246. {
  247. throw new RouterException('no such page', 404);
  248. }
  249. if(!class_exists($action))
  250. {
  251. throw new RouterException('action unavailable', 500);
  252. }
  253. return array('action' => $action, 'params' => $params);
  254. }
  255. private function extractParams($route, $requested_url, $regex)
  256. {
  257. $param_names = array();
  258. preg_match_all('/<([a-z0-9]+)>/i', $route, $param_names);
  259. if(count($param_names) === 2)
  260. {
  261. $param_names = $param_names[1];
  262. }
  263. $param_values = array();
  264. preg_match_all($regex, $requested_url, $param_values, \PREG_SET_ORDER);
  265. if(count($param_values))
  266. {
  267. $param_values = array_pop($param_values);
  268. if(count($param_values) && $param_values[0] == $requested_url)
  269. {
  270. array_shift($param_values);
  271. }
  272. }
  273. if(count($param_names) === count($param_values))
  274. {
  275. return array_combine($param_names, $param_values);
  276. }
  277. return array();
  278. }
  279. private function getRequestedRoute(RequestInterface $request)
  280. {
  281. $requested_url = $request->getRequestedUrl();
  282. $pos = strpos($requested_url, '&');
  283. if ($pos !== false)
  284. {
  285. $requested_url = substr($requested_url, 0, $pos);
  286. }
  287. if (strpos($requested_url, '/') !== 0)
  288. {
  289. $requested_url = '/' . $requested_url;
  290. }
  291. $parts = explode('?', $requested_url);
  292. $requested_url = $parts[0];
  293. $requested_url = $request->getRequestMethod() . ' ' . $requested_url;
  294. return $requested_url;
  295. }
  296. /**
  297. *
  298. * @param string $class
  299. * @return bool
  300. */
  301. public static function autoload($class)
  302. {
  303. if (substr($class, 0, 1) == '\\')
  304. {
  305. $class = substr($class, 1);
  306. }
  307. $classFile = str_replace(array('_', '\\'), array(\DIRECTORY_SEPARATOR, \DIRECTORY_SEPARATOR), $class) . '.php';
  308. $old = ini_set('error_reporting', 0);
  309. $result = include ($classFile);
  310. ini_set('error_reporting', $old);
  311. return $result;
  312. }
  313. }
  314. interface EventDispatcherInterface
  315. {
  316. public function attach($event, $callback);
  317. public function detach($event, $callback);
  318. public function notify($event);
  319. }
  320. // OPTIONAL
  321. class EventDispatcher implements EventDispatcherInterface
  322. {
  323. private $events = array(); // events callback
  324. private static $instance;
  325. private function __construct()
  326. {
  327. }
  328. /**
  329. *
  330. * @return EventDispatcher
  331. */
  332. public static function getInstance()
  333. {
  334. if(is_null(self::$instance))
  335. {
  336. self::$instance = new self;
  337. }
  338. return self::$instance;
  339. }
  340. /**
  341. * Observe event
  342. *
  343. * <code>
  344. * EventDispatcher::observe('system.shutdown', array('Profiler', 'display'));
  345. * </code>
  346. *
  347. * @param string
  348. * @param mixed
  349. * @return EventDispatcher
  350. */
  351. public function attach($event, $callback)
  352. {
  353. if (!isset($this->events[$event]))
  354. {
  355. $this->events[$event] = array();
  356. }
  357. $this->events[$event][] = $callback;
  358. return $this;
  359. }
  360. /**
  361. *
  362. * @param string $name
  363. * @param callback $callback
  364. * @return EventDispatcher
  365. */
  366. public function detach($event, $callback=false)
  367. {
  368. if (!$callback)
  369. {
  370. $this->events[$event] = array();
  371. }
  372. else if(isset($this->events[$event]))
  373. {
  374. foreach ($this->events[$event] as $i => $event_callback)
  375. {
  376. if ($callback === $event_callback)
  377. {
  378. unset($this->events[$event][$i]);
  379. }
  380. }
  381. }
  382. return $this;
  383. }
  384. /**
  385. *
  386. * @param string $name
  387. * @return array
  388. */
  389. public function get($event)
  390. {
  391. return empty($this->events[$event]) ? array(): $this->events[$event];
  392. }
  393. /**
  394. * Notify event
  395. *
  396. * <code>
  397. * EventDispatcher::notify('system.execute');
  398. * </code>
  399. *
  400. * @param string
  401. */
  402. public function notify($event)
  403. {
  404. // removing event name from the arguments
  405. $args = func_num_args() > 1 ? array_slice(func_get_args(), 1): array();
  406. foreach ($this->get($event) as $callback)
  407. {
  408. if(is_callable($callback))
  409. {
  410. call_user_func_array($callback, $args);
  411. }
  412. }
  413. }
  414. }
  415. abstract class ResponseAbstract implements ResponseInterface
  416. {
  417. private $headers = array();
  418. private $body = '';
  419. public function sendHeaders()
  420. {
  421. foreach ($this->headers as $header_name => $header_value)
  422. {
  423. header($header_name . ': ' . $header_value, true);
  424. }
  425. }
  426. /**
  427. *
  428. * @param string $header_name
  429. * @param string $header_value
  430. * @return HTMLResponse
  431. */
  432. public function setHeader($header_name, $header_value)
  433. {
  434. $this->headers[$header_name] = $header_value;
  435. return $this;
  436. }
  437. /**
  438. *
  439. * @param string $body
  440. * @return HTMLResponse
  441. */
  442. public function setBody($body)
  443. {
  444. $this->body = $body;
  445. return $this;
  446. }
  447. /**
  448. *
  449. * @return array
  450. */
  451. public function getHeaders()
  452. {
  453. return $this->headers;
  454. }
  455. /**
  456. *
  457. * @return string
  458. */
  459. public function getBody()
  460. {
  461. return $this->body;
  462. }
  463. /**
  464. *
  465. * @param string $cookie_var_name
  466. * @param string $cookie_var_value
  467. * @param integer $expires
  468. */
  469. public function setCookieVar($cookie_var_name, $cookie_var_value, $expires = 0)
  470. {
  471. setcookie($cookie_var_name, $cookie_var_value, $expires);
  472. }
  473. /**
  474. *
  475. * @param string $session_var_name
  476. * @param string $session_var_value
  477. */
  478. public function setSessionVar($session_var_name, $session_var_value)
  479. {
  480. if(!isset($_SESSION))
  481. {
  482. session_start();
  483. }
  484. $_SESSION[$session_var_name] = $session_var_value;
  485. }
  486. }
  487. abstract class ActionAbstract implements ActionInterface
  488. {
  489. protected $request;
  490. /**
  491. *
  492. * @param RequestInterface $request
  493. */
  494. public function __construct(RequestInterface $request)
  495. {
  496. $this->request = $request;
  497. }
  498. /**
  499. *
  500. * @return RequestInterface
  501. */
  502. public function getRequest()
  503. {
  504. return $this->request;
  505. }
  506. }
  507. class Request implements RequestInterface
  508. {
  509. private $constructed_at;
  510. private $constructed_at_datetime;
  511. private $params;
  512. public function __construct()
  513. {
  514. $this->constructed_at = time();
  515. }
  516. /**
  517. * @return string
  518. */
  519. public function getRequestedUrl()
  520. {
  521. return(isset($_SERVER['REDIRECT_URL']) ? $_SERVER['REDIRECT_URL'] : $_SERVER['REQUEST_URI']);
  522. }
  523. /**
  524. * @return DateTime
  525. */
  526. public function getDateTime()
  527. {
  528. if(is_null($this->constructed_at_datetime))
  529. {
  530. $timestamp = $this->getServerVar('REQUEST_TIME') ?: $this->constructed_at;
  531. $this->constructed_at_datetime = \DateTime::createFromFormat('Y-m-d H:i:s', date('Y-m-d H:i:s', $timestamp));
  532. }
  533. return $this->constructed_at_datetime;
  534. }
  535. /**
  536. *
  537. * @return string
  538. */
  539. public function getRequestMethod()
  540. {
  541. return $_SERVER['REQUEST_METHOD'];
  542. }
  543. /**
  544. *
  545. * @param string $server_var_name
  546. * @return string
  547. */
  548. public function getServerVar($server_var_name)
  549. {
  550. if(isset($_SERVER[$server_var_name]))
  551. {
  552. return $_SERVER[$server_var_name];
  553. }
  554. return;
  555. }
  556. /**
  557. *
  558. * @param string $server_var_name
  559. * @return string
  560. */
  561. public function getCookieVar($cookie_name)
  562. {
  563. if(isset($_COOKIE[$cookie_name]))
  564. {
  565. return $_COOKIE[$cookie_name];
  566. }
  567. return;
  568. }
  569. /**
  570. *
  571. * @param string $server_var_name
  572. * @return string
  573. */
  574. public function getPostVar($post_var_name)
  575. {
  576. if(isset($_POST[$post_var_name]))
  577. {
  578. return $_POST[$post_var_name];
  579. }
  580. return;
  581. }
  582. /**
  583. *
  584. * @param string $server_var_name
  585. * @return string
  586. */
  587. public function getSessionVar($session_var_name)
  588. {
  589. if(!isset($_SESSION))
  590. {
  591. session_start();
  592. }
  593. if(isset($_SESSION[$session_var_name]))
  594. {
  595. return $_SESSION[$session_var_name];
  596. }
  597. return;
  598. }
  599. /**
  600. *
  601. * @param string $server_var_name
  602. * @return string
  603. */
  604. public function getGetVar($get_var_name)
  605. {
  606. if(isset($_GET[$get_var_name]))
  607. {
  608. return $_GET[$get_var_name];
  609. }
  610. return;
  611. }
  612. /**
  613. *
  614. * @return string
  615. */
  616. public function getBody()
  617. {
  618. return file_get_contents('php://input');
  619. }
  620. /**
  621. *
  622. * @param string $uploaded_file_name
  623. * @return array
  624. */
  625. public function getUploadedFile($uploaded_file_name)
  626. {
  627. if(isset($_FILES[$uploaded_file_name]))
  628. {
  629. $_FILES[$uploaded_file_name];
  630. }
  631. return;
  632. }
  633. /**
  634. *
  635. * @param string $param_name
  636. * @param string $param_value
  637. * @return Request
  638. */
  639. public function setParam($param_name, $param_value)
  640. {
  641. $this->params[$param_name] = $param_value;
  642. return $this;
  643. }
  644. public function getParam($param_name)
  645. {
  646. if(isset($this->params[$param_name]))
  647. {
  648. return $this->params[$param_name];
  649. }
  650. return;
  651. }
  652. }
  653. class JSONResponse extends ResponseAbstract
  654. {
  655. private $data;
  656. /**
  657. *
  658. * @param mixed $data
  659. * @return JSONResponse
  660. */
  661. public function setData($data)
  662. {
  663. $this->data = $data;
  664. return $this;
  665. }
  666. public function send()
  667. {
  668. $this->setHeader('Content-type', 'application/json');
  669. $this->sendHeaders();
  670. echo json_encode($this->data);
  671. }
  672. }
  673. class HTMLResponse extends ResponseAbstract
  674. {
  675. public function send()
  676. {
  677. $this->setHeader('Content-type', 'text/html');
  678. $this->sendHeaders();
  679. echo $this->getBody();
  680. }
  681. }
  682. class TaconiteResponseException extends Exception{
  683. private $xml;
  684. public function setXML($xml)
  685. {
  686. $this->xml = $xml;
  687. }
  688. public function getXML($xml)
  689. {
  690. return $this->xml;
  691. }
  692. }
  693. class TaconiteResponse extends ResponseAbstract
  694. {
  695. private $debug = false;
  696. private $content = '';
  697. public function setDebug($on_off)
  698. {
  699. $this->debug = (bool)$on_off;
  700. }
  701. /**
  702. * Appends XHTML content to matching elements
  703. *
  704. * @param string $selector Any valid JQuery selector
  705. * @param string $content Any valid XHTML content
  706. * @return Taconite Taconite document instance
  707. */
  708. public function append($selector, $content)
  709. {
  710. $this->elementCommand('append', $selector, $content);
  711. return $this;
  712. }
  713. /**
  714. * Prepends XHTML content to matching elements
  715. *
  716. * @param string $selector Any valid JQuery selector
  717. * @param string $content Any valid XHTML content
  718. * @return Taconite Taconite document instance
  719. */
  720. public function prepend($selector, $content)
  721. {
  722. $this->elementCommand('prepend', $selector, $content);
  723. return $this;
  724. }
  725. /**
  726. * Puts XHTML content before matching elements
  727. *
  728. * @param string $selector Any valid JQuery selector
  729. * @param string $content Any valid XHTML content
  730. * @return Taconite Taconite document instance
  731. */
  732. public function before($selector, $content)
  733. {
  734. $this->elementCommand('before', $selector, $content);
  735. return $this;
  736. }
  737. /**
  738. * Puts XHTML content after matching elements
  739. *
  740. * @param string $selector Any valid JQuery selector
  741. * @param string $content Any valid XHTML content
  742. * @return Taconite Taconite document instance
  743. */
  744. public function after($selector, $content)
  745. {
  746. $this->elementCommand('after', $selector, $content);
  747. return $this;
  748. }
  749. /**
  750. * Wraps matching elements with given tags.
  751. *
  752. * Don't use text in $content
  753. *
  754. * @param string $selector Any valid JQuery selector
  755. * @param string $content Wrapper string
  756. * @return Taconite Taconite document instance
  757. */
  758. public function wrap($selector, $content)
  759. {
  760. $this->elementCommand('wrap', $selector, $content);
  761. return $this;
  762. }
  763. /**
  764. * Replaces matching elements with given content.
  765. *
  766. * This is not JQuery-native but a convenience of the Taconite plugin
  767. *
  768. * @param string $selector Any valid JQuery selector
  769. * @param string $content Any valid XHTML content
  770. * @return Taconite Taconite document instance
  771. */
  772. public function replace($selector, $content)
  773. {
  774. $this->elementCommand('replace', $selector, $content);
  775. return $this;
  776. }
  777. /**
  778. * Replaces matching element's content with given content.
  779. *
  780. * This is not JQuery-native but a convenience if the Taconite plugin
  781. *
  782. * @param string $selector Any valid JQuery selector
  783. * @param string $content Any valid XHTML content
  784. * @return Taconite Taconite document instance
  785. */
  786. public function replaceContent($selector, $content)
  787. {
  788. $this->elementCommand('replaceContent', $selector, $content);
  789. return $this;
  790. }
  791. /**
  792. * Removes matching elements
  793. *
  794. * @param string $selector Any valid JQuery selector
  795. * @return Taconite Taconite document instance
  796. */
  797. public function remove($selector)
  798. {
  799. $this->rawCommand('<remove select="' . $selector . '" />');
  800. return $this;
  801. }
  802. /**
  803. * Shows matching elements
  804. *
  805. * @param string $selector Any valid JQuery selector
  806. * @return Taconite Taconite document instance
  807. */
  808. public function show($selector)
  809. {
  810. $this->rawCommand('<show select="' . $selector . '" />');
  811. return $this;
  812. }
  813. /**
  814. * Hides matching elements
  815. *
  816. * @param string $selector Any valid JQuery selector
  817. * @return Taconite Taconite document instance
  818. */
  819. public function hide($selector)
  820. {
  821. $this->rawCommand('<hide select="' . $selector . '" />');
  822. return $this;
  823. }
  824. /**
  825. * Remove content from matching elements (JQuery's empty method)
  826. *
  827. * @param string $selector Any valid JQuery selector
  828. * @return Taconite Taconite document instance
  829. */
  830. public function removeContent($selector)
  831. {
  832. $this->rawCommand('<empty select="' . $selector . '" />');
  833. return $this;
  834. }
  835. /**
  836. * Adds class to matching elements
  837. *
  838. * @param string $class CSS class to add
  839. * @param string $selector Any valid JQuery selector
  840. * @return Taconite Taconite document instance
  841. */
  842. public function addClass($class, $selector)
  843. {
  844. $this->rawCommand('<addClass select="' . $selector . '" arg1="'
  845. . $class . '" /><addClass select="'
  846. . $selector . '" value="' . $class . '" />');
  847. return $this;
  848. }
  849. /**
  850. * Removes class from matching elements
  851. *
  852. * @param string $class CSS class to remove
  853. * @param string $selector Any valid JQuery selector
  854. * @return Taconite Taconite document instance
  855. */
  856. public function removeClass($class, $selector)
  857. {
  858. $this->rawCommand('<removeClass select="' . $selector . '" arg1="'
  859. . $class . '" /><removeClass select="'
  860. . $selector . '" value="' . $class . '" />');
  861. return $this;
  862. }
  863. /**
  864. * Toggles a class to matching elements
  865. *
  866. * @param string $class CSS class to toggle
  867. * @param string $selector Any valid JQuery selector
  868. * @return Taconite Taconite document instance
  869. */
  870. public function toggleClass($class, $selector)
  871. {
  872. $this->rawCommand('<toggleClass select="' . $selector . '" arg1="'
  873. . $class . '" /><toggleClass select="'
  874. . $selector . '" value="' . $class . '" />');
  875. return $this;
  876. }
  877. /**
  878. * Modifies a css property
  879. *
  880. * The taconite plugin requires that you "camelize" all css properties but
  881. * this will do it for you if forget it.
  882. *
  883. * @param string $selector Any valid JQuery selector
  884. * @param string $property Any CSS property
  885. * @param string $value CSS value
  886. * @return Taconite Taconite document instance
  887. */
  888. public function css($selector, $property, $value)
  889. {
  890. $property = $this->camelize($property);
  891. $taco = '<css select="' . $selector . '" name="' . $property
  892. . '" value="' . $value . '" />';
  893. $this->rawCommand($taco);
  894. return $this;
  895. }
  896. /**
  897. * Adds Javascript to be evaluated in the global context
  898. *
  899. * @param string $script Javascript string
  900. * @return Taconite Taconite document instance
  901. */
  902. public function js($script)
  903. {
  904. $taco = '<eval><![CDATA[' . $script . ']]></eval>';
  905. $this->rawCommand($taco);
  906. return $this;
  907. }
  908. /**
  909. * Adds an element command, as described in the Taconite plugin docs.
  910. *
  911. * @param string $method A JQuery method
  912. * @param string $selector Any valid JQuery selector
  913. * @param string $content XHTML content
  914. * @return Taconite Taconite document instance
  915. */
  916. public function elementCommand($method, $selector, $content)
  917. {
  918. $taco = '<' . $method . ' select="' . $selector . '">' . $content
  919. . '</' . $method . '>';
  920. $this->rawCommand($taco);
  921. return $this;
  922. }
  923. /**
  924. * Adds a raw Taconite command to the document
  925. *
  926. * @param string $command A Taconite command
  927. * @return Taconite Taconite document instance
  928. */
  929. public function rawCommand($command)
  930. {
  931. $this->content.= $command;
  932. return $this;
  933. }
  934. /**
  935. * Javascript alert shortcut
  936. *
  937. * @param string
  938. * @return Taconite Taconite document instance
  939. */
  940. public function alert($string)
  941. {
  942. $this->js('alert(' . $this->escapeJSArgs($string) . ');');
  943. return $this;
  944. }
  945. /**
  946. * Javascript status bar shortcut
  947. *
  948. * @param string
  949. * @return Taconite Taconite document instance
  950. */
  951. public function status($string)
  952. {
  953. $this->js('window.status = ' . $this->escapeJSArgs($string) . ';');
  954. return $this;
  955. }
  956. public function escapeJSArgs($string, $string_delimiter = '"', $add_delimiters = true)
  957. {
  958. if ($string_delimiter == '"')
  959. {
  960. $string = str_replace(array(
  961. "\r\n",
  962. "\n",
  963. '"'
  964. ) , array(
  965. '\n',
  966. '\n',
  967. '\"'
  968. ) , $string);
  969. }
  970. elseif ($string_delimiter == "'")
  971. {
  972. $string = str_replace(array(
  973. "\r\n",
  974. "\n",
  975. "'"
  976. ) , array(
  977. '\n',
  978. '\n',
  979. "\'"
  980. ) , $string);
  981. }
  982. else
  983. {
  984. trigger_error('delimiter should be single or double quote.', E_USER_ERROR);
  985. }
  986. if ($add_delimiters)
  987. {
  988. return $string_delimiter . $string . $string_delimiter;
  989. }
  990. return $string;
  991. }
  992. /**
  993. * Returns the command document string
  994. *
  995. * This method does not perform any syntax check !
  996. *
  997. * @return string
  998. */
  999. public function getContent()
  1000. {
  1001. return '<taconite>' . $this->content . '</taconite>';
  1002. }
  1003. public function send()
  1004. {
  1005. $trans = array(
  1006. '&nbsp;' => '&#160;'
  1007. );
  1008. $this->content = strtr($this->content, $trans);
  1009. if ($this->isValid())
  1010. {
  1011. $this->setHeader('Expires', '26 Jul 1997 05:00:00 GMT');
  1012. $this->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
  1013. $this->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate');
  1014. $this->setHeader('Cache-Control', 'pre-check=0, post-check=0, max-age=0');
  1015. $this->setHeader('Pragma', 'no-cache');
  1016. $this->setHeader('Content-type', 'text/xml; charset=UTF-8');
  1017. $this->sendHeaders();
  1018. echo $this->getContent();
  1019. }
  1020. else
  1021. {
  1022. $taconite_exception = new TaconiteResponseException('Document is not valid XML.');
  1023. $taconite_exception->setXML($this->content);
  1024. throw $taconite_exception;
  1025. }
  1026. }
  1027. private function camelize($property)
  1028. {
  1029. $property_chops = explode('-', $property);
  1030. $chops_size = count($property_chops);
  1031. if ($chops_size > 1)
  1032. {
  1033. for ($i = 1;$i < $chops_size;$i++)
  1034. {
  1035. $property_chops[$i] = ucfirst(trim($property_chops[$i]));
  1036. }
  1037. $property = implode('', $property_chops);
  1038. }
  1039. return $property;
  1040. }
  1041. private function isValid()
  1042. {
  1043. $string = $this->getContent();
  1044. libxml_use_internal_errors(true);
  1045. $dom = new \DOMDocument('1.0', 'utf-8');
  1046. $dom->loadXML($string);
  1047. $errors = libxml_get_errors();
  1048. if (empty($errors))
  1049. {
  1050. return true;
  1051. }
  1052. return false;
  1053. }
  1054. }
  1055. class CookieSessionHandler
  1056. {
  1057. private static $obj_session;
  1058. private $expires = 0;
  1059. private $encryption_key;
  1060. private $cookie_domain;
  1061. private $session_id;
  1062. private function __construct($encryption_key, $cookie_domain = '', $session_id = 'omfg')
  1063. {
  1064. $this->encryption_key = $encryption_key;
  1065. $this->cookie_domain = $cookie_domain;
  1066. $this->session_id = $session_id;
  1067. ini_set('session.use_cookies', 0);
  1068. ini_set('session.use_trans_sid', 0);
  1069. session_set_save_handler(array($this, 'open'),
  1070. array($this, 'close'),
  1071. array($this, 'read'),
  1072. array($this, 'write'),
  1073. array($this, 'destroy'),
  1074. array($this, 'gc'));
  1075. register_shutdown_function('session_write_close');
  1076. session_start();
  1077. }
  1078. /**
  1079. *
  1080. * @param integer $stamp
  1081. * @return CookieSessionHandler
  1082. */
  1083. public function setExpiry($stamp)
  1084. {
  1085. $this->expires = (int)$stamp;
  1086. $_SESSION['sess_exp'] = $this->expires;
  1087. return $this;
  1088. }
  1089. /**
  1090. *
  1091. * @param string $arg_str_save_path
  1092. * @param string $arg_str_session_name
  1093. * @return bool
  1094. */
  1095. public function open($arg_str_save_path, $arg_str_session_name)
  1096. {
  1097. return true;
  1098. }
  1099. /**
  1100. *
  1101. * @return bool
  1102. */
  1103. public function close()
  1104. {
  1105. return true;
  1106. }
  1107. /**
  1108. *
  1109. * @param string $arg_str_session_id
  1110. * @return string
  1111. */
  1112. public function read($arg_str_session_id)
  1113. {
  1114. $arg_str_session_id = $this->session_id;
  1115. if(!isset($_COOKIE[$arg_str_session_id]))
  1116. {
  1117. return '';
  1118. }
  1119. $cypher = $_COOKIE[$arg_str_session_id];
  1120. $plain_text = self::cookieDecrypt($cypher, $this->encryption_key);
  1121. return $plain_text;
  1122. }
  1123. /**
  1124. *
  1125. * @param string $arg_str_session_id
  1126. * @param string $arg_str_session_data
  1127. * @return bool
  1128. */
  1129. public function write($arg_str_session_id, $arg_str_session_data)
  1130. {
  1131. $arg_str_session_id = $this->session_id;
  1132. if(empty($arg_str_session_data))
  1133. {
  1134. return true;
  1135. }
  1136. $cypher = self::cookieCrypt($arg_str_session_data, $this->encryption_key);
  1137. if(strlen($cypher) > 4000)
  1138. {
  1139. throw new Exception('session data overflow');
  1140. }
  1141. if($this->cookie_domain)
  1142. {
  1143. setcookie(session_name(), session_id(), $this->expires, '/', ($this->cookie_domain ? '.' . $this->cookie_domain : NULL));
  1144. }
  1145. setcookie($arg_str_session_id, $cypher, $this->expires, '/', ($this->cookie_domain ? '.' . $this->cookie_domain : NULL));
  1146. return true;
  1147. }
  1148. /**
  1149. *
  1150. * @param string $arg_str_session_id
  1151. * @return bool
  1152. */
  1153. public function destroy($arg_str_session_id)
  1154. {
  1155. $arg_str_session_id = $this->session_id;
  1156. setcookie($arg_str_session_id, '');
  1157. return true;
  1158. }
  1159. /**
  1160. *
  1161. * @param string $arg_int_next_lifetime
  1162. * @return bool
  1163. */
  1164. public function gc($arg_int_next_lifetime)
  1165. {
  1166. return true;
  1167. }
  1168. /**
  1169. *
  1170. * @param string $encryption_key
  1171. * @param string $cookie_domain
  1172. * @param string $session_id
  1173. * @return CookieSessionHandler
  1174. */
  1175. public static function getInstance($encryption_key = null, $cookie_domain = '', $session_id = 'omfg')
  1176. {
  1177. if(is_null($encryption_key))
  1178. {
  1179. $encryption_key = defined('COOKIE_ENCRYPTION_KEY') ? COOKIE_ENCRYPTION_KEY : 'abjh23cpi7cz';
  1180. }
  1181. if(is_null(self::$obj_session))
  1182. {
  1183. self::$obj_session = new CookieSessionHandler($encryption_key, $cookie_domain, $session_id);
  1184. if(isset($_SESSION['sess_exp']))
  1185. {
  1186. self::$obj_session->setExpiry($_SESSION['sess_exp']);
  1187. }
  1188. }
  1189. return self::$obj_session;
  1190. }
  1191. /**
  1192. *
  1193. * @param string $in
  1194. * @param string $salt
  1195. * @return string
  1196. */
  1197. public static function cookieCrypt($in, $salt)
  1198. {
  1199. if(empty($in))
  1200. {
  1201. return '';
  1202. }
  1203. $td = mcrypt_module_open('tripledes', '', 'ecb', '');
  1204. $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  1205. mcrypt_generic_init($td, $salt, $iv);
  1206. $cypher = base64_encode(mcrypt_generic($td, $in));
  1207. mcrypt_generic_deinit($td);
  1208. mcrypt_module_close($td);
  1209. if(strlen($cypher) > 4000)
  1210. {
  1211. throw new Exception('cookie data overflow');
  1212. }
  1213. return $cypher;
  1214. }
  1215. /**
  1216. *
  1217. * @param string $in
  1218. * @param string $salt
  1219. * @return string
  1220. */
  1221. public static function cookieDecrypt($in, $salt)
  1222. {
  1223. if(empty($in))
  1224. {
  1225. return '';
  1226. }
  1227. $td = mcrypt_module_open('tripledes', '', 'ecb', '');
  1228. $iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  1229. mcrypt_generic_init($td, $salt, $iv);
  1230. $plain_text = rtrim(mdecrypt_generic($td, base64_decode($in)), "\0");
  1231. mcrypt_generic_deinit($td);
  1232. mcrypt_module_close($td);
  1233. return $plain_text;
  1234. }
  1235. }
  1236. interface CacheInterface
  1237. {
  1238. /**
  1239. *
  1240. * @param string $id
  1241. * @param mixed $value
  1242. * @param integer $ttl
  1243. */
  1244. public function store($id, $value, $ttl);
  1245. /**
  1246. *
  1247. * @param string $id
  1248. * @return mixed
  1249. */
  1250. public function fetch($id);
  1251. /**
  1252. *
  1253. * @param string $id
  1254. */
  1255. public function delete($id);
  1256. }
  1257. class APCCache implements CacheInterface
  1258. {
  1259. private static $instance;
  1260. /**
  1261. *
  1262. * @return APCCache
  1263. */
  1264. public static function getInstance()
  1265. {
  1266. if(is_null(self::$instance))
  1267. {
  1268. self::$instance = new self;
  1269. }
  1270. return self::$instance;
  1271. }
  1272. private function __construct()
  1273. {
  1274. if(!function_exists('apc_store'))
  1275. {
  1276. throw new Exception('APC must be installed to use this backend');
  1277. }
  1278. }
  1279. /**
  1280. * Store value
  1281. *
  1282. * @param string $id Value identifier
  1283. * @param mixed $value Value to be stored
  1284. * @param integer $ttl Cache time to live
  1285. * @return boolean
  1286. */
  1287. public function store($id, $value, $ttl = 0)
  1288. {
  1289. return apc_store($id, $value, $ttl);
  1290. }
  1291. /**
  1292. * Add value. Same as store, but will not overwrite an existing value.
  1293. *
  1294. * @param string $id Value identifier
  1295. * @param mixed $value Value to be stored
  1296. * @param integer $ttl Cache time to live
  1297. * @return boolean
  1298. */
  1299. public function add($id, $value, $ttl = 0)
  1300. {
  1301. if(($val = $this->fetch($id)) === false)
  1302. {
  1303. return $this->store($id, $value, $ttl);
  1304. }
  1305. return false;
  1306. }
  1307. /**
  1308. * Fetch value
  1309. *
  1310. * @param string $id Value identifier
  1311. * @return mixed Returns value or false
  1312. */
  1313. public function fetch($id)
  1314. {
  1315. return apc_fetch($id);
  1316. }
  1317. /**
  1318. * Delete value from cache
  1319. *
  1320. * @param string $id Value identifier
  1321. * @return boolean
  1322. */
  1323. public function delete($id)
  1324. {
  1325. return apc_delete($id);
  1326. }
  1327. }
  1328. class FileCache implements CacheInterface
  1329. {
  1330. private $path;
  1331. /**
  1332. * New file cache
  1333. *
  1334. * @param Array Options are cache path ('path') and wether to create it ('create')
  1335. */
  1336. public function __construct(array $options = null)
  1337. {
  1338. if(!is_array($options))
  1339. {
  1340. $options = array();
  1341. }
  1342. if(!isset($options['path']))
  1343. {
  1344. $options['path'] = sys_get_temp_dir();
  1345. }
  1346. if(!isset($options['create']))
  1347. {
  1348. $options['create'] = false;
  1349. }
  1350. $slash = substr($options['path'], -1);
  1351. if($slash != '/' and $slash !='\\')
  1352. {
  1353. $options['path'] .= '/';
  1354. }
  1355. if($options['create'])
  1356. {
  1357. if(!is_dir($options['path']))
  1358. {
  1359. if(!mkdir($options['path'], 0755, true))
  1360. {
  1361. throw new \shozu\Cache\Exception('directory "' . $options['path'] . '" does ot exist and could not be created.');
  1362. }
  1363. }
  1364. }
  1365. $this->path = $options['path'];
  1366. }
  1367. /**
  1368. * Store value
  1369. *
  1370. * @param string $id Value identifier
  1371. * @param mixed $value Value to be stored
  1372. * @param integer $ttl Cache time to live
  1373. * @return boolean
  1374. */
  1375. public function store($id, $value, $ttl = 0)
  1376. {
  1377. $file = $this->fileName($id);
  1378. if($ttl == 0)
  1379. {
  1380. $expires = 0;
  1381. }
  1382. else
  1383. {
  1384. $expires = time() + (int)$ttl;
  1385. }
  1386. if(file_put_contents($file,$expires
  1387. . "\n" . serialize($value)))
  1388. {
  1389. return true;
  1390. }
  1391. }
  1392. /**
  1393. * Add value. Same as store, only will not overwrite existing value
  1394. *
  1395. * @param string $id Value identifier
  1396. * @param mixed $value Value to be stored
  1397. * @param integer $ttl Cache time to live
  1398. * @return boolean
  1399. */
  1400. public function add($id, $value, $ttl = 0)
  1401. {
  1402. if(($val = $this->fetch($id)) === false)
  1403. {
  1404. return $this->store($id, $value, $ttl);
  1405. }
  1406. return false;
  1407. }
  1408. /**
  1409. * Fetch value
  1410. *
  1411. * @param string $id Value identifier
  1412. * @return mixed Returns value or false
  1413. */
  1414. public function fetch($id)
  1415. {
  1416. $fileName = $this->fileName($id);
  1417. $old = ini_set('error_reporting', 0);
  1418. if(($file = fopen($fileName, 'r')) === false)
  1419. {
  1420. ini_set('error_reporting', $old);
  1421. return false;
  1422. }
  1423. ini_set('error_reporting', $old);
  1424. $expires = (int)fgets($file);
  1425. if($expires > time() or $expires === 0)
  1426. {
  1427. $data = '';
  1428. while(($line = fgets($file)) !== false)
  1429. {
  1430. $data .= $line;
  1431. }
  1432. fclose($file);
  1433. return unserialize($data);
  1434. }
  1435. fclose($file);
  1436. unlink($fileName);
  1437. return false;
  1438. }
  1439. /**
  1440. * Delete value from cache
  1441. *
  1442. * @param string $id Value identifier
  1443. * @return boolean
  1444. */
  1445. public function delete($id)
  1446. {
  1447. $file = $this->fileName($id);
  1448. if(is_file($file))
  1449. {
  1450. return unlink($file);
  1451. }
  1452. return false;
  1453. }
  1454. /**
  1455. * Remove no more valid cache entries
  1456. *
  1457. * @return integer the number of entries removed
  1458. */
  1459. public function clean()
  1460. {
  1461. $erased = 0;
  1462. $files = glob($this->path . '*.cache');
  1463. foreach($files as $file)
  1464. {
  1465. if(($handle = $this->fileHandle($file)) !== false)
  1466. {
  1467. $expires = (int)fgets($handle);
  1468. if($expires < time())
  1469. {
  1470. fclose($handle);
  1471. unlink($file);
  1472. $erased++;
  1473. }
  1474. }
  1475. }
  1476. return $erased;
  1477. }
  1478. private function fileName($id)
  1479. {
  1480. return $this->path . md5($id) . '.cache';
  1481. }
  1482. private function fileHandle($fileName)
  1483. {
  1484. $old = ini_set('error_reporting', 0);
  1485. if(($file = fopen($fileName, 'r')) === false)
  1486. {
  1487. ini_set('error_reporting', $old);
  1488. return false;
  1489. }
  1490. ini_set('error_reporting', $old);
  1491. return $file;
  1492. }
  1493. }
  1494. class Template
  1495. {
  1496. /**
  1497. * String of template file
  1498. */
  1499. private $file;
  1500. /**
  1501. * Array of template variables
  1502. */
  1503. private $vars = array();
  1504. private $cache_id;
  1505. private $cache;
  1506. /**
  1507. * Assign the template path
  1508. *
  1509. * @param string $file Template path (absolute path or path relative to the templates dir)
  1510. * @param array $vars assigned variables
  1511. */
  1512. public function __construct($file, $vars = false)
  1513. {
  1514. $this->file = $file;
  1515. if (!file_exists($this->file))
  1516. {
  1517. throw new Exception("View '{$this->file}' not found!");
  1518. }
  1519. if ($vars !== false)
  1520. {
  1521. $this->vars = $vars;
  1522. }
  1523. }
  1524. /**
  1525. * Assign specific variable to the template
  1526. *
  1527. * <code>
  1528. * // assign single var
  1529. * $view->assign('varname', 'varvalue');
  1530. * // assign array of vars
  1531. * $view->assign(array('varname1' => 'varvalue1', 'varname2' => 'varvalue2'));
  1532. * </code>
  1533. *
  1534. * @param mixed $name Variable name
  1535. * @param mixed $value Variable value
  1536. */
  1537. public function assign($name, $value = null)
  1538. {
  1539. if (is_array($name))
  1540. {
  1541. array_merge($this->vars, $name);
  1542. }
  1543. else
  1544. {
  1545. $this->vars[$name] = $value;
  1546. }
  1547. }
  1548. /**
  1549. * Return template output as string
  1550. *
  1551. * @return string content of compiled view template
  1552. */
  1553. public function render()
  1554. {
  1555. ob_start();
  1556. extract($this->vars, EXTR_SKIP);
  1557. include $this->file;
  1558. $content = ob_get_clean();
  1559. return $content;
  1560. }
  1561. /**
  1562. * Render the content and return it
  1563. *
  1564. * <code>
  1565. * echo new View('blog', array('title' => 'My title'));
  1566. * </code>
  1567. *
  1568. * @return string content of the view
  1569. */
  1570. public function __toString()
  1571. {
  1572. return $this->render();
  1573. }
  1574. /**
  1575. * Escape HTML special chars
  1576. *
  1577. * @param string
  1578. * @return string
  1579. */
  1580. public function escape($string)
  1581. {
  1582. return htmlspecialchars($string);
  1583. }
  1584. /**
  1585. * Limit string to given length but do not truncate words
  1586. *
  1587. * @param string $str input string
  1588. * @param integer $length length limit
  1589. * @param integer $minword
  1590. * @return string
  1591. */
  1592. public function limit($str, $length, $minword = 3)
  1593. {
  1594. $sub = '';
  1595. $len = 0;
  1596. foreach (explode(' ', $str) as $word)
  1597. {
  1598. $part = (($sub != '') ? ' ' : '') . $word;
  1599. $sub .= $part;
  1600. $len += strlen($part);
  1601. if (strlen($word) > $minword && strlen($sub) >= $length)
  1602. {
  1603. break;
  1604. }
  1605. }
  1606. return $sub . (($len < strlen($str)) ? '...' : '');
  1607. }
  1608. /**
  1609. * Multibyte-aware ucfirst.
  1610. *
  1611. * Uppercase first letter
  1612. *
  1613. * @param string $str
  1614. * @param string $e encoding, defaults to utf-8
  1615. * @return string
  1616. */
  1617. public function ucfirst($str, $e = 'utf-8')
  1618. {
  1619. $fc = mb_strtoupper(mb_substr($str, 0, 1, $e), $e);
  1620. return $fc . mb_substr($str, 1, mb_strlen($str, $e), $e);
  1621. }
  1622. /**
  1623. * Cache portions of a view. Usage:
  1624. *
  1625. * <code>
  1626. * <?php if($this->cacheBegin('myCacheId')){ ?>
  1627. * <!-- some dynamic content here will be cached for 600 seconds -->
  1628. * <?php $this->cacheEnd(600);} ?>
  1629. * </code>
  1630. *
  1631. * @param string $id
  1632. * @return boolean
  1633. */
  1634. public function cacheBegin($id)
  1635. {
  1636. if(is_null($this->cache))
  1637. {
  1638. return false;
  1639. }
  1640. $cache = $this->cache;
  1641. $this->cache_id = $id;
  1642. if(($contentFromCache = $cache->fetch($id)) === false)
  1643. {
  1644. ob_start();
  1645. return true;
  1646. }
  1647. else
  1648. {
  1649. echo $contentFromCache;
  1650. return false;
  1651. }
  1652. }
  1653. /**
  1654. *
  1655. * @param integer $ttl
  1656. */
  1657. public function cacheEnd($ttl = 0)
  1658. {
  1659. if(is_null($this->cache))
  1660. {
  1661. return;
  1662. }
  1663. $cache = $this->cache;
  1664. if(($contentFromCache = $cache->fetch($this->cache_id)) === false)
  1665. {
  1666. $contentToCache = ob_get_contents();
  1667. $cache->store($this->cache_id, $contentToCache, $ttl);
  1668. ob_end_clean();
  1669. echo $contentToCache;
  1670. }
  1671. else
  1672. {
  1673. ob_end_clean();
  1674. }
  1675. }
  1676. public function setCache(CacheInterface $cache)
  1677. {
  1678. $this->cache = $cache;
  1679. }
  1680. }
  1681. class Benchmark
  1682. {
  1683. public static $marks = array();
  1684. public static $enabled = false;
  1685. /**
  1686. * Benchmark start point
  1687. *
  1688. * @param string $name point name
  1689. * @return boolean
  1690. */
  1691. public static function start($name)
  1692. {
  1693. if (!self::$enabled)
  1694. {
  1695. return false;
  1696. }
  1697. if (!isset(self::$marks[$name]))
  1698. {
  1699. self::$marks[$name] = array(
  1700. 'start' => microtime(true) ,
  1701. 'stop' => false,
  1702. 'memory_start' => function_exists('memory_get_usage') ? memory_get_usage() : 0,
  1703. 'memory_stop' => false
  1704. );
  1705. }
  1706. return true;
  1707. }
  1708. /**
  1709. * Benchmark stop point
  1710. *
  1711. * @param string $name point name
  1712. * @return boolean
  1713. */
  1714. public static function stop($name)
  1715. {
  1716. if (!self::$enabled)
  1717. {
  1718. return false;
  1719. }
  1720. if (isset(self::$marks[$name]))
  1721. {
  1722. self::$marks[$name]['stop'] = microtime(true);
  1723. self::$marks[$name]['memory_stop'] = function_exists('memory_get_usage') ? memory_get_usage() : 0;
  1724. }
  1725. return true;
  1726. }
  1727. /**
  1728. * Get the elapsed time between a start and stop of a mark name, TRUE for all.
  1729. *
  1730. * @param string $name
  1731. * @param integer $decimals
  1732. * @return array
  1733. */
  1734. public static function get($name, $decimals = 4)
  1735. {
  1736. if (!self::$enabled)
  1737. {
  1738. return false;
  1739. }
  1740. if ($name === true)
  1741. {
  1742. $times = array();
  1743. foreach(array_keys(self::$marks) as $name)
  1744. {
  1745. $times[$name] = self::get($name, $decimals);
  1746. }
  1747. return $times;
  1748. }
  1749. if (!isset(self::$marks[$name]))
  1750. {
  1751. return false;
  1752. }
  1753. if (self::$marks[$name]['stop'] === false)
  1754. {
  1755. self::stop($name);
  1756. }
  1757. return array(
  1758. 'time' => number_format(self::$marks[$name]['stop'] - self::$marks[$name]['start'], $decimals) ,
  1759. 'memory' => self::convert_size(self::$marks[$name]['memory_stop'] - self::$marks[$name]['memory_start'])
  1760. );
  1761. }
  1762. /**
  1763. * Convert byte size in human readable format
  1764. *
  1765. * @param integer
  1766. * @return string
  1767. */
  1768. public static function convert_size($num)
  1769. {
  1770. if ($num >= 1073741824)
  1771. {
  1772. $num = round($num / 1073741824 * 100) / 100 . ' gb';
  1773. }
  1774. else if ($num >= 1048576)
  1775. {
  1776. $num = round($num / 1048576 * 100) / 100 . ' mb';
  1777. }
  1778. else if ($num >= 1024)
  1779. {
  1780. $num = round($num / 1024 * 100) / 100 . ' kb';
  1781. }
  1782. else
  1783. {
  1784. $num.= ' b';
  1785. }
  1786. return $num;
  1787. }
  1788. /**
  1789. * Generate HTML-formatted report
  1790. *
  1791. * @return string
  1792. */
  1793. public static function htmlReport()
  1794. {
  1795. if (!self::$enabled)
  1796. {
  1797. return '';
  1798. }
  1799. $html = '<div style="font-size:14px;font-family:monospace;"><ol>';
  1800. foreach(self::get(true) as $key => $val)
  1801. {
  1802. $html.= '<li><strong>' . htmlspecialchars($key) . '</strong><br/>time&nbsp;&nbsp;: ' . $val['time'] . '<br/>memory: ' . $val['memory'] . '</li>';
  1803. }
  1804. return $html . '</ol></div>';
  1805. }
  1806. /**
  1807. * Generate CLI/text formatted report
  1808. *
  1809. * @return string
  1810. */
  1811. public static function cliReport()
  1812. {
  1813. $output = '';
  1814. if (!self::$enabled)
  1815. {
  1816. return $output;
  1817. }
  1818. $points = self::get(true);
  1819. if (!empty($points))
  1820. {
  1821. $output.= "\n#### Benchmark ####\n";
  1822. foreach($points as $key => $val)
  1823. {
  1824. $output.= "\n[ " . $key . " ]\n time: " . $val['time'] . "\n memory: " . $val['memory'] . "\n";
  1825. }
  1826. }
  1827. return $output;
  1828. }
  1829. /**
  1830. * Enable benchmark
  1831. *
  1832. * @return boolean state
  1833. */
  1834. public static function enable()
  1835. {
  1836. self::$enabled = true;
  1837. return self::$enabled;
  1838. }
  1839. /**
  1840. * Disable benchmark
  1841. *
  1842. * @return boolean state
  1843. */
  1844. public static function disable()
  1845. {
  1846. self::$enabled = false;
  1847. return self::$enabled;
  1848. }
  1849. }
  1850. class MockRequest implements RequestInterface
  1851. {
  1852. private $date_time;
  1853. private $cookie = array();
  1854. private $post = array();
  1855. private $get = array();
  1856. private $server = array();
  1857. private $session = array();
  1858. private $params = array();
  1859. private $body = '';
  1860. private $files = array();
  1861. private $request_method = 'GET';
  1862. private $requested_url = '/';
  1863. public function __construct()
  1864. {
  1865. $this->date_time = \DateTime::createFromFormat('Y-m-d H:i:s', time('Y-m-d H:i:s'));
  1866. }
  1867. /**
  1868. *
  1869. * @return string
  1870. */
  1871. public function getRequestedUrl()
  1872. {
  1873. return $this->requested_url;
  1874. }
  1875. /**
  1876. * @return \DateTime
  1877. */
  1878. public function getDateTime()
  1879. {
  1880. return $this->date_time;
  1881. }
  1882. /**
  1883. *
  1884. * @return string
  1885. */
  1886. public function getRequestMethod()
  1887. {
  1888. return $this->request_method;
  1889. }
  1890. /**
  1891. *
  1892. * @param string $http_verb
  1893. * @return MockRequest
  1894. */
  1895. public function setRequestMethod($http_verb)
  1896. {
  1897. $this->request_method = $http_verb;
  1898. return $this;
  1899. }
  1900. /**
  1901. * @return string
  1902. */
  1903. public function getCookieVar($cookie_name)
  1904. {
  1905. if(isset($this->cookie[$cookie_name]))
  1906. {
  1907. return $this->cookie[$cookie_name];
  1908. }
  1909. }
  1910. /**
  1911. *
  1912. * @param string $cookie_name
  1913. * @param string $cookie_value
  1914. * @return MockRequest
  1915. */
  1916. public function setCookieVar($cookie_name, $cookie_value)
  1917. {

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