PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/errors/processor.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 596 lines | 438 code | 32 blank | 126 comment | 15 complexity | ff190512d4d642bd79b5787d481340ce MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Errors
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Error processor
  28. *
  29. * @author Magento Core Team <core@magentocommerce.com>
  30. */
  31. class Error_Processor
  32. {
  33. const MAGE_ERRORS_LOCAL_XML = 'local.xml';
  34. const MAGE_ERRORS_DESIGN_XML = 'design.xml';
  35. const DEFAULT_SKIN = 'default';
  36. const ERROR_DIR = 'errors';
  37. /**
  38. * Page title
  39. *
  40. * @var string
  41. */
  42. public $pageTitle;
  43. /**
  44. * Skin URL
  45. *
  46. * @var string
  47. */
  48. public $skinUrl;
  49. /**
  50. * Base URL
  51. *
  52. * @var string
  53. */
  54. public $baseUrl;
  55. /**
  56. * Post data
  57. *
  58. * @var array
  59. */
  60. public $postData;
  61. /**
  62. * Report data
  63. *
  64. * @var array
  65. */
  66. public $reportData;
  67. /**
  68. * Report action
  69. *
  70. * @var string
  71. */
  72. public $reportAction;
  73. /**
  74. * Report ID
  75. *
  76. * @var int
  77. */
  78. public $reportId;
  79. /**
  80. * Report file
  81. *
  82. * @var string
  83. */
  84. protected $_reportFile;
  85. /**
  86. * Show error message
  87. *
  88. * @var bool
  89. */
  90. public $showErrorMsg;
  91. /**
  92. * Show message after sending email
  93. *
  94. * @var bool
  95. */
  96. public $showSentMsg;
  97. /**
  98. * Show form for sending
  99. *
  100. * @var bool
  101. */
  102. public $showSendForm;
  103. /**
  104. * Server script name
  105. *
  106. * @var string
  107. */
  108. protected $_scriptName;
  109. /**
  110. * Is root
  111. *
  112. * @var bool
  113. */
  114. protected $_root;
  115. /**
  116. * Internal config object
  117. *
  118. * @var stdClass
  119. */
  120. protected $_config;
  121. public function __construct()
  122. {
  123. $this->_errorDir = dirname(__FILE__) . '/';
  124. $this->_reportDir = dirname($this->_errorDir) . '/var/report/';
  125. if (!empty($_SERVER['SCRIPT_NAME'])) {
  126. if (in_array(basename($_SERVER['SCRIPT_NAME'],'.php'), array('404','503','report'))) {
  127. $this->_scriptName = dirname($_SERVER['SCRIPT_NAME']);
  128. }
  129. else {
  130. $this->_scriptName = $_SERVER['SCRIPT_NAME'];
  131. }
  132. }
  133. $reportId = (isset($_GET['id'])) ? (int)$_GET['id'] : null;
  134. if ($reportId) {
  135. $this->loadReport($reportId);
  136. }
  137. $this->_indexDir = $this->_getIndexDir();
  138. $this->_root = is_dir($this->_indexDir.'app');
  139. $this->_prepareConfig();
  140. if (isset($_GET['skin'])) {
  141. $this->_setSkin($_GET['skin']);
  142. }
  143. }
  144. /**
  145. * Process 404 error
  146. */
  147. public function process404()
  148. {
  149. $this->pageTitle = 'Error 404: Not Found';
  150. $this->_sendHeaders(404);
  151. $this->_renderPage('404.phtml');
  152. }
  153. /**
  154. * Process 503 error
  155. */
  156. public function process503()
  157. {
  158. $this->pageTitle = 'Error 503: Service Unavailable';
  159. $this->_sendHeaders(503);
  160. $this->_renderPage('503.phtml');
  161. }
  162. /**
  163. * Process report
  164. */
  165. public function processReport()
  166. {
  167. $this->pageTitle = 'There has been an error processing your request';
  168. $this->_sendHeaders(503);
  169. $this->showErrorMsg = false;
  170. $this->showSentMsg = false;
  171. $this->showSendForm = false;
  172. $this->reportAction = $this->_config->action;
  173. $this->_setReportUrl();
  174. if($this->reportAction == 'email') {
  175. $this->showSendForm = true;
  176. $this->sendReport();
  177. }
  178. $this->_renderPage('report.phtml');
  179. }
  180. /**
  181. * Retrieve skin URL
  182. *
  183. * @return string
  184. */
  185. public function getSkinUrl()
  186. {
  187. return $this->getBaseUrl() . self::ERROR_DIR. '/' . $this->_config->skin . '/';
  188. }
  189. /**
  190. * Retrieve base host URL without path
  191. *
  192. * @return string
  193. */
  194. public function getHostUrl()
  195. {
  196. /**
  197. * Define server http host
  198. */
  199. if (!empty($_SERVER['HTTP_HOST'])) {
  200. $host = $_SERVER['HTTP_HOST'];
  201. } elseif (!empty($_SERVER['SERVER_NAME'])) {
  202. $host = $_SERVER['SERVER_NAME'];
  203. } else {
  204. $host = 'localhost';
  205. }
  206. $isSecure = (!empty($_SERVER['HTTPS'])) && ($_SERVER['HTTPS'] != 'off');
  207. $url = ($isSecure ? 'https://' : 'http://') . $host;
  208. if (!empty($_SERVER['SERVER_PORT']) && !in_array($_SERVER['SERVER_PORT'], array(80, 433))) {
  209. $url .= ':' . $_SERVER['SERVER_PORT'];
  210. }
  211. return $url;
  212. }
  213. /**
  214. * Retrieve base URL
  215. *
  216. * @return string
  217. */
  218. public function getBaseUrl($param = false)
  219. {
  220. $path = $this->_scriptName;
  221. if($param && !$this->_root) {
  222. $path = dirname($path);
  223. }
  224. $basePath = str_replace('\\', '/', dirname($path));
  225. return $this->getHostUrl() . ('/' == $basePath ? '' : $basePath) . '/';
  226. }
  227. /**
  228. * Retrieve client IP address
  229. *
  230. * @return string
  231. */
  232. protected function _getClientIp()
  233. {
  234. return (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : 'undefined';
  235. }
  236. /**
  237. * Get index dir
  238. *
  239. * @return string
  240. */
  241. protected function _getIndexDir()
  242. {
  243. $documentRoot = '';
  244. if (!empty($_SERVER['DOCUMENT_ROOT'])) {
  245. $documentRoot = rtrim($_SERVER['DOCUMENT_ROOT'],'/');
  246. }
  247. return dirname($documentRoot . $this->_scriptName) . '/';
  248. }
  249. /**
  250. * Prepare config data
  251. */
  252. protected function _prepareConfig()
  253. {
  254. $local = $this->_loadXml(self::MAGE_ERRORS_LOCAL_XML);
  255. $design = $this->_loadXml(self::MAGE_ERRORS_DESIGN_XML);
  256. //initial settings
  257. $config = new stdClass();
  258. $config->action = '';
  259. $config->subject = 'Store Debug Information';
  260. $config->email_address = '';
  261. $config->trash = 'leave';
  262. $config->skin = self::DEFAULT_SKIN;
  263. //combine xml data to one object
  264. if (!is_null($design) && (string)$design->skin) {
  265. $this->_setSkin((string)$design->skin, $config);
  266. }
  267. if (!is_null($local)) {
  268. if ((string)$local->report->action) {
  269. $config->action = $local->report->action;
  270. }
  271. if ((string)$local->report->subject) {
  272. $config->subject = $local->report->subject;
  273. }
  274. if ((string)$local->report->email_address) {
  275. $config->email_address = $local->report->email_address;
  276. }
  277. if ((string)$local->report->trash) {
  278. $config->trash = $local->report->trash;
  279. }
  280. if ((string)$local->skin) {
  281. $this->_setSkin((string)$local->skin, $config);
  282. }
  283. }
  284. if ((string)$config->email_address == '' && (string)$config->action == 'email') {
  285. $config->action = '';
  286. }
  287. $this->_config = $config;
  288. }
  289. /**
  290. * Load xml file
  291. *
  292. * @param string $config
  293. * return SimpleXMLElement
  294. */
  295. protected function _loadXml($xmlFile)
  296. {
  297. $configPath = $this->_getFilePath($xmlFile);
  298. return ($configPath) ? simplexml_load_file($configPath) : null;
  299. }
  300. /**
  301. * Send error headers
  302. *
  303. * @param int $statusCode
  304. */
  305. protected function _sendHeaders($statusCode)
  306. {
  307. $serverProtocol = !empty($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
  308. switch ($statusCode) {
  309. case 404:
  310. $description = 'Not Found';
  311. break;
  312. case 503:
  313. $description = 'Service Unavailable';
  314. break;
  315. default:
  316. $description = '';
  317. break;
  318. }
  319. header(sprintf('%s %s %s', $serverProtocol, $statusCode, $description), true, $statusCode);
  320. header(sprintf('Status: %s %s', $statusCode, $description), true, $statusCode);
  321. }
  322. /**
  323. * Render page
  324. */
  325. protected function _renderPage($template)
  326. {
  327. $baseTemplate = $this->_getTemplatePath('page.phtml');
  328. $contentTemplate = $this->_getTemplatePath($template);
  329. if ($baseTemplate && $contentTemplate) {
  330. require_once $baseTemplate;
  331. }
  332. }
  333. /**
  334. * Find file path
  335. *
  336. * @param string $file
  337. * @param array $directories
  338. * return $string
  339. */
  340. protected function _getFilePath($file, $directories = null)
  341. {
  342. if (is_null($directories)) {
  343. $directories = array();
  344. if (!$this->_root) {
  345. $directories[] = $this->_indexDir . self::ERROR_DIR . '/';
  346. }
  347. $directories[] = $this->_errorDir;
  348. }
  349. foreach ($directories as $directory) {
  350. if (file_exists($directory . $file)) {
  351. return $directory . $file;
  352. }
  353. }
  354. }
  355. /**
  356. * Find template path
  357. *
  358. * @param string $template
  359. * return $string
  360. */
  361. protected function _getTemplatePath($template)
  362. {
  363. $directories = array();
  364. if (!$this->_root) {
  365. $directories[] = $this->_indexDir . self::ERROR_DIR. '/'. $this->_config->skin . '/';
  366. if ($this->_config->skin != self::DEFAULT_SKIN) {
  367. $directories[] = $this->_indexDir . self::ERROR_DIR . '/'. self::DEFAULT_SKIN . '/';
  368. }
  369. }
  370. $directories[] = $this->_errorDir . $this->_config->skin . '/';
  371. if ($this->_config->skin != self::DEFAULT_SKIN) {
  372. $directories[] = $this->_errorDir . self::DEFAULT_SKIN . '/';
  373. }
  374. return $this->_getFilePath($template, $directories);
  375. }
  376. /**
  377. * Set report data
  378. *
  379. * @param array $reportData
  380. */
  381. protected function _setReportData($reportData)
  382. {
  383. $this->reportData = $reportData;
  384. if (!isset($reportData['url'])) {
  385. $this->reportData['url'] = '';
  386. }
  387. else {
  388. $this->reportData['url'] = $this->getHostUrl() . $reportData['url'];
  389. }
  390. if ($this->reportData['script_name']) {
  391. $this->_scriptName = $this->reportData['script_name'];
  392. }
  393. }
  394. /**
  395. * Create report
  396. *
  397. * @param array $reportData
  398. */
  399. public function saveReport($reportData)
  400. {
  401. $this->reportData = $reportData;
  402. $this->reportId = abs(intval(microtime(true) * rand(100, 1000)));
  403. $this->_reportFile = $this->_reportDir . '/' . $this->reportId;
  404. $this->_setReportData($reportData);
  405. if (!file_exists($this->_reportDir)) {
  406. @mkdir($this->_reportDir, 0777, true);
  407. }
  408. @file_put_contents($this->_reportFile, serialize($reportData));
  409. @chmod($this->_reportFile, 0777);
  410. if (isset($reportData['skin']) && self::DEFAULT_SKIN != $reportData['skin']) {
  411. $this->_setSkin($reportData['skin']);
  412. }
  413. $this->_setReportUrl();
  414. if (headers_sent()) {
  415. print '<script type="text/javascript">';
  416. print "window.location.href = '{$this->reportUrl}';";
  417. print '</script>';
  418. exit;
  419. }
  420. }
  421. /**
  422. * Get report
  423. *
  424. * @param int $reportId
  425. */
  426. public function loadReport($reportId)
  427. {
  428. $this->reportId = $reportId;
  429. $this->_reportFile = $this->_reportDir . '/' . $reportId;
  430. if (!file_exists($this->_reportFile) || !is_readable($this->_reportFile)) {
  431. header("Location: " . $this->getBaseUrl());
  432. die();
  433. }
  434. $this->_setReportData(unserialize(file_get_contents($this->_reportFile)));
  435. }
  436. /**
  437. * Send report
  438. *
  439. */
  440. public function sendReport()
  441. {
  442. $this->pageTitle = 'Error Submission Form';
  443. $this->postData['firstName'] = (isset($_POST['firstname'])) ? trim(htmlspecialchars($_POST['firstname'])) : '';
  444. $this->postData['lastName'] = (isset($_POST['lastname'])) ? trim(htmlspecialchars($_POST['lastname'])) : '';
  445. $this->postData['email'] = (isset($_POST['email'])) ? trim(htmlspecialchars($_POST['email'])) : '';
  446. $this->postData['telephone'] = (isset($_POST['telephone'])) ? trim(htmlspecialchars($_POST['telephone'])) : '';
  447. $this->postData['comment'] = (isset($_POST['comment'])) ? trim(htmlspecialchars($_POST['comment'])) : '';
  448. if (isset($_POST['submit'])) {
  449. if ($this->_validate()) {
  450. $msg = "URL: {$this->reportData['url']}\n"
  451. . "IP Address: {$this->_getClientIp()}\n"
  452. . "First Name: {$this->postData['firstName']}\n"
  453. . "Last Name: {$this->postData['lastName']}\n"
  454. . "E-mail Address: {$this->postData['email']}\n";
  455. if ($this->postData['telephone']) {
  456. $msg .= "Telephone: {$this->postData['telephone']}\n";
  457. }
  458. if ($this->postData['comment']) {
  459. $msg .= "Comment: {$this->postData['comment']}\n";
  460. }
  461. $subject = sprintf('%s [%s]', (string)$this->_config->subject, $this->reportId);
  462. @mail((string)$this->_config->email_address, $subject, $msg);
  463. $this->showSendForm = false;
  464. $this->showSentMsg = true;
  465. } else {
  466. $this->showErrorMsg = true;
  467. }
  468. } else {
  469. $time = gmdate('Y-m-d H:i:s \G\M\T');
  470. $msg = "URL: {$this->reportData['url']}\n"
  471. . "IP Address: {$this->_getClientIp()}\n"
  472. . "Time: {$time}\n"
  473. . "Error:\n{$this->reportData[0]}\n\n"
  474. . "Trace:\n{$this->reportData[1]}";
  475. $subject = sprintf('%s [%s]', (string)$this->_config->subject, $this->reportId);
  476. @mail((string)$this->_config->email_address, $subject, $msg);
  477. if ($this->_config->trash == 'delete') {
  478. @unlink($this->_reportFile);
  479. }
  480. }
  481. }
  482. /**
  483. * Validate submitted post data
  484. *
  485. * @return bool
  486. */
  487. protected function _validate()
  488. {
  489. $email = eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $this->postData['email']);
  490. return ($this->postData['firstName'] && $this->postData['lastName'] && $email);
  491. }
  492. /**
  493. * Skin setter
  494. *
  495. * @param string $value
  496. * @param object $config
  497. */
  498. protected function _setSkin($value, stdClass $config = null)
  499. {
  500. if (preg_match('/^[a-z0-9_]+$/i', $value) && is_dir($this->_indexDir . self::ERROR_DIR . '/' . $value)) {
  501. if (!$config) {
  502. if ($this->_config) {
  503. $config = $this->_config;
  504. }
  505. }
  506. if ($config) {
  507. $config->skin = $value;
  508. }
  509. }
  510. }
  511. /**
  512. * Set current report URL from current params
  513. */
  514. protected function _setReportUrl()
  515. {
  516. if ($this->reportId && $this->_config && isset($this->_config->skin)) {
  517. $this->reportUrl = "{$this->getBaseUrl(true)}errors/report.php?" . http_build_query(array(
  518. 'id' => $this->reportId, 'skin' => $this->_config->skin
  519. ));
  520. }
  521. }
  522. }