PageRenderTime 67ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/webcore/webcore.web.php

#
PHP | 2840 lines | 1581 code | 298 blank | 961 comment | 114 complexity | abb435e1948727a2e20de1d52ac286c2 MD5 | raw file
  1. <?php
  2. /**
  3. * @package WebCore
  4. * @subpackage Web
  5. *
  6. *
  7. *
  8. * @author Mario Di Vece <mario@unosquare.com>
  9. * @author Geovanni Perez <geovanni.perez@unosquare.com>
  10. * @copyright Copyright (c) 2008-2009, Author(s) above
  11. */
  12. require_once "webcore.php";
  13. require_once "webcore.imaging.php";
  14. /**
  15. * All Http handlers must implement this interface.
  16. * @package WebCore
  17. * @subpackage Web
  18. */
  19. interface IHttpHandler extends IObject
  20. {
  21. function handleRequest();
  22. }
  23. /**
  24. * Defines the methods required for a session handler.
  25. * @package WebCore
  26. * @subpackage Web
  27. */
  28. interface ISessionHandler extends ISingleton
  29. {
  30. /**
  31. * @param string $savePath
  32. * @param string $sessionName
  33. * @return bool
  34. */
  35. public static function open($savePath, $sessionName);
  36. /**
  37. * @return bool
  38. */
  39. public static function close();
  40. /**
  41. * @param string $sessionId
  42. * @return string
  43. */
  44. public static function read($sessionId);
  45. /**
  46. * @param string $sessionId
  47. * @param string $sessionData
  48. * @return bool
  49. */
  50. public static function write($sessionId, $sessionData);
  51. /**
  52. * @param string $sessionId
  53. * @return bool
  54. */
  55. public static function destroy($sessionId);
  56. /**
  57. * @param int $maxLifetime the number of seconds the session exists for
  58. * @return bool
  59. */
  60. public static function gc($maxLifetime);
  61. }
  62. /**
  63. * Cookie management singleton.
  64. * @todo Create CookieContainer class to match path and domain otherwise deleteCookie does not work!
  65. * @package WebCore
  66. * @subpackage Web
  67. */
  68. class CookieManager extends SerializableObjectBase implements ISingleton
  69. {
  70. /**
  71. * Represents the instance of the singleton object
  72. *
  73. * @var CookieManager
  74. */
  75. protected static $__instance = null;
  76. /**
  77. * @var KeyedCollection
  78. */
  79. protected static $__internalCollection;
  80. /**
  81. * Creates a new instance of this class.
  82. */
  83. protected function __construct()
  84. {
  85. self::$__internalCollection = new KeyedCollectionWrapper($_COOKIE, false);
  86. }
  87. /**
  88. * Gets a unique cookie key based on it name, path, and domain.
  89. * @param string $name
  90. * @param string $path
  91. * @param string $domain
  92. */
  93. protected static function getCookieId($name, $path, $domain)
  94. {
  95. return $domain . $path . $name;
  96. }
  97. /**
  98. * Sets or registers a cookie value given its identifier and value.
  99. * @param string $name
  100. * @param mixed $value
  101. * @param string $path Specify an empty string to make this cookie valid only for the current folder.
  102. * @param string $domain Leave empty to specify the cookie is valid for the entire domain.
  103. * @param string $expires The UNIX string representation of a time. The expiration timestamp is calculated using the strtotime function.
  104. * @param bool $secure
  105. * @param bool $httpOnly Prevents access to the cookie on the client-side (i.e. XSS attacks)
  106. * @return bool Returns true if the cookie was successfully set.
  107. */
  108. public function setCookie($name, $value, $path = '/', $domain = '', $expires = '+30 days', $secure = false, $httpOnly = false)
  109. {
  110. $cookieId = self::getCookieId($name, $path, $domain);
  111. return setcookie($cookieId, $value, strtotime($expires), $path, $domain, $secure, $httpOnly);
  112. }
  113. /**
  114. * Deletes the cookie given its name, path and domain.
  115. * Note that the path and domain must match the original intended cookie for this method to not throw an exception.
  116. * @param string $name
  117. * @param string $path
  118. * @param string $domain
  119. * @return bool Returns true if the cookie was successfully deleted (an expiration time in the past is set).
  120. */
  121. public function deleteCookie($name, $path = '/', $domain = '')
  122. {
  123. $cookieId = self::getCookieId($name, $path, $domain);
  124. if (!$this->isCookieSet($name, $path, $domain))
  125. throw new SystemException(SystemException::EX_INVALIDKEY, "Could not delete cookie with id '$cookieId'. It does not exist.");
  126. $this->getCookies()->removeItem($cookieId);
  127. return setcookie($cookieId, '', 1, $path, $domain);
  128. }
  129. /**
  130. * Gets the value stored within a cookie.
  131. * @param string $name The name of the cookie
  132. * @param string $path The path for which the cookie is valid.
  133. * @param string $domain The domain for which the cookie is available.
  134. *
  135. * @return mixed
  136. */
  137. public function getCookieValue($name, $path = '/', $domain = '')
  138. {
  139. $cookieId = self::getCookieId($name, $path, $domain);
  140. return $this->getCookies()->getValue($cookieId);
  141. }
  142. /**
  143. * Provides direct access to the cookies collection.
  144. * Use the provided cookie methods instead for better cookie management.
  145. * @return KeyedCollection
  146. */
  147. public function getCookies()
  148. {
  149. return self::$__internalCollection;
  150. }
  151. /**
  152. * Determines whether the cokkie with a given name has been set.
  153. * @return bool
  154. */
  155. public function isCookieSet($name, $path = '/', $domain = '')
  156. {
  157. $cookieId = self::getCookieId($name, $path, $domain);
  158. return $this->getCookies()->keyExists($cookieId);
  159. }
  160. /**
  161. * Creates a default instance of this class.
  162. * @return CookieManager
  163. */
  164. public static function createInstance()
  165. {
  166. return self::getInstance();
  167. }
  168. /**
  169. * Gets the singleton instance for this class
  170. *
  171. * @return CookieManager
  172. */
  173. public static function getInstance()
  174. {
  175. if (self::isLoaded() === false)
  176. self::$__instance = new CookieManager();
  177. return self::$__instance;
  178. }
  179. /**
  180. * Determines whether the singleton has loaded its instance
  181. *
  182. * @return bool
  183. */
  184. public static function isLoaded()
  185. {
  186. if (is_null(self::$__instance))
  187. return false;
  188. return true;
  189. }
  190. }
  191. /**
  192. * Provides a database-agnostic session handler.
  193. * This session ehandler expects a table structure accessible from the data context.
  194. * WARNING: If the table is not found, it will be automatically created
  195. * Tabe Name: AppSessions (use setDbTableName to change this before calling the HttpContext::initialize method)
  196. * Column: SessionId VARCHAR(255), Primary key
  197. * Column: SessionData Text
  198. * Column: SessionExpires Int32
  199. * Standard ISO SQL command
  200. * CREATE TABLE AppSessions (
  201. SessionId varchar(255) NOT NULL,
  202. SessionData text NOT NULL,
  203. SessionExpires int NOT NULL,
  204. PRIMARY KEY (SessionId)
  205. )
  206. * @package WebCore
  207. * @subpackage Web
  208. */
  209. class DatabaseSessionHandler implements ISessionHandler
  210. {
  211. const DB_TABLENAME = 'AppSessions';
  212. private static $dbTableName = self::DB_TABLENAME;
  213. /**
  214. * Gets the database table name on which sessions are stored
  215. */
  216. public static function getDbTableName()
  217. {
  218. return self::$dbTableName;
  219. }
  220. /**
  221. * Sets the database table name on which sessions are stored
  222. */
  223. public static function setDbTableName($value)
  224. {
  225. self::$dbTableName = $value;
  226. }
  227. /**
  228. * Gets whether the instance of this singleton has been loaded.
  229. * @return bool
  230. */
  231. public static function isLoaded()
  232. {
  233. return true;
  234. }
  235. /**
  236. * Gets the instance of this singleton
  237. * @return eAcceleratorSessionHandler
  238. */
  239. public static function getInstance()
  240. {
  241. return new DatabaseSessionHandler();
  242. }
  243. /**
  244. * Gets the reflectionclass for this type.
  245. * @return ReflectionClass
  246. */
  247. public function getType()
  248. {
  249. return ReflectionClass(__CLASS__);
  250. }
  251. /**
  252. * @param string $savePath
  253. * @param string $sessionName
  254. * @return bool
  255. */
  256. public static function open($savePath, $sessionName)
  257. {
  258. $originalLogLevel = LogManager::getLogLevel();
  259. LogManager::setLogLevel(LogManager::LOG_LEVEL_DISABLED);
  260. $found = false;
  261. $foundCol = new IndexedCollection();
  262. try
  263. {
  264. $sql = "SELECT * FROM information_schema.tables WHERE TABLE_NAME LIKE ?";
  265. $command = DataContext::getInstance()->getConnection()->createCommand();
  266. $command->setCommandText($sql);
  267. $command->addQuotedParam('tableName', self::getDbTableName());
  268. $foundCol = DataContext::getInstance()->executeQuery($command);
  269. }
  270. catch (Exception $ex)
  271. {
  272. $exString = "<pre>DatabseSessionHandler Exception\nA default database needs to be configured in the app.settings file.\n"
  273. . $ex->getLine() . " on '" . $ex->getFile() . "'\n"
  274. . $ex->getCode() . ": " . $ex->getMessage() . "\nStack Trace:\n" . $ex->getTraceAsString() . "</pre>";
  275. LogManager::setLogLevel($originalLogLevel);
  276. HttpResponse::write($exString);
  277. HttpResponse::end();
  278. return false;
  279. }
  280. $found = $foundCol->getCount() > 0;
  281. if (!$found)
  282. {
  283. $quotedTableName = DataContext::getInstance()->getConnection()->quoteIdentifier(self::getDbTableName());
  284. $sql = "CREATE TABLE $quotedTableName ( SessionId varchar(255) NOT NULL, SessionData text NOT NULL, SessionExpires int NOT NULL, PRIMARY KEY (SessionId) )";
  285. $command = DataContext::getInstance()->getConnection()->createCommand();
  286. $command->setCommandText($sql);
  287. $sessionData = DataContext::getInstance()->executeNonQuery($command);
  288. }
  289. LogManager::setLogLevel($originalLogLevel);
  290. return true;
  291. }
  292. /**
  293. * @return bool
  294. */
  295. public static function close()
  296. {
  297. return true;
  298. }
  299. /**
  300. * @param string $sessionId
  301. * @return string
  302. */
  303. public static function read($sessionId)
  304. {
  305. $originalLogLevel = LogManager::getLogLevel();
  306. LogManager::setLogLevel(LogManager::LOG_LEVEL_DISABLED);
  307. try
  308. {
  309. $quotedTableName = DataContext::getInstance()->getConnection()->quoteIdentifier(self::getDbTableName());
  310. $sql = "SELECT SessionData FROM $quotedTableName WHERE SessionId = ?";
  311. $command = DataContext::getInstance()->getConnection()->createCommand();
  312. $command->setCommandText($sql);
  313. $command->addQuotedParam('sessionId', $sessionId);
  314. $sessionData = DataContext::getInstance()->executeScalar($command);
  315. if (is_null($sessionData))
  316. {
  317. LogManager::setLogLevel($originalLogLevel);
  318. return '';
  319. }
  320. else
  321. {
  322. LogManager::setLogLevel($originalLogLevel);
  323. return base64_decode($sessionData);
  324. }
  325. }
  326. catch (Exception $ex)
  327. {
  328. $exString = "<pre>DatabseSessionHandler Exception\nUnable to read session record from database.\n"
  329. . $ex->getLine() . " on '" . $ex->getFile() . "'\n"
  330. . $ex->getCode() . ": " . $ex->getMessage() . "\nStack Trace:\n" . $ex->getTraceAsString() . "</pre>";
  331. LogManager::setLogLevel($originalLogLevel);
  332. HttpResponse::write($exString);
  333. HttpResponse::end();
  334. return null;
  335. }
  336. }
  337. /**
  338. * Writes session data to the database
  339. * @param string $sessionId
  340. * @param string $sessionData
  341. * @return bool
  342. */
  343. public static function write($sessionId, $sessionData)
  344. {
  345. $originalLogLevel = LogManager::getLogLevel();
  346. LogManager::setLogLevel(LogManager::LOG_LEVEL_DISABLED);
  347. try
  348. {
  349. $quotedTableName = DataContext::getInstance()->getConnection()->quoteIdentifier(self::getDbTableName());
  350. $sql = "SELECT COUNT(*) AS __COUNT__ FROM $quotedTableName WHERE SessionId = ?";
  351. $command = DataContext::getInstance()->getConnection()->createCommand();
  352. $command->setCommandText($sql);
  353. $command->addQuotedParam('sessionId', $sessionId);
  354. $foundSession = DataContext::getInstance()->executeScalar($command);
  355. $command = DataContext::getInstance()->getConnection()->createCommand();
  356. if ($foundSession == '0')
  357. {
  358. $sql = "INSERT INTO $quotedTableName (SessionId, SessionData, SessionExpires) VALUES (?, ?, ?)";
  359. $command->addQuotedParam('sessionId', $sessionId);
  360. $command->addQuotedParam('sessionData', base64_encode($sessionData));
  361. $command->addQuotedParam('sessionExpires', time());
  362. }
  363. else
  364. {
  365. $sql = "UPDATE $quotedTableName SET SessionData = ?, SessionExpires = ? WHERE SessionId = ?";
  366. $command->addQuotedParam('sessionData', base64_encode($sessionData));
  367. $command->addQuotedParam('sessionExpires', time());
  368. $command->addQuotedParam('sessionId', $sessionId);
  369. }
  370. $command->setCommandText($sql);
  371. DataContext::getInstance()->executeNonQuery($command);
  372. }
  373. catch (Exception $ex)
  374. {
  375. $exString = "<pre>DatabseSessionHandler Exception\nUnable to write session record to database.\n"
  376. . $ex->getLine() . " on '" . $ex->getFile() . "'\n"
  377. . $ex->getCode() . ": " . $ex->getMessage() . "\nStack Trace:\n" . $ex->getTraceAsString() . "</pre>";
  378. LogManager::setLogLevel($originalLogLevel);
  379. HttpResponse::write($exString);
  380. HttpResponse::end();
  381. return false;
  382. }
  383. LogManager::setLogLevel($originalLogLevel);
  384. return true;
  385. }
  386. /**
  387. * @param string $sessionId
  388. * @return bool
  389. */
  390. public static function destroy($sessionId)
  391. {
  392. $originalLogLevel = LogManager::getLogLevel();
  393. LogManager::setLogLevel(LogManager::LOG_LEVEL_DISABLED);
  394. try
  395. {
  396. $quotedTableName = DataContext::getInstance()->getConnection()->quoteIdentifier(self::getDbTableName());
  397. $sql = "DELETE FROM $quotedTableName WHERE SessionId = ?";
  398. $command = DataContext::getInstance()->getConnection()->createCommand();
  399. $command->setCommandText($sql);
  400. $command->addQuotedParam('sessionId', $sessionId);
  401. DataContext::getInstance()->executeNonQuery($command);
  402. }
  403. catch (Exception $ex)
  404. {
  405. $exString = "<pre>DatabseSessionHandler Exception\nUnable to destroy session record.\n"
  406. . $ex->getLine() . " on '" . $ex->getFile() . "'\n"
  407. . $ex->getCode() . ": " . $ex->getMessage() . "\nStack Trace:\n" . $ex->getTraceAsString() . "</pre>";
  408. LogManager::setLogLevel($originalLogLevel);
  409. HttpResponse::write($exString);
  410. HttpResponse::end();
  411. return false;
  412. }
  413. LogManager::setLogLevel($originalLogLevel);
  414. return true;
  415. }
  416. /**
  417. * @param int $maxLifetime the number of seconds the session exists for
  418. * @return bool
  419. */
  420. public static function gc($maxLifetime)
  421. {
  422. $originalLogLevel = LogManager::getLogLevel();
  423. LogManager::setLogLevel(LogManager::LOG_LEVEL_DISABLED);
  424. try
  425. {
  426. $quotedTableName = DataContext::getInstance()->getConnection()->quoteIdentifier(self::getDbTableName());
  427. $deleteFilter = time() - $maxLifetime;
  428. $sql = "DELETE FROM $quotedTableName WHERE SessionExpires < ?";
  429. $command = DataContext::getInstance()->getConnection()->createCommand();
  430. $command->setCommandText($sql);
  431. $command->addQuotedParam('sessionExpires', time());
  432. DataContext::getInstance()->executeNonQuery($command);
  433. }
  434. catch (Exception $ex)
  435. {
  436. $exString = "<pre>DatabseSessionHandler Exception\nUnable to perform session garbage collection.\n"
  437. . $ex->getLine() . " on '" . $ex->getFile() . "'\n"
  438. . $ex->getCode() . ": " . $ex->getMessage() . "\nStack Trace:\n" . $ex->getTraceAsString() . "</pre>";
  439. LogManager::setLogLevel($originalLogLevel);
  440. HttpResponse::write($exString);
  441. HttpResponse::end();
  442. return false;
  443. }
  444. LogManager::setLogLevel($originalLogLevel);
  445. return true;
  446. }
  447. }
  448. /**
  449. * Provides a session handler for eAccelerator-enabled web servers.
  450. * @package WebCore
  451. * @subpackage Web
  452. */
  453. class eAcceleratorSessionHandler implements ISessionHandler
  454. {
  455. protected static $sessionName;
  456. /**
  457. * Gets whether the instance of this singleton has been loaded.
  458. * @return bool
  459. */
  460. public static function isLoaded()
  461. {
  462. return true;
  463. }
  464. /**
  465. * Gets the instance of this singleton
  466. * @return eAcceleratorSessionHandler
  467. */
  468. public static function getInstance()
  469. {
  470. return new eAcceleratorSessionHandler();
  471. }
  472. /**
  473. * Gets the reflectionclass for this type.
  474. * @return ReflectionClass
  475. */
  476. public function getType()
  477. {
  478. return ReflectionClass(__CLASS__);
  479. }
  480. /**
  481. * @param string $savePath
  482. * @param string $sessionName
  483. * @return bool
  484. */
  485. public static function open($savePath, $sessionName)
  486. {
  487. self::$sessionName = $sessionName;
  488. return true;
  489. }
  490. /**
  491. * @return bool
  492. */
  493. public static function close()
  494. {
  495. return true;
  496. }
  497. /**
  498. * @param string $sessionId
  499. * @return string
  500. */
  501. public static function read($sessionId)
  502. {
  503. return eaccelerator_get(self::$sessionName . '_' . $sessionId);
  504. }
  505. /**
  506. * @param string $sessionId
  507. * @param string $sessionData
  508. * @return bool
  509. */
  510. public static function write($sessionId, $sessionData)
  511. {
  512. $ttl = session_cache_limiter() * 60;
  513. if ($ttl <= 0)
  514. $ttl = 30 * 60;
  515. return eaccelerator_put(self::$sessionName . '_' . $sessionId, $sessionData, $ttl);
  516. }
  517. /**
  518. * @param string $sessionId
  519. * @return bool
  520. */
  521. public static function destroy($sessionId)
  522. {
  523. return eaccelerator_rm(self::$sessionName . '_' . $sessionId);
  524. }
  525. /**
  526. * @param int $maxLifetime the number of seconds the session exists for
  527. * @return bool
  528. */
  529. public static function gc($maxLifetime)
  530. {
  531. eaccelerator_gc();
  532. return true;
  533. }
  534. }
  535. /**
  536. * Singleton class representing the current request's session state
  537. * The class should not be used on its own but rather accessed through
  538. * the HttpContext object.
  539. *
  540. * @package WebCore
  541. * @subpackage Web
  542. */
  543. class HttpSession extends KeyedCollectionBase implements ISingleton
  544. {
  545. protected function __construct()
  546. {
  547. $appSettings = Settings::getValue(Settings::SKEY_APPLICATION);
  548. $handler = isset($appSettings[Settings::KEY_APPLICATION_SESSIONHANDLER]) ? $appSettings[Settings::KEY_APPLICATION_SESSIONHANDLER] : '';
  549. if ($handler != '')
  550. {
  551. session_set_save_handler(array(
  552. $handler,
  553. 'open'
  554. ), array(
  555. $handler,
  556. 'close'
  557. ), array(
  558. $handler,
  559. 'read'
  560. ), array(
  561. $handler,
  562. 'write'
  563. ), array(
  564. $handler,
  565. 'destroy'
  566. ), array(
  567. $handler,
  568. 'gc'
  569. ));
  570. }
  571. session_start();
  572. parent::__construct($_SESSION, false);
  573. }
  574. /**
  575. * Regenerates the current session Id
  576. * Returns true is successful, false if failure.
  577. *
  578. * @return bool
  579. */
  580. public static function regenerateSessionId()
  581. {
  582. return session_regenerate_id();
  583. }
  584. /**
  585. * gets the current session identifier
  586. *
  587. * @return string
  588. */
  589. public static function getSessionId()
  590. {
  591. return session_id();
  592. }
  593. /**
  594. * Represents the instance of the singleton object
  595. *
  596. * @var HttpSession
  597. */
  598. private static $__instance = null;
  599. /**
  600. * Gets the singleton instance for this class
  601. *
  602. * @return HttpSession
  603. */
  604. public static function getInstance()
  605. {
  606. if (self::isLoaded() === false)
  607. self::$__instance = new HttpSession();
  608. return self::$__instance;
  609. }
  610. /**
  611. * Determines whether the singleton has loaded its instance
  612. *
  613. * @return bool
  614. */
  615. public static function isLoaded()
  616. {
  617. if (is_null(self::$__instance))
  618. return false;
  619. return true;
  620. }
  621. /**
  622. * Creates a default instance of this class
  623. *
  624. * @return HttpSession
  625. */
  626. public static function createInstance()
  627. {
  628. return self::getInstance();
  629. }
  630. /**
  631. * Clears all the session variables
  632. */
  633. public function clear()
  634. {
  635. session_unset();
  636. }
  637. /**
  638. * Destroys the session and all data associated with it. this is equivalent to calling session_destroy()
  639. */
  640. public function destroy()
  641. {
  642. session_destroy();
  643. }
  644. /**
  645. * Registers an object -or array- for in-session persistence.
  646. * If the key does not exist, it creates it with the passed $object
  647. * If the key already exists, then $object is set to the contents of the key
  648. * @example $obj = new StdClass(); HttpContext::getSession()->registerPersistentObject('myKey', $obj); $obj->prop1 = 'myProp1Value';
  649. * @param string $keyName
  650. * @param object $object
  651. * @return int Returns 0 if the key did not exist before. Returns 1 if the key existed before.
  652. */
  653. public static function registerPersistentObject($keyName, &$object)
  654. {
  655. if (!is_object($object) && !is_array($object))
  656. throw new SystemException(SystemException::EX_INVALIDPARAMETER, 'Parameter $object must be an instance of an object or an array.');
  657. if (!is_string($keyName))
  658. throw new SystemException(SystemException::EX_INVALIDPARAMETER, 'Parameter $keyName must be a string');
  659. $session = self::getInstance();
  660. if ($session->keyExists($keyName) === false)
  661. {
  662. $session->setValue($keyName, $object);
  663. return 0;
  664. }
  665. else
  666. {
  667. $object = HttpContext::getSession()->getValue($keyName);
  668. return 1;
  669. }
  670. }
  671. }
  672. /**
  673. * The singleton response to output headers
  674. *
  675. * @package WebCore
  676. * @subpackage Web
  677. */
  678. class HttpResponse extends ObjectBase implements ISingleton
  679. {
  680. /*
  681. @todo Add all the response codes to constants http://www.krisjordan.com/php-class-for-http-response-status-codes/
  682. */
  683. const HTTP_RESPONSE_CODE_404 = '404 Not Found';
  684. const HTTP_RESPONSE_CODE_403 = '403 Forbidden';
  685. /**
  686. * Represents the instance of the singleton object
  687. *
  688. * @var HttpResponse
  689. */
  690. private static $__instance = null;
  691. /**
  692. * Gets the singleton instance for this class.
  693. *
  694. * @return HttpResponse
  695. */
  696. public static function getInstance()
  697. {
  698. if (self::isLoaded() === false)
  699. self::$__instance = new HttpResponse();
  700. return self::$__instance;
  701. }
  702. /**
  703. * Determines whether the singleton has loaded its instance
  704. *
  705. * @return bool
  706. */
  707. public static function isLoaded()
  708. {
  709. if (is_null(self::$__instance))
  710. return false;
  711. return true;
  712. }
  713. /**
  714. * Writes content directly to the response's output stream.
  715. * Use the getMarkupWriter method to output HTML easily.
  716. */
  717. public static function write($content)
  718. {
  719. echo $content;
  720. }
  721. /**
  722. * Writes content directly to the response's output stream, appending both, a carriage return and a line feed character (CRLF).
  723. * Use the getMarkupWriter method to output HTML easily.
  724. */
  725. public static function writeLine($content)
  726. {
  727. echo $content . "\r\n";
  728. }
  729. /**
  730. * Ends the response immediately.
  731. * WARNING: If output buffering is on, you must call the outputBufferFlush method in order to produce some output.
  732. */
  733. public static function end()
  734. {
  735. exit(0);
  736. }
  737. /**
  738. * Gets the output markup writer.
  739. * @return MarkupWriter
  740. */
  741. public static function getMarkupWriter()
  742. {
  743. return HtmlWriter::getInstance();
  744. }
  745. /**
  746. * Redirects to the given URL
  747. * @param string $url
  748. * @param array $params
  749. */
  750. public static function redirect($url, $params = null)
  751. {
  752. $queryString = '';
  753. if (is_null($params) === false)
  754. {
  755. $queryString = '?';
  756. $paramNames = array_keys($params);
  757. foreach ($paramNames as $param)
  758. {
  759. $queryString .= $param . '=' . urlencode($params[$param]) . '&';
  760. }
  761. }
  762. self::appendHeader('Location', $url . $queryString);
  763. HttpResponse::end();
  764. }
  765. /**
  766. * Turns output buffering on.
  767. */
  768. public static function outputBufferStart()
  769. {
  770. ob_start();
  771. }
  772. /**
  773. * Flushes the output buffer; You must call the outputBufferstart function before you call this method.
  774. */
  775. public static function outputBufferFlush()
  776. {
  777. ob_end_flush();
  778. }
  779. /**
  780. * Gets the length in bytes of the output buffer.
  781. *
  782. * @return int
  783. */
  784. public static function outputBufferGetLength()
  785. {
  786. return ob_get_length();
  787. }
  788. /**
  789. * Clears the contents of the output buffer
  790. *
  791. */
  792. public static function clearOutputBuffer()
  793. {
  794. ob_end_clean();
  795. }
  796. /**
  797. * Returns the contents of the output buffer
  798. *
  799. * @return string
  800. */
  801. public static function getOutputBuffer()
  802. {
  803. return ob_get_contents();
  804. }
  805. /**
  806. * Adds a header to the response headers.
  807. *
  808. * @param string $headerName
  809. * @param string $headerValue
  810. */
  811. public static function appendHeader($headerName, $headerValue)
  812. {
  813. header($headerName . ': ' . $headerValue);
  814. }
  815. /**
  816. * Sets the response code for the Current HttpRequest
  817. *
  818. * @param string $responseCode. One of the HTTP_RESPONSE_CODE_* prefixes constants
  819. */
  820. public static function setResponseCode($responseCode)
  821. {
  822. header('HTTP/1.0 ' . $responseCode);
  823. }
  824. /**
  825. * Sets a Last-Modified header.
  826. * use strtotime function to obtain timestamps from ISO-compliant dates.
  827. * @param int $timestamp
  828. */
  829. public static function setLastModified($timestamp)
  830. {
  831. $timestampStr = gmdate("D, d M Y H:i:s", $timestamp);
  832. self::appendHeader('Expires', $timestampStr . ' GMT');
  833. }
  834. /**
  835. * Sets the Expires header given an offset in minutes.
  836. *
  837. * @param int $minutesFromNow The parameter can be a negative integer.
  838. */
  839. public static function setExpires($minutesFromNow = 0)
  840. {
  841. $offset = 60 * $minutesFromNow;
  842. $timestamp = gmdate("D, d M Y H:i:s", time() + $offset);
  843. self::appendHeader('Expires', $timestamp . ' GMT');
  844. }
  845. /**
  846. * Sets the Cache-Control and Expires header to control content cacheability.
  847. * If minutes is negative a no-cache, must-revalidate header is sent out. Otherwise a max-age value is sent out.
  848. *
  849. * @param int $minutes
  850. */
  851. public static function setCacheControl($minutes = 0)
  852. {
  853. if ($minutes <= 0)
  854. {
  855. self::appendHeader('Cache-Control', 'no-cache, must-revalidate');
  856. self::setExpires(times() - (60 * 24 * 365 * 10));
  857. }
  858. else
  859. {
  860. $seconds = $minutes * 60;
  861. self::appendHeader('Cache-Control', 'max-age=' . $seconds . ', must-revalidate');
  862. self::setExpires(time() + $seconds);
  863. }
  864. }
  865. /**
  866. * Sets the content-type header
  867. *
  868. * @param string $mimetype
  869. */
  870. public static function setContentType($mimetype = 'application/octet-stream')
  871. {
  872. self::appendHeader('Content-Type', $mimetype);
  873. }
  874. /**
  875. * Sets the content-disposition header.
  876. *
  877. * @param string $disposition Can be attachment or inline
  878. * @param string $filename If disposition is 'attachment' then you can specify a filename to download.
  879. */
  880. public static function setContentDisposition($disposition = 'attachment', $filename = '')
  881. {
  882. $headerValue = $disposition;
  883. if ($filename != '')
  884. $headerValue .= '; filename="' . $filename . '"';
  885. self::appendHeader('Content-Disposition', $headerValue);
  886. }
  887. /**
  888. * Sets the content-length header (in bytes).
  889. *
  890. * @param int $length
  891. */
  892. public static function setContentLength($length)
  893. {
  894. self::appendHeader('Content-Length', $length);
  895. }
  896. /**
  897. * Determines whether the headers have already been sent to the client.
  898. * @return bool
  899. */
  900. public static function hasSentHeaders()
  901. {
  902. return headers_sent();
  903. }
  904. }
  905. /**
  906. * The singleton request holding references to GET, POST, REQUEST and FILES variables.
  907. *
  908. * @package WebCore
  909. * @subpackage Web
  910. */
  911. class HttpRequest extends ObjectBase implements ISingleton
  912. {
  913. /**
  914. * Represents the instance of the singleton object
  915. *
  916. * @var HttpRequest
  917. */
  918. private static $__instance = null;
  919. /**
  920. * Gets a collection representing $_REQUEST variables.
  921. *
  922. * @var KeyedCollectionWrapper
  923. */
  924. private static $requestItems;
  925. /**
  926. * Gets a collection representing $_GET variables
  927. *
  928. * @var KeyedCollectionWrapper
  929. */
  930. private static $queryStringItems;
  931. /**
  932. * Gets a collection representing $_POST variables
  933. *
  934. * @var KeyedCollectionWrapper
  935. */
  936. private static $postedItems;
  937. /**
  938. * Gets a collection representing $_FILES variables
  939. *
  940. * @var KeyedCollection
  941. */
  942. private static $filesItems;
  943. /**
  944. * Gets the singleton instance for this class.
  945. *
  946. * @return HttpRequest
  947. */
  948. public static function getInstance()
  949. {
  950. if (self::isLoaded() === false)
  951. {
  952. self::$__instance = new HttpRequest();
  953. self::$requestItems = new KeyedCollectionWrapper($_REQUEST, true);
  954. self::$queryStringItems = new KeyedCollectionWrapper($_GET, true);
  955. self::$postedItems = new KeyedCollectionWrapper($_POST, true);
  956. self::$filesItems = new KeyedCollection();
  957. // Populate the files collection
  958. $postedFileKeys = array_keys($_FILES);
  959. foreach ($postedFileKeys as $fileKey)
  960. {
  961. $postedFile = new PostedFile($fileKey);
  962. self::$filesItems->setValue($fileKey, $postedFile);
  963. }
  964. }
  965. return self::$__instance;
  966. }
  967. /**
  968. * Determines whether the singleton has loaded its instance
  969. *
  970. * @return bool
  971. */
  972. public static function isLoaded()
  973. {
  974. if (is_null(self::$__instance))
  975. return false;
  976. return true;
  977. }
  978. /**
  979. * Gets a collection representing $_REQUEST variables (by reference)
  980. *
  981. * @return KeyedCollectionWrapper
  982. */
  983. public function &getRequestVars()
  984. {
  985. $vars = new KeyedCollection();
  986. foreach (self::$requestItems as $key => $value)
  987. {
  988. $decodedValue = utf8_decode($value);
  989. $vars->setValue($key, $decodedValue);
  990. }
  991. return $vars;
  992. }
  993. /**
  994. * Gets a collection representing $_POST variables (by reference)
  995. *
  996. * @return KeyedCollectionWrapper
  997. */
  998. public function &getPostVars()
  999. {
  1000. return self::$postedItems;
  1001. }
  1002. /**
  1003. * Gets a collection representing $_GET variables (by reference)
  1004. *
  1005. * @return KeyedCollectionWrapper
  1006. */
  1007. public function &getQueryStringVars()
  1008. {
  1009. return self::$queryStringItems;
  1010. }
  1011. /**
  1012. * Gets a KeyedCollection containing items of type PostedFile
  1013. * This is an enhanced version of the $_FILES array
  1014. *
  1015. * @return KeyedCollection
  1016. */
  1017. public function &getPostedFiles()
  1018. {
  1019. return self::$filesItems;
  1020. }
  1021. }
  1022. /**
  1023. * Wraps an item from the $_FILES array
  1024. *
  1025. * @package WebCore
  1026. * @subpackage Web
  1027. */
  1028. class PostedFile extends ObjectBase
  1029. {
  1030. private $__fileReference;
  1031. /**
  1032. * Creates a new instance of this class
  1033. *
  1034. * @param string $filesKey
  1035. */
  1036. public function __construct($filesKey)
  1037. {
  1038. if (array_key_exists($filesKey, $_FILES) === false)
  1039. throw new SystemException(SystemException::EX_INVALIDKEY, '$_FILES key ' . $filesKey . ' does not exist.');
  1040. $this->__fileReference =& $_FILES[$filesKey];
  1041. }
  1042. /**
  1043. * Gets the filename, without the path
  1044. * Example: myfile.ext
  1045. *
  1046. * @return string
  1047. */
  1048. public function getFileName()
  1049. {
  1050. return basename($this->__fileReference['name']);
  1051. }
  1052. /**
  1053. * Gets the filename, without the path or extension
  1054. * Example: myfile
  1055. *
  1056. * @return string
  1057. */
  1058. public function getFileBaseName()
  1059. {
  1060. $fileName = $this->getFileName();
  1061. $pathInfo = pathinfo($fileName);
  1062. return $pathInfo['filename'];
  1063. }
  1064. /**
  1065. * Gets the file extension of the uploaded file
  1066. * Example: ext
  1067. *
  1068. * @return string
  1069. */
  1070. public function getFileExtension()
  1071. {
  1072. $fileName = $this->getFileName();
  1073. $pathInfo = pathinfo($fileName);
  1074. return $pathInfo['extension'];
  1075. }
  1076. /**
  1077. * Gets the mime-type that the client set when the file was uploaded
  1078. * Example: image/gif
  1079. *
  1080. * @return string
  1081. */
  1082. public function getMimeType()
  1083. {
  1084. return $this->__fileReference['type'];
  1085. }
  1086. /**
  1087. * Gets the size, in bytes of the array.
  1088. *
  1089. * @return int
  1090. */
  1091. public function getSize()
  1092. {
  1093. return (int) $this->__fileReference['size'];
  1094. }
  1095. /**
  1096. * Gets the full path in the server to the uploaded file
  1097. *
  1098. * @return string
  1099. */
  1100. public function getTempFileName()
  1101. {
  1102. return $this->__fileReference['tmp_name'];
  1103. }
  1104. /**
  1105. * Gets whether file was uploaded and can be correcly found in the server.
  1106. *
  1107. * @return bool
  1108. */
  1109. public function isUploaded()
  1110. {
  1111. return is_uploaded_file($this->getTempFileName());
  1112. }
  1113. /**
  1114. * Gets the entire contents of the uploaded filed
  1115. *
  1116. * @return string
  1117. */
  1118. public function readAll()
  1119. {
  1120. $pathFileName = $this->getTempFileName();
  1121. return file_get_contents($pathFileName);
  1122. }
  1123. /**
  1124. * Gets the error code of the file upload result
  1125. *
  1126. * @return int
  1127. */
  1128. public function getErrorCode()
  1129. {
  1130. return $this->__fileReference['error'];
  1131. }
  1132. /**
  1133. * Gets a user-friendly message based on the error code
  1134. *
  1135. * @return string
  1136. */
  1137. public function getErrorMessage()
  1138. {
  1139. $errorCode = $this->getErrorCode();
  1140. switch ($errorCode)
  1141. {
  1142. case UPLOAD_ERR_CANT_WRITE:
  1143. return Resources::getValue(Resources::SRK_UPLOAD_ERR_CANT_WRITE);
  1144. break;
  1145. case UPLOAD_ERR_EXTENSION:
  1146. return Resources::getValue(Resources::SRK_UPLOAD_ERR_EXTENSION);
  1147. break;
  1148. case UPLOAD_ERR_FORM_SIZE:
  1149. return Resources::getValue(Resources::SRK_UPLOAD_ERR_FORM_SIZE);
  1150. break;
  1151. case UPLOAD_ERR_INI_SIZE:
  1152. return Resources::getValue(Resources::SRK_UPLOAD_ERR_INI_SIZE);
  1153. break;
  1154. case UPLOAD_ERR_NO_FILE:
  1155. return Resources::getValue(Resources::SRK_UPLOAD_ERR_NO_FILE);
  1156. break;
  1157. case UPLOAD_ERR_NO_TMP_DIR:
  1158. return Resources::getValue(Resources::SRK_UPLOAD_ERR_NO_TMP_DIR);
  1159. break;
  1160. case UPLOAD_ERR_OK:
  1161. return Resources::getValue(Resources::SRK_UPLOAD_ERR_OK);
  1162. break;
  1163. case UPLOAD_ERR_PARTIAL:
  1164. return Resources::getValue(Resources::SRK_UPLOAD_ERR_PARTIAL);
  1165. break;
  1166. default:
  1167. return Resources::getValue(Resources::SRK_UPLOAD_ERR_CANT_WRITE);
  1168. break;
  1169. }
  1170. return StaticResources::getMessagePostedFileErrorCode($this->getErrorCode());
  1171. }
  1172. }
  1173. /**
  1174. * Represents a typed, keyed collection wrapping the $_SERVER PHP array
  1175. *
  1176. * @package WebCore
  1177. * @subpackage Web
  1178. */
  1179. class HttpContextInfo extends KeyedCollectionBase implements ISingleton
  1180. {
  1181. const CLIENT_DESKTOP = "desktop";
  1182. const CLIENT_MOBILE = "mobile";
  1183. const CLIENT_IPHONE = "iphone";
  1184. const CLIENT_BB = "blackberry";
  1185. const CLIENT_BOT = "bot";
  1186. const INFO_HTTP_USER_AGENT = 'HTTP_USER_AGENT';
  1187. const INFO_REMOTE_ADDR = 'REMOTE_ADDR';
  1188. const INFO_REMOTE_PORT = 'REMOTE_PORT';
  1189. const INFO_HTTP_ACCEPT = 'HTTP_ACCEPT';
  1190. const INFO_HTTP_ACCEPT_ENCODING = 'HTTP_ACCEPT_ENCODING';
  1191. const INFO_HTTP_ACCEPT_LANGUAGE = 'HTTP_ACCEPT_LANGUAGE';
  1192. const INFO_GATEWAY_INTERFACE = 'GATEWAY_INTERFACE';
  1193. const INFO_SERVER_ADDR = 'SERVER_ADDR';
  1194. const INFO_SERVER_PORT = 'SERVER_PORT';
  1195. const INFO_DOCUMENT_ROOT = 'DOCUMENT_ROOT';
  1196. const INFO_SERVER_NAME = 'SERVER_NAME';
  1197. const INFO_SERVER_SOFTWARE = 'SERVER_SOFTWARE';
  1198. const INFO_SERVER_PROTOCOL = 'SERVER_PROTOCOL';
  1199. const INFO_REQUEST_URI = 'REQUEST_URI';
  1200. const INFO_QUERY_STRING = 'QUERY_STRING';
  1201. const INFO_REQUEST_METHOD = 'REQUEST_METHOD';
  1202. const INFO_REQUEST_TIME = 'REQUEST_TIME';
  1203. const INFO_HTTP_HOST = 'HTTP_HOST';
  1204. const INFO_SCRIPT_NAME = 'SCRIPT_NAME';
  1205. const INFO_HTTP_CONNECTION = 'HTTP_CONNECTION';
  1206. const INFO_PHP_SELF = 'PHP_SELF';
  1207. const INFO_SCRIPT_FILENAME = 'SCRIPT_FILENAME';
  1208. private static $clientType;
  1209. protected function __construct()
  1210. {
  1211. parent::__construct($_SERVER, true);
  1212. }
  1213. /**
  1214. * Represents the instance of the singleton object
  1215. *
  1216. * @var HttpContextInfo
  1217. */
  1218. private static $__instance = null;
  1219. /**
  1220. * Gets the singleton instance for this class.
  1221. *
  1222. * @return HttpContextInfo
  1223. */
  1224. public static function getInstance()
  1225. {
  1226. if (self::isLoaded() === false)
  1227. {
  1228. self::$__instance = new HttpContextInfo();
  1229. self::$__instance->detectClientType();
  1230. }
  1231. return self::$__instance;
  1232. }
  1233. /**
  1234. * Determines whether the singleton has loaded its instance
  1235. *
  1236. * @return bool
  1237. */
  1238. public static function isLoaded()
  1239. {
  1240. if (is_null(self::$__instance))
  1241. return false;
  1242. return true;
  1243. }
  1244. /**
  1245. * Returns client's type
  1246. *
  1247. * @return string
  1248. */
  1249. public function getClientType()
  1250. {
  1251. return self::$clientType;
  1252. }
  1253. /**
  1254. * Detects client type using User-Agent
  1255. *
  1256. */
  1257. public function detectClientType()
  1258. {
  1259. self::$clientType = self::CLIENT_DESKTOP;
  1260. $agent = self::getInstance()->getClientAgent();
  1261. $iphoneAgents = array(
  1262. "iPhone",
  1263. "iPod"
  1264. );
  1265. foreach ($iphoneAgents as $key)
  1266. {
  1267. if (preg_match("/$key/i", $agent))
  1268. {
  1269. self::$clientType = self::CLIENT_IPHONE;
  1270. return;
  1271. }
  1272. }
  1273. $botAgents = array(
  1274. "Teoma",
  1275. "alexa",
  1276. "MSNBot",
  1277. "inktomi",
  1278. "looksmart",
  1279. "Firefly",
  1280. "NationalDirectory",
  1281. "Ask Jeeves",
  1282. "TECNOSEEK",
  1283. "InfoSeek",
  1284. "WebFindBot",
  1285. "girafabot",
  1286. "crawler",
  1287. "www.galaxy.com",
  1288. "Googlebot",
  1289. "Scooter",
  1290. "Slurp",
  1291. "Yammybot",
  1292. "WebBug",
  1293. "Spade",
  1294. "ZyBorg"
  1295. );
  1296. foreach ($botAgents as $key)
  1297. {
  1298. if (preg_match("/$key/i", $agent))
  1299. {
  1300. self::$clientType = self::CLIENT_BOT;
  1301. return;
  1302. }
  1303. }
  1304. $mobileAgents = array(
  1305. "BlackBerry",
  1306. "Opera Mini",
  1307. "Windows CE",
  1308. "Symbian"
  1309. );
  1310. foreach ($mobileAgents as $key)
  1311. {
  1312. if (preg_match("/$key/i", $agent))
  1313. {
  1314. if ($key == "BlackBerry")
  1315. self::$clientType = self::CLIENT_BB;
  1316. else
  1317. self::$clientType = self::CLIENT_MOBILE;
  1318. return;
  1319. }
  1320. }
  1321. }
  1322. /**
  1323. * Returns an info value from the $_SERVER array
  1324. *
  1325. * @return string
  1326. */
  1327. protected static function getInfoValue($key)
  1328. {
  1329. return (self::getInstance()->keyExists($key) === true) ? self::getInstance()->getValue($key) : "";
  1330. }
  1331. /**
  1332. * Gets the client's browser name and version (if set in the request)
  1333. *
  1334. * @return string
  1335. */
  1336. public function getClientAgent()
  1337. {
  1338. return self::getInfoValue(self::INFO_HTTP_USER_AGENT);
  1339. }
  1340. /**
  1341. * Returns an array with client agent information such as name and version
  1342. * @return array
  1343. */
  1344. public function getClientAgentInfo()
  1345. {
  1346. return get_browser(null, true);
  1347. }
  1348. /**
  1349. * Gets the IP Address of the current request.
  1350. *
  1351. * @return string
  1352. */
  1353. public function getClientIPAddress()
  1354. {
  1355. return self::getInfoValue(self::INFO_REMOTE_ADDR);
  1356. }
  1357. /**
  1358. * Gets the TCP/IP port the client used to send the request
  1359. *
  1360. * @return int
  1361. */
  1362. public function getClientPort()
  1363. {
  1364. return self::getInfoValue(self::INFO_REMOTE_PORT);
  1365. }
  1366. /**
  1367. * Gets the comma-delimited mimetypes that the client accepts.
  1368. *
  1369. * @return string
  1370. */
  1371. public function getClientAccept()
  1372. {
  1373. return self::getInfoValue(self::INFO_HTTP_ACCEPT);
  1374. }
  1375. /**
  1376. * Gets the comma-delimieted supported stream formats that the client supports.
  1377. * For example, gzip, deflate
  1378. *
  1379. * @return string
  1380. */
  1381. public function getClientAcceptEncoding()
  1382. {
  1383. return self::getInfoValue(self::INFO_HTTP_ACCEPT_ENCODING);
  1384. }
  1385. /**
  1386. * Gets the client's language and culture code
  1387. * For example, en-us or es-mx
  1388. * @return string
  1389. */
  1390. public function getClientAcceptLanguage()
  1391. {
  1392. return self::getInfoValue(self::INFO_HTTP_ACCEPT_LANGUAGE);
  1393. }
  1394. /**
  1395. * Gets the version of the Common Gateway Interface the server is using.
  1396. * For example, CGI/1.1
  1397. *
  1398. * @return string
  1399. */
  1400. public function getServerCGI()
  1401. {
  1402. return self::getInfoValue(self::INFO_GATEWAY_INTERFACE);
  1403. }
  1404. /**
  1405. * Gets the server's IP address serving the response
  1406. *
  1407. * @return string
  1408. */
  1409. public function getServerIPAddress()
  1410. {
  1411. return self::getInfoValue(self::INFO_SERVER_ADDR);
  1412. }
  1413. /**
  1414. * Gets the TCP/IP port on which the response is returned by the server
  1415. *
  1416. * @return string
  1417. */
  1418. public function getServerPort()
  1419. {
  1420. return self::getInfoValue(self::INFO_SERVER_PORT);
  1421. }
  1422. /**
  1423. * Gets the root path in the server's file system from which all
  1424. * documents are processed and served.
  1425. *
  1426. * @return string
  1427. */
  1428. public function getServerFileSystemWebRootPath()
  1429. {
  1430. return self::getInfoValue(self::INFO_DOCUMENT_ROOT);
  1431. }
  1432. /**
  1433. * Gets the name of the server.
  1434. * For example, localhost
  1435. *
  1436. * @return string
  1437. */
  1438. public function getServerAddress()
  1439. {
  1440. return self::getInfoValue(self::INFO_SERVER_NAME);
  1441. }
  1442. /**
  1443. * Gets the name and version of the software used to process requests and responses.
  1444. *
  1445. * @return string
  1446. */
  1447. public function getServerSoftware()
  1448. {
  1449. return self::getInfoValue(self::INFO_SERVER_SOFTWARE);
  1450. }
  1451. /**
  1452. * Gets the protocol the server is using to process requests and serve response.
  1453. * For example, HTTP/1.1
  1454. *
  1455. * @return string
  1456. */
  1457. public function getServerProtocol()
  1458. {
  1459. return self::getInfoValue(self::INFO_SERVER_PROTOCOL);
  1460. }
  1461. /**
  1462. * Gets the full Uniform Resource identifier of the request.
  1463. * For example, http://localhost/test/test.php?id=6
  1464. *
  1465. * @return string
  1466. */
  1467. public function getRequestUri()
  1468. {
  1469. return self::getInfoValue(self::INFO_REQUEST_URI);
  1470. }
  1471. /**
  1472. * Gets the query string that appears after the script's name
  1473. * For example, id=6
  1474. *
  1475. * @return string
  1476. */
  1477. public function getRequestQueryString()
  1478. {
  1479. return self::getInfoValue(self::INFO_QUERY_STRING);
  1480. }
  1481. /**
  1482. * Gets the REST method for the request.
  1483. * For example, POST
  1484. *
  1485. * @return string
  1486. */
  1487. public function getRequestMethod()
  1488. {
  1489. return StringHelper::toUpper(self::getInfoValue(self::INFO_REQUEST_METHOD));
  1490. }
  1491. /**
  1492. * Gets the timestamp at which the request was made.
  1493. *
  1494. * @return int
  1495. */
  1496. public function getRequestStartTime()
  1497. {
  1498. return self::getInfoValue(self::INFO_REQUEST_TIME);
  1499. }
  1500. /**
  1501. * Gets the hostname and port at which the request is directed
  1502. * For example, localhost:88
  1503. *
  1504. * @return string
  1505. */
  1506. public function getRequestHost()
  1507. {
  1508. return self::getInfoValue(self::INFO_HTTP_HOST);
  1509. }
  1510. /**
  1511. * Gets the virtual path to the resource at which the request was created.
  1512. * For example, /test/testing.php
  1513. *
  1514. * @return string
  1515. */
  1516. public function getRequestScriptPath()
  1517. {
  1518. return self::getInfoValue(self::INFO_SCRIPT_NAME);
  1519. }
  1520. /**
  1521. * Gets the connection mode the client requests.
  1522. * For example, Keep-Alive
  1523. *
  1524. * @return string
  1525. */
  1526. public function getRequestConnectionMode()
  1527. {
  1528. return self::getInfoValue(self::INFO_HTTP_CONNECTION);
  1529. }
  1530. /**
  1531. * Gets the full path to the executing script in the file system.
  1532. * For example: c:\InetPub\wwwroot\test\testing.php
  1533. *
  1534. * @return string
  1535. */
  1536. public function getScriptFileSystemPath()
  1537. {
  1538. return self::getInfoValue(self::INFO_SCRIPT_FILENAME);
  1539. }
  1540. /**
  1541. * Gets the full virtual path to the executing script.
  1542. * for example: /test/testing.php
  1543. *
  1544. * @return string
  1545. */
  1546. public function getScriptVirtualPath()
  1547. {
  1548. return self::getInfoValue(self::INFO_PHP_SELF);
  1549. }
  1550. /**
  1551. * Creates a default instance of this class
  1552. *
  1553. * @return HttpContextInfo
  1554. */
  1555. public static function createInstance()
  1556. {
  1557. return self::getInstance();
  1558. }
  1559. }
  1560. /**
  1561. * Represents a user navigation entry holding significant request information.
  1562. * @package WebCore
  1563. * @subpackage Web
  1564. */
  1565. class NavigationEntry extends SerializableObjectBase
  1566. {
  1567. protected $postedVars;
  1568. protected $queryVars;
  1569. protected $requestUrl;
  1570. protected $requestTime;
  1571. protected $hadPostedFiles;
  1572. protected $requestMethod;
  1573. protected $scriptVirtualPath;
  1574. /**
  1575. * Creates a new instance of this class
  1576. */
  1577. public function __construct()
  1578. {
  1579. $this->postedVars = clone HttpRequest::getInstance()->getPostVars();
  1580. $this->queryVars = clone HttpRequest::getInstance()->getQueryStringVars();
  1581. $this->hadPostedFiles = HttpRequest::getInstance()->getPostedFiles()->getCount() > 0;
  1582. $this->requestUrl = HttpContextInfo::getInstance()->getRequestUri();
  1583. $this->requestTime = time();
  1584. $this->requestMethod = HttpContextInfo::getInstance()->getRequestMethod();
  1585. $this->scriptVirtualPath = HttpContextInfo::getInstance()->getScriptVirtualPath();
  1586. }
  1587. /**
  1588. * Transfers the client to the state of this this NavigationEntry
  1589. * @param bool $onlyStateFlags If set to true, rall transfer parameters that are not prefixed by Controller::PREFIX_STATE
  1590. */
  1591. public function transfer($onlyStateFlags = true)
  1592. {
  1593. $params = new KeyedCollection();
  1594. foreach ($this->postedVars->getKeys() as $key)
  1595. {
  1596. if (!StringHelper::beginsWith($key, Controller::PREFIX_STATE) && $onlyStateFlags === true)
  1597. continue;
  1598. $params->setValue($key, $this->postedVars->getValue($key));
  1599. }
  1600. Controller::transfer($this->requestUrl, $params->getArrayReference());
  1601. }
  1602. /**
  1603. * Creates a new instance of this class.
  1604. */
  1605. public static function createInstance()
  1606. {
  1607. return new NavigationEntry();
  1608. }
  1609. /**
  1610. * @return KeyedCollection
  1611. */
  1612. public function getPostedVars()
  1613. {
  1614. return $this->postedVars;
  1615. }
  1616. /**
  1617. * @return KeyedCollection
  1618. */
  1619. public function getQueryVars()
  1620. {
  1621. return $this->queryVars;
  1622. }
  1623. /**
  1624. * @return string
  1625. */
  1626. public function getRequestUrl()
  1627. {
  1628. return $this->requestUrl;
  1629. }
  1630. /**
  1631. * @return int
  1632. */
  1633. public function getRequestTime()
  1634. {
  1635. return $this->requestTime;
  1636. }
  1637. /**
  1638. * @return bool
  1639. */
  1640. public function getHadPPostedFiles()
  1641. {
  1642. return $this->hadPostedFiles;
  1643. }
  1644. /**
  1645. * @return string
  1646. */
  1647. public function getRequestMethod()
  1648. {
  1649. return $this->requestMethod;
  1650. }
  1651. /**
  1652. * @return string
  1653. */
  1654. public function getScriptVirtualPath()
  1655. {
  1656. return $this->scriptVirtualPath;
  1657. }
  1658. }
  1659. /**
  1660. * Represents the user navigation history.
  1661. * This class is useful to transfer the user back to a previous request or to keep track of navigation statistics.
  1662. * Note: The first item (0) always has the most recent navigation entry.
  1663. * A maximum of 10 navigation entries is kept.
  1664. *
  1665. * @package WebCore
  1666. * @subpackage Web
  1667. */
  1668. class NavigationHistory extends IndexedCollection
  1669. {
  1670. protected $storageLimit;
  1671. /**
  1672. * Creates a new instance of this class.
  1673. */
  1674. public function __construct($storageLimit = 4)
  1675. {
  1676. $this->storageLimit = $storageLimit; // @todo get this from settings
  1677. $this->isReadOnly = true;
  1678. }
  1679. /**
  1680. * @return NavigationEntry
  1681. */
  1682. public function getValue($offset)
  1683. {
  1684. return parent::getItem($offset);
  1685. }
  1686. /**
  1687. * @return NavigationEntry
  1688. */
  1689. public function &getItem($offset)
  1690. {
  1691. return parent::getItem($offset);
  1692. }
  1693. /**
  1694. * @return NavigationEntry
  1695. */
  1696. public function &getLastItem()
  1697. {
  1698. return parent::getLastItem();
  1699. }
  1700. /**
  1701. * Gets the Navigation entry previous to the current request being navigated.
  1702. * @return NavigationEntry Returns null if no previous item can be found
  1703. */
  1704. public function &getPreviousItem()
  1705. {
  1706. if ($this->getCount() <= 1)
  1707. return null;
  1708. return $this->getItem(1);
  1709. }
  1710. /**
  1711. * Adds the current navigation enetry to the NavigationHistory
  1712. * @param bool $withReplace Determines whether the las entry should be replaced with the new one if the script virtual paths match exactly.
  1713. */
  1714. public function addCurrent($withReplace = true)
  1715. {
  1716. // unlock the collection
  1717. $this->isReadOnly = false;
  1718. $entry = new NavigationEntry();
  1719. $updated = false;
  1720. if (strstr($entry->getScriptVirtualPath(), 'getfile')) return;
  1721. if ($this->getCount() > 0 && $withReplace === true)
  1722. {
  1723. if ($this->getItem(0)->getScriptVirtualPath() === $entry->getScriptVirtualPath())
  1724. {
  1725. $oldNav = $this->getItem(0);
  1726. $oldNav->getPostedVars()->merge($entry->getPostedVars());
  1727. $updated = true;
  1728. }
  1729. }
  1730. if ($updated === false)
  1731. {
  1732. parent::insertAt(0, $entry);
  1733. }
  1734. if ($this->getCount() > $this->storageLimit)
  1735. {
  1736. $this->removeAt($this->storageLimit);
  1737. }
  1738. $this->isReadOnly = true;
  1739. }
  1740. }
  1741. /**
  1742. * Represents the current HTTP context
  1743. * Always call the initialize() method in order to enable access to child objects.
  1744. *
  1745. * @package WebCore
  1746. * @subpackage Web
  1747. */
  1748. class HttpContext extends ObjectBase
  1749. {
  1750. /**
  1751. * State variable to determine whether the Context has been initialized.
  1752. *
  1753. * @var bool
  1754. */
  1755. private static $isInitialized = false;
  1756. protected static $accessPermissionSet;
  1757. /**
  1758. * @var NavigationHistory
  1759. */
  1760. protected static $navigationHistory;
  1761. /**
  1762. * Initializes the current HTTP context available to the current request.
  1763. * This method is usuarlly called in the first line of logic after the require
  1764. * statements.
  1765. *
  1766. */
  1767. public static function initialize()
  1768. {
  1769. if (self::$isInitialized === true) return;
  1770. ClassLoader::addIncludePath(HttpContext::getFSLibraryRoot());
  1771. self::$isInitialized = true;
  1772. $appSettings = Settings::getValue(Settings::SKEY_APPLICATION);
  1773. if (array_key_exists(Settings::KEY_APPLICATION_TIMEZONE, $appSettings))
  1774. date_default_timezone_set($appSettings[Settings::KEY_APPLICATION_TIMEZONE]);
  1775. else
  1776. date_default_timezone_set('America/Mexico_City');
  1777. LogManager::getInstance();
  1778. HttpSession::getInstance();
  1779. self::$navigationHistory = new NavigationHistory();
  1780. HttpContext::getSession()->registerPersistentObject('__navigationHistory', self::$navigationHistory);
  1781. self::getNavigationHistory()->addCurrent(); // @todo if appSettings->storageLimit > 0 then addCurrent
  1782. self::registerStandardHandlers();
  1783. HttpHandlerManager::handleRequest();
  1784. $settings = Settings::getValue(Settings::SKEY_COMPRESSION);
  1785. if ($settings[Settings::KEY_COMPRESSION_ENABLED] == 1)
  1786. {
  1787. $className = $settings[Settings::KEY_COMPRESSION_PROVIDER];
  1788. if ($className == HttpCompressor::PROVIDER_DOM)
  1789. DomCompressor::getInstance()->initialize();
  1790. }
  1791. }
  1792. /**
  1793. * registers the common handlers for the frameword
  1794. */
  1795. private static function registerStandardHandlers()
  1796. {
  1797. $fileHandler = new FileHttpHandler();
  1798. $resourcesHandler = new ResourcesHttpHandler();
  1799. $imageHandler = new ImageHttpHandler();
  1800. HttpHandlerManager::registerHandler($fileHandler);
  1801. HttpHandlerManager::registerHandler($resourcesHandler);
  1802. HttpHandlerManager::registerHandler($imageHandler);
  1803. }
  1804. /**
  1805. * Returns the current Session object.
  1806. *
  1807. * @return HttpSession
  1808. */
  1809. public static function getSession()
  1810. {
  1811. if (self::$isInitialized === false)
  1812. throw new SystemException(SystemException::EX_NOCONTEXT);
  1813. return HttpSession::getInstance();
  1814. }
  1815. /**
  1816. * Gets the preserved user navigation history.
  1817. * @return NavigationHistory
  1818. */
  1819. public static function &getNavigationHistory()
  1820. {
  1821. if (self::$isInitialized === false)
  1822. throw new SystemException(SystemException::EX_NOCONTEXT);
  1823. return self::$navigationHistory;
  1824. }
  1825. /**
  1826. * Gets the Cookie Manager object
  1827. * @return CookieManager
  1828. */
  1829. public static function &getCookieManager()
  1830. {
  1831. if (self::$isInitialized === false)
  1832. throw new SystemException(SystemException::EX_NOCONTEXT);
  1833. return CookieManager::getInstance();
  1834. }
  1835. /**
  1836. * Gets the current HttpRequest object, containing all GET and POST variables
  1837. *
  1838. * @return HttpRequest
  1839. */
  1840. public static function getRequest()
  1841. {
  1842. return HttpRequest::getInstance();
  1843. }
  1844. /**
  1845. * Gets the current HttpResponse object, from which response processing can be manipulated
  1846. * @return HttpResponse
  1847. */
  1848. public static function getResponse()
  1849. {
  1850. return HttpResponse::getInstance();
  1851. }
  1852. /**
  1853. * Gets the PermissionSet object in effect
  1854. * @return PermissionSet
  1855. */
  1856. public static function getPermissionSet()
  1857. {
  1858. if (is_null(self::$accessPermissionSet))
  1859. self::$accessPermissionSet = new PermissionSet(Permission::PERMISSION_DENY);
  1860. return self::$accessPermissionSet;
  1861. }
  1862. /**
  1863. * @return IMembershipUser
  1864. */
  1865. public static function getUser()
  1866. {
  1867. return FormsAuthentication::getUser();
  1868. }
  1869. /**
  1870. * @return IndexedCollection
  1871. */
  1872. public static function getUserRoles()
  1873. {
  1874. $user = self::getUser();
  1875. if (is_null($user))
  1876. return new IndexedCollection();
  1877. return $user->getRoles();
  1878. }
  1879. /**
  1880. * Resolves role-based security for this context according to the rules dfined by PermissionSet
  1881. */
  1882. public static function applySecurity()
  1883. {
  1884. /**
  1885. * @var MembershipUser
  1886. */
  1887. $user = self::getUser();
  1888. $allow = self::getPermissionSet()->resolve($user);
  1889. if ($allow == Permission::PERMISSION_DENY)
  1890. {
  1891. FormsAuthentication::redirectToLoginPage(HttpContext::getInfo()->getRequestUri());
  1892. }
  1893. }
  1894. /**
  1895. * Determines whether the Context has been properly initialized.
  1896. *
  1897. * @return bool
  1898. */
  1899. public static function isInitialized()
  1900. {
  1901. return self::$isInitialized;
  1902. }
  1903. /**
  1904. * Gets the current request's information.
  1905. *
  1906. * @return HttpContextInfo
  1907. */
  1908. public static function getInfo()
  1909. {
  1910. return HttpContextInfo::getInstance();
  1911. }
  1912. /**
  1913. * Gets WebCore's libraray extensions absolute path (for use with php include paths)
  1914. * Paths returned always have a trailing slash '/'.
  1915. * This is a file system path
  1916. * @return string
  1917. */
  1918. public static function getFSLibraryExtensionsRoot()
  1919. {
  1920. return self::getFSLibraryRoot() . 'ext/';
  1921. }
  1922. /**
  1923. * Gets WebCore's libraray absolute path (for use with php include paths)
  1924. * Paths returned always have a trailing slash '/'.
  1925. * This is a file system path
  1926. * @return string
  1927. */
  1928. public static function getFSLibraryRoot()
  1929. {
  1930. return str_replace('//', '/', str_replace('\\', '/', realpath(dirname(__FILE__)) . '/'));
  1931. }
  1932. /**
  1933. * Gets WebCore's libraray virtual path (for use with css and js includes)
  1934. * Paths returned always have a trailing slash '/'.
  1935. * This is a virtual path
  1936. * @return string
  1937. */
  1938. public static function getLibraryRoot()
  1939. {
  1940. if (defined('LIBRARY_ROOT') === true)
  1941. {
  1942. if (strrchr(LIBRARY_ROOT, '/') == '/' || strrchr(LIBRARY_ROOT, '\\') == '\\')
  1943. return str_replace('\\', '/', LIBRARY_ROOT);
  1944. else
  1945. return str_replace('\\', '/', LIBRARY_ROOT) . '/';
  1946. }
  1947. $libRoot = str_replace('\\', '/', self::getApplicationRoot() . substr(realpath(dirname(__FILE__)), stripos(realpath(dirname(__FILE__)), 'webcore')) . '/');
  1948. return $libRoot;
  1949. }
  1950. /**
  1951. * Gets the absolute, real path from which the server takes documents.
  1952. * If the constant DOCUMENT_ROOT is not defined, the method tries to obtain the path automatically.
  1953. * Paths returned always have a trailing slash '/'.
  1954. * This is a file system path
  1955. * @return string
  1956. */
  1957. public static function getDocumentRoot()
  1958. {
  1959. if (defined('DOCUMENT_ROOT') === true)
  1960. {
  1961. if (strrchr(DOCUMENT_ROOT, '/') == '/' || strrchr(DOCUMENT_ROOT, '\\') == '\\')
  1962. return str_replace('\\', '/', DOCUMENT_ROOT);
  1963. else
  1964. return str_replace('\\', '/', DOCUMENT_ROOT) . '/';
  1965. }
  1966. // Get local and absolute paths
  1967. $localPathInfo = pathinfo(getenv("SCRIPT_NAME"));
  1968. $localPath = $localPathInfo['dirname'];
  1969. $absolutePath = realpath('.');
  1970. // a fix for Windows slashes. Windows 2k and above accept forward slashes
  1971. $absolutePath = str_replace("\\", "/", $absolutePath);
  1972. // To lower case strings
  1973. $localPath = strtolower($localPath);
  1974. $absolutePath = strtolower($absolutePath);
  1975. // Cut off the last part of the script's path, matching the absolute path
  1976. $documentRoot = substr($absolutePath, 0, strpos($absolutePath, $localPath));
  1977. if ($documentRoot != '/')
  1978. $documentRoot = $documentRoot . '/';
  1979. return $documentRoot;
  1980. }
  1981. /**
  1982. * Gets the temporary Operating System path
  1983. * Paths returned always have a trailing slash '/'.
  1984. * This is a file system path
  1985. * @return string
  1986. */
  1987. public static function getTempDir()
  1988. {
  1989. $absolutePath = str_replace("\\", "/", sys_get_temp_dir());
  1990. if ($absolutePath != '/' && substr($absolutePath, -1) != '/')
  1991. $absolutePath = $absolutePath . '/';
  1992. return $absolutePath;
  1993. }
  1994. /**
  1995. * Gets the virtual path of the server root.
  1996. * Paths returned always have a trailing slash '/'.
  1997. * This is a file system path
  1998. * @return string
  1999. */
  2000. public static function getServerRoot()
  2001. {
  2002. $current_script = dirname($_SERVER['SCRIPT_NAME']);
  2003. $current_path = dirname($_SERVER['SCRIPT_FILENAME']);
  2004. $adjust = explode("/", $current_script);
  2005. $adjust = count($adjust) - 1;
  2006. $traverse = str_repeat("../", $adjust);
  2007. $adjusted_path = sprintf("%s/%s", $current_path, $traverse);
  2008. $absolutePath = realpath($adjusted_path);
  2009. $absolutePath = str_replace("\\", "/", $absolutePath);
  2010. return $absolutePath;
  2011. }
  2012. /**
  2013. * Gets the virtual path of the application root.
  2014. * If the constant APPLICATION_ROOT is not defined, the method returns '/'
  2015. * Paths returned always have a trailing slash '/'.
  2016. * This is a virtual path
  2017. * @return string
  2018. */
  2019. public static function getApplicationRoot()
  2020. {
  2021. if (defined('APPLICATION_ROOT') === true)
  2022. return APPLICATION_ROOT;
  2023. return "/";
  2024. }
  2025. }
  2026. /**
  2027. * This class provide a easy way to know MIME type
  2028. * and valid file extension of any stream
  2029. * @todo Deprecate with PHP 5.3
  2030. * @package WebCore
  2031. * @subpackage Web
  2032. */
  2033. class MimeResolver extends HelperBase
  2034. {
  2035. private static $extdata = array(
  2036. 'image/jpeg' => 'jpg',
  2037. 'image/x-png' => 'png',
  2038. 'text/vnd.ms-word' => 'doc',
  2039. 'text/vnd.ms-excel' => 'xls',
  2040. 'application/msword' => 'doc',
  2041. 'application/vnd.ms-excel' => 'xls',
  2042. 'application/pdf' => 'pdf',
  2043. 'application/zip' => 'zip',
  2044. 'application/x-rar' => 'rar',
  2045. 'audio/mpeg' => 'mp3',
  2046. 'video/mpeg' => 'mpg',
  2047. 'text/html' => 'html',
  2048. 'image/gif' => 'gif',
  2049. 'video/quicktime' => 'mov',
  2050. 'video/avi' => 'avi',
  2051. 'image/x-bmp' => 'bmp');
  2052. private static $magicdata = array(
  2053. array(0, 2, 0xfff0, 0xf0ff, "audio/mpeg"),
  2054. array(4, 4, 0, "moov", "video/quicktime"),
  2055. array(4, 4, 0, "mdat", "video/quicktime"),
  2056. array(257, 6, 0, "ustar\0", "application/x-tar"),
  2057. array(0, 4, 0, "Rar!", "application/x-rar"),
  2058. array(0, 4, 0, "PK\003\004", "application/zip"),
  2059. array(0, 11, 0, "#!/bin/perl", "application/x-perl"),
  2060. array(0, 12, 0, "#! /bin/perl", "application/x-perl"),
  2061. array(0, 2, 0, "#!", "text/script"),
  2062. array(0, 2, 0, "\037\213", "application/x-gzip"),
  2063. array(0, 2, 0, "BZ", "application/x-bzip"),
  2064. array(0, 5, 0, "\000\001\000\000\000", "font/ttf"),
  2065. array(0, 4, 0, "MM\x00\x2a", "image/tiff"),
  2066. array(0, 4, 0, "\x89PNG", "image/x-png"),
  2067. array(1, 3, 0, "PNG", "image/x-png"),
  2068. array(0, 2, 0, "Ř˙", "image/jpeg"),
  2069. array(0, 3, 0, "˙Ř˙", "image/jpeg"),
  2070. array(0, 2, 0, "BM", "image/x-bmp"),
  2071. array(0, 2, 0, "IC", "image/x-ico"),
  2072. array(0, 4, 0, "FFIL", "font/ttf"),
  2073. array(65, 4, 0, "FFIL", "font/ttf"),
  2074. array(0, 4, 0, "LWFN", "font/type1"),
  2075. array(65, 4, 0, "LWFN", "font/type1"),
  2076. array(0, 2, 0, "MZ", "application/x-ms-dos-executable"),
  2077. array(2080, 27, 0, "Microsoft Word 6.0 Document", "text/vnd.ms-word"),
  2078. array(2080, 26, 0, "Documento Microsoft Word 6", "text/vnd.ms-word"),
  2079. array(2112, 9, 0, "MSWordDoc", "text/vnd.ms-word"),
  2080. array(0, 5, 0, "PO^Q`", "text/vnd.ms-word"),
  2081. array(2080, 29, 0, "Microsoft Excel 5.0 Worksheet", "application/vnd.ms-excel"),
  2082. array(2114, 5, 0, "Biff5", "application/vnd.ms-excel"),
  2083. array(0, 2, 0, "%!", "application/postscript"),
  2084. array(0, 14, 0, "<!DOCTYPE HTML", "text/html"),
  2085. array(0, 14, 0, "<!doctype html", "text/html"),
  2086. array(0, 5, 0, "<html", "text/html"),
  2087. array(0, 5, 0, "<HTML", "text/html"),
  2088. array(0, 4, 0, "%PDF", "application/pdf"),
  2089. array('>2', 2, 0, "şž", "application/java"),
  2090. array('>8', 4, 0, "WAVE", "audio/x-wav"),
  2091. array(0, 3, 0, "ID3", "audio/mpeg"),
  2092. array(0, 4, 0, "OggS", "audio/x-ogg"),
  2093. array(0, 2, 0, "MM", "image/tiff"),
  2094. array(0, 2, 0, "II", "image/tiff"),
  2095. array(0, 6, 0, "FGF95a", "image/gif"),
  2096. array(0, 3, 0, "PBF", "image/gif"),
  2097. array(0, 3, 0, "GIF", "image/gif"),
  2098. array(0, 4, 0, "\376\067\0\043", "application/msword"),
  2099. array(0, 6, 0, "\320\317\021\340\241\261", "application/msword"),
  2100. array(0, 6, 0, "\333\245-\0\0\0", "application/msword"),
  2101. array('>8', 4, 0, "AVI ", "video/avi"),
  2102. array(0, 4, 0, "Å‚\x01\x00\x00", "video/mpeg"),
  2103. array(0, 4, 0, "ÅŸ\x01\x00\x00", "video/mpeg"),
  2104. array(0, 4, 0, "\x00\x00ž1", "text/vnd.ms-word"),
  2105. array(0, 2, 0, "\x00\x00", "audio/mpeg"),
  2106. array(0, 5, 0, "<?php", "application/x-php"));
  2107. /**
  2108. * Gets Extension value of a MIME type
  2109. *
  2110. * @param string $mimeType
  2111. * @return string
  2112. */
  2113. public static function getExtension($mimeType)
  2114. {
  2115. $collection = new KeyedCollectionWrapper(self::$extdata, true);
  2116. if ($collection->keyExists($mimeType))
  2117. return $collection->getValue($mimeType);
  2118. return "0";
  2119. }
  2120. /**
  2121. * Gets MIME type by Extension
  2122. *
  2123. * @param string $extension
  2124. * @param bool $defaultHtml
  2125. * @return string
  2126. */
  2127. public static function getMimebyExtension($extension, $defaultHtml = true)
  2128. {
  2129. foreach (self::$extdata as $key => $value)
  2130. {
  2131. if ($extension == $value)
  2132. return $key;
  2133. }
  2134. return ($defaultHtml) ? "text/html" : "application/octet-stream";
  2135. }
  2136. /**
  2137. * Gets MIME type of a stream
  2138. *
  2139. * @param string $binaryData
  2140. * @return string
  2141. */
  2142. public static function getMime(&$binaryData)
  2143. {
  2144. $fd = substr($binaryData, 0, 3072);
  2145. foreach (self::$magicdata as $def)
  2146. {
  2147. $pos0 = $def[0];
  2148. if ($pos0[0] == ">")
  2149. {
  2150. $pos0 = substr($pos0, 1);
  2151. if (strpos($fd, $def[3], $pos0) !== false)
  2152. return ($def[4]);
  2153. }
  2154. else
  2155. {
  2156. $part = substr($fd, $pos0, $def[1]);
  2157. if ($mask = $def[2])
  2158. {
  2159. $value = 1 * ('0x' . bin2hex($part));
  2160. if (($value & $mask) == $def[3])
  2161. return ($def[4]);
  2162. }
  2163. else if ($part == $def[3])
  2164. return ($def[4]);
  2165. }
  2166. }
  2167. return "application/octet-stream";
  2168. }
  2169. }
  2170. /**
  2171. * Manages, registers and executes all Http Handlers
  2172. * @package WebCore
  2173. * @subpackage Web
  2174. */
  2175. class HttpHandlerManager extends HelperBase
  2176. {
  2177. /**
  2178. * @var IndexedCollection
  2179. */
  2180. private static $handlers;
  2181. private static $hasExecuted;
  2182. /**
  2183. * Gets the registered handler collection
  2184. * @return IndexedCollection
  2185. */
  2186. public static function getHandlers()
  2187. {
  2188. if (is_null(self::$handlers))
  2189. self::$handlers = new IndexedCollection();
  2190. return self::$handlers;
  2191. }
  2192. /**
  2193. * Determines whether the Handler Manager has executed all the registered handlers
  2194. * @return bool
  2195. */
  2196. public function getHasExecuted()
  2197. {
  2198. return self::$hasExecuted === true;
  2199. }
  2200. /**
  2201. * Iterates through every registered HttpHandler and executes the handleRequest method for each of them
  2202. */
  2203. public static function handleRequest()
  2204. {
  2205. if (self::$hasExecuted === true)
  2206. throw new SystemException(SystemException::EX_INVALIDOPERATION, 'The request has already been handled.');
  2207. foreach (self::getHandlers() as $handler)
  2208. {
  2209. $handler->handleRequest();
  2210. }
  2211. self::$hasExecuted = true;
  2212. }
  2213. /**
  2214. * Registers an IHttpHandler object for execution. If the Handler manager has already
  2215. * handled the request, this method will throw and invalid operation exception.
  2216. * @param IHttpHandler
  2217. */
  2218. public static function registerHandler($handler)
  2219. {
  2220. if (self::$hasExecuted === true)
  2221. throw new SystemException(SystemException::EX_INVALIDOPERATION, 'The request has already been handled.');
  2222. if (!ObjectIntrospector::isImplementing($handler, 'IHttpHandler'))
  2223. throw new SystemException(SystemException::EX_INVALIDPARAMETER, 'Parameter $handler must implement IHttpHandler');
  2224. self::getHandlers()->addItem($handler);
  2225. }
  2226. }
  2227. /**
  2228. * Handles File Downloads
  2229. *
  2230. * @package WebCore
  2231. * @subpackage Web
  2232. */
  2233. class FileHttpHandler extends ObjectBase implements IHttpHandler
  2234. {
  2235. /**
  2236. * Handles file download
  2237. */
  2238. public function handleRequest()
  2239. {
  2240. $queryStringVars = HttpRequest::getInstance()->getQueryStringVars();
  2241. $fileName = '';
  2242. if ($queryStringVars->keyExists("_file"))
  2243. {
  2244. if ($queryStringVars->keyExists("_fileName"))
  2245. $fileName = $queryStringVars->getValue("_fileName");
  2246. $file = HttpContext::getTempDir() . $queryStringVars->getValue("_file");
  2247. if (file_exists($file))
  2248. {
  2249. $content = file_get_contents($file);
  2250. if ($fileName == '')
  2251. {
  2252. $mime = MimeResolver::getMime($content);
  2253. $ext = MimeResolver::getExtension($mime);
  2254. $fileName = "unknownfile." . $ext;
  2255. }
  2256. else
  2257. {
  2258. $ext = explode(".", $fileName);
  2259. $ext = $ext[count($ext) - 1];
  2260. $mime = MimeResolver::getMimebyExtension($ext);
  2261. }
  2262. header('Content-Type: ' . $mime);
  2263. header('Content-Length: ' . strlen($content));
  2264. header('Content-Disposition: attachment; filename="' . $fileName . '"');
  2265. echo $content;
  2266. }
  2267. exit(0);
  2268. }
  2269. }
  2270. }
  2271. /**
  2272. * Handles Image previewing
  2273. *
  2274. * @package WebCore
  2275. * @subpackage Web
  2276. */
  2277. class ImageHttpHandler extends ObjectBase implements IHttpHandler
  2278. {
  2279. /**
  2280. * Handles images and thumbnails
  2281. */
  2282. public function handleRequest()
  2283. {
  2284. $queryStringVars = HttpRequest::getInstance()->getQueryStringVars();
  2285. $fileName = '';
  2286. if ($queryStringVars->keyExists("_file_img_handler"))
  2287. {
  2288. if ($queryStringVars->keyExists("_fileName"))
  2289. $fileName = $queryStringVars->getValue("_fileName");
  2290. $img = HttpContext::getTempDir() . $queryStringVars->getValue("_file_img_handler");
  2291. if (file_exists($img))
  2292. {
  2293. if ($fileName == '')
  2294. $fileName = 'image.jpg';
  2295. header("Content-type: image/jpg");
  2296. $content = file_get_contents($img);
  2297. if ($queryStringVars->keyExists("option"))
  2298. {
  2299. header("Content-Disposition: inline; filename=" . $fileName);
  2300. $thumb = imagecreatefromstring($content);
  2301. }
  2302. else
  2303. {
  2304. $source = imagecreatefromstring($content);
  2305. $thumb = ImageHelper::createThumbnail($source, 140, 140);
  2306. }
  2307. imagejpeg($thumb);
  2308. }
  2309. else
  2310. {
  2311. header("Content-type: image/gif");
  2312. $missing = ImageHelper::createDummy();
  2313. imagegif($missing);
  2314. }
  2315. exit(0);
  2316. }
  2317. }
  2318. }
  2319. /**
  2320. * Handles resource compression
  2321. *
  2322. * @package WebCore
  2323. * @subpackage Web
  2324. */
  2325. class ResourcesHttpHandler extends ObjectBase implements IHttpHandler
  2326. {
  2327. /**
  2328. * Handles resource compression from Memcached or filesystem
  2329. */
  2330. public function handleRequest()
  2331. {
  2332. $queryStringVars = HttpRequest::getInstance()->getQueryStringVars();
  2333. $fileName = '';
  2334. if ($queryStringVars->keyExists("_resource_hash") || $queryStringVars->keyExists("_cache_hash"))
  2335. {
  2336. $ext = "js";
  2337. if ($queryStringVars->keyExists("_resource_ext"))
  2338. $ext = $queryStringVars->getValue("_resource_ext");
  2339. header("Content-Type: text/" . $ext);
  2340. ResourcesCompressor::getInstance()->compressResource();
  2341. if ($queryStringVars->keyExists("_resource_hash"))
  2342. {
  2343. $hash = $queryStringVars->getValue("_resource_hash");
  2344. $cache = CacheManagerBase::fromSettings();
  2345. if ($cache->contains($hash))
  2346. echo $cache->get($hash);
  2347. }
  2348. else
  2349. {
  2350. chdir(dirname($_SERVER['SCRIPT_FILENAME']));
  2351. $hash = $queryStringVars->getValue("_cache_hash");
  2352. $path = HttpContext::getDocumentRoot() . "cache/" . $hash;
  2353. if (file_exists($path))
  2354. echo file_get_contents($path);
  2355. }
  2356. exit(0);
  2357. }
  2358. }
  2359. }
  2360. /**
  2361. * Represents a Uniform Resource Identifier (URI)
  2362. * Provides functionality to parse and modify a given Uri
  2363. *
  2364. * @package WebCore
  2365. * @subpackage Web
  2366. */
  2367. class UniformResourceIdentifier extends SerializableObjectBase
  2368. {
  2369. protected $scheme;
  2370. protected $host;
  2371. protected $port;
  2372. protected $username;
  2373. protected $password;
  2374. protected $path;
  2375. protected $query;
  2376. protected $fragment;
  2377. /**
  2378. * Creates a new instance of this class
  2379. * @param string $uri Optional uri to decompose. If not provided, tries to read the current request Uri
  2380. */
  2381. public function __construct($uri = '')
  2382. {
  2383. if (!is_string($uri)) throw new SystemException(SystemException::EX_INVALIDPARAMETER, 'uri parameter expects a string');
  2384. $contextInfo = HttpContextInfo::getInstance();
  2385. if ($uri === '') $uri = $contextInfo->getRequestUri();
  2386. $components = parse_url($uri);
  2387. $this->setScheme(isset($components['scheme']) ? $components['scheme'] : 'http');
  2388. $this->setHost(isset($components['host']) ? $components['host'] : $contextInfo->getRequestHost());
  2389. $this->setPort(isset($components['port']) ? $components['port'] : '');
  2390. $this->setUsername(isset($components['user']) ? $components['user'] : '');
  2391. $this->setPassword(isset($components['pass']) ? $components['pass'] : '');
  2392. $this->setPath(isset($components['path']) ? $components['path'] : $contextInfo->getScriptVirtualPath());
  2393. $this->setQuery(isset($components['query']) ? $components['query'] : $contextInfo->getRequestQueryString());
  2394. $this->setFragment(isset($components['fragment']) ? $components['fragment'] : '');
  2395. }
  2396. /**
  2397. * Creates a new instance of this class
  2398. * @return UniformResourceIdentifier
  2399. */
  2400. public static function createInstance()
  2401. {
  2402. return new UniformResourceIdentifier('');
  2403. }
  2404. public function __toString()
  2405. {
  2406. return $this->toString();
  2407. }
  2408. /**
  2409. * Converts the URI to a string
  2410. * @return string
  2411. */
  2412. public function toString()
  2413. {
  2414. $result = $this->getScheme() . '://';
  2415. $hasUsername = $this->getUsername() != '';
  2416. $hasPassword = $this->getPassword() != '';
  2417. if ($hasUsername && $hasPassword)
  2418. {
  2419. $result .= $this->getUsername() . ':' . $this->getPassword() . '@';
  2420. }
  2421. elseif($hasUsername && !$hasPassword)
  2422. {
  2423. $result .= $this->getUsername() . '@';
  2424. }
  2425. $result .= $this->getHost() . $this->getPath();
  2426. if ($this->getQuery() != '') $result .= '?' . $this->getQuery();
  2427. if ($this->getFragment() != '') $result .= '#' . $this->getFragment();
  2428. return $result;
  2429. }
  2430. /**
  2431. * Gets the URI as a base64-encoded string
  2432. * @return string
  2433. */
  2434. public function toBase64String()
  2435. {
  2436. return base64_encode($this->toString());
  2437. }
  2438. /**
  2439. * Removes a query string variable name-value pair from the query string
  2440. * @param string $varName The name of the variable to remove from the query string
  2441. */
  2442. public function removeQueryVariable($varName)
  2443. {
  2444. $queryStr = '';
  2445. $vars = array();
  2446. parse_str($this->getQuery(), $vars);
  2447. $keys = array_keys($vars);
  2448. for ($i = 0; $i < count($keys); $i++)
  2449. {
  2450. $keyName = $keys[$i];
  2451. if ($keyName == $varName) continue;
  2452. $value = $vars[$keyName];
  2453. $queryStr .= urlencode($keyName) . '=' . urlencode($value) . '&';
  2454. }
  2455. $queryStr = StringHelper::replaceEnd($queryStr, '&', '');
  2456. $this->setQuery($queryStr);
  2457. }
  2458. /**
  2459. * Adds a Query string name-value pair to the query string
  2460. * @param string $varName The name of the variable to add
  2461. * @param string $value The value of the variable
  2462. */
  2463. public function addQueryVariable($varName, $value)
  2464. {
  2465. $queryStr = $this->getQuery();
  2466. $queryStr .= '&' . urlencode($varName) . '=' . urlencode($value);
  2467. $queryStr = StringHelper::replaceStart($queryStr, '&', '');
  2468. $this->setQuery($queryStr);
  2469. }
  2470. public function getScheme()
  2471. {
  2472. return $this->scheme;
  2473. }
  2474. public function setScheme($value)
  2475. {
  2476. $this->scheme = $value;
  2477. }
  2478. public function getHost()
  2479. {
  2480. return $this->host;
  2481. }
  2482. public function setHost($value)
  2483. {
  2484. $this->host = $value;
  2485. }
  2486. public function getPort()
  2487. {
  2488. return $this->port;
  2489. }
  2490. public function setPort($value)
  2491. {
  2492. $this->port = $value;
  2493. }
  2494. public function getUsername()
  2495. {
  2496. return $this->username;
  2497. }
  2498. public function setUsername($value)
  2499. {
  2500. $this->username = $value;
  2501. }
  2502. public function getPassword()
  2503. {
  2504. return $this->password;
  2505. }
  2506. public function setPassword($value)
  2507. {
  2508. $this->password = $value;
  2509. }
  2510. public function getPath()
  2511. {
  2512. return $this->path;
  2513. }
  2514. public function setPath($value)
  2515. {
  2516. $this->path = $value;
  2517. }
  2518. public function getQuery()
  2519. {
  2520. return $this->query;
  2521. }
  2522. public function setQuery($value)
  2523. {
  2524. $this->query = $value;
  2525. }
  2526. public function getFragment()
  2527. {
  2528. return $this->fragment;
  2529. }
  2530. public function setFragment($value)
  2531. {
  2532. $this->fragment = $value;
  2533. }
  2534. }
  2535. ?>