InstallationChecker.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  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@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Gdata
  17. * @subpackage Demos
  18. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * Simple class to verify that the server that this is run on has a correct
  23. * installation of the Zend Framework Gdata component.
  24. */
  25. class InstallationChecker {
  26. const CSS_WARNING = '.warning { color: #fff; background-color: #AF0007;}';
  27. const CSS_SUCCESS = '.success { color: #000; background-color: #69FF4F;}';
  28. const CSS_ERROR = '.error { color: #fff; background-color: #FF9FA3;}';
  29. const PHP_EXTENSION_ERRORS = 'PHP Extension Errors';
  30. const PHP_MANUAL_LINK_FRAGMENT = 'http://us.php.net/manual/en/book.';
  31. const PHP_REQUIREMENT_CHECKER_ID = 'PHP Requirement checker v0.1';
  32. const SSL_CAPABILITIES_ERRORS = 'SSL Capabilities Errors';
  33. const YOUTUBE_API_CONNECTIVITY_ERRORS = 'YouTube API Connectivity Errors';
  34. const ZEND_GDATA_INSTALL_ERRORS = 'Zend Framework Installation Errors';
  35. const ZEND_SUBVERSION_URI = 'http://framework.zend.com/download/subversion';
  36. private static $REQUIRED_EXTENSIONS = array(
  37. 'ctype', 'dom', 'libxml', 'spl', 'standard', 'openssl');
  38. private $_allErrors = array(
  39. self::PHP_EXTENSION_ERRORS => array(
  40. 'tested' => false, 'errors' => null),
  41. self::ZEND_GDATA_INSTALL_ERRORS => array(
  42. 'tested' => false, 'errors' => null),
  43. self::SSL_CAPABILITIES_ERRORS => array(
  44. 'tested' => false, 'errors' => null),
  45. self::YOUTUBE_API_CONNECTIVITY_ERRORS => array(
  46. 'tested' => false, 'errors' => null)
  47. );
  48. private $_sapiModeCLI = null;
  49. /**
  50. * Create a new InstallationChecker object and run verifications.
  51. * @return void
  52. */
  53. public function __construct()
  54. {
  55. $this->determineIfInCLIMode();
  56. $this->runAllVerifications();
  57. $this->outputResults();
  58. }
  59. /**
  60. * Set the sapiModeCLI variable to true if we are running CLI mode.
  61. *
  62. * @return void
  63. */
  64. private function determineIfInCLIMode()
  65. {
  66. if (php_sapi_name() == 'cli') {
  67. $this->_sapiModeCLI = true;
  68. }
  69. }
  70. /**
  71. * Getter for sapiModeCLI variable.
  72. *
  73. * @return boolean True if we are running in CLI mode.
  74. */
  75. public function runningInCLIMode()
  76. {
  77. if ($this->_sapiModeCLI) {
  78. return true;
  79. } else {
  80. return false;
  81. }
  82. }
  83. /**
  84. * Run verifications, stopping at each step if there is a failure.
  85. *
  86. * @return void
  87. */
  88. public function runAllVerifications()
  89. {
  90. if (!$this->validatePHPExtensions()) {
  91. return;
  92. }
  93. if (!$this->validateZendFrameworkInstallation()) {
  94. return;
  95. }
  96. if (!$this->testSSLCapabilities()) {
  97. return;
  98. }
  99. if (!$this->validateYouTubeAPIConnectivity()) {
  100. return;
  101. }
  102. }
  103. /**
  104. * Validate that the required PHP Extensions are installed and available.
  105. *
  106. * @return boolean False if there were errors.
  107. */
  108. private function validatePHPExtensions()
  109. {
  110. $phpExtensionErrors = array();
  111. foreach (self::$REQUIRED_EXTENSIONS as $requiredExtension) {
  112. if (!extension_loaded($requiredExtension)) {
  113. $requiredExtensionError = $requiredExtension .
  114. ' extension missing';
  115. $documentationLink = null;
  116. if ($requiredExtension != 'standard') {
  117. $documentationLink = self::PHP_MANUAL_LINK_FRAGMENT .
  118. $requiredExtension . '.php';
  119. $documentationLink =
  120. $this->checkAndAddHTMLLink($documentationLink);
  121. } else {
  122. $documentationLink = self::PHP_MANUAL_LINK_FRAGMENT .
  123. 'spl.php';
  124. $documentationLink =
  125. $this->checkAndAddHTMLLink($documentationLink);
  126. }
  127. if ($documentationLink) {
  128. $phpExtensionErrors[] = $requiredExtensionError .
  129. ' - refer to ' . $documentationLink;
  130. }
  131. }
  132. }
  133. $this->_allErrors[self::PHP_EXTENSION_ERRORS]['tested'] = true;
  134. if (count($phpExtensionErrors) > 0) {
  135. $this->_allErrors[self::PHP_EXTENSION_ERRORS]['errors'] =
  136. $phpExtensionErrors;
  137. return false;
  138. }
  139. return true;
  140. }
  141. /**
  142. * Validate that the Gdata component of Zend Framework is installed
  143. * properly. Also checks that the required YouTube API helper methods are
  144. * found.
  145. *
  146. * @return boolean False if there were errors.
  147. */
  148. private function validateZendFrameworkInstallation()
  149. {
  150. $zendFrameworkInstallationErrors = array();
  151. $zendLoaderPresent = false;
  152. try {
  153. $zendLoaderPresent = @fopen('Zend/Loader.php', 'r', true);
  154. } catch (Exception $e) {
  155. $zendFrameworkInstallationErrors[] = 'Exception thrown trying to ' .
  156. 'access Zend/Loader.php using \'use_include_path\' = true ' .
  157. 'Make sure you include the Zend Framework in your ' .
  158. 'include_path which currently contains: "' .
  159. ini_get('include_path') . '"';
  160. }
  161. if ($zendLoaderPresent) {
  162. @fclose($zendLoaderPresent);
  163. require_once('Zend/Loader.php');
  164. require_once('Zend/Version.php');
  165. Zend_Loader::loadClass('Zend_Gdata_YouTube');
  166. Zend_Loader::loadClass('Zend_Gdata_YouTube_VideoEntry');
  167. $yt = new Zend_Gdata_YouTube();
  168. $videoEntry = $yt->newVideoEntry();
  169. if (!method_exists($videoEntry, 'setVideoTitle')) {
  170. $zendFrameworkMessage = 'Your version of the ' .
  171. 'Zend Framework ' . Zend_Version::VERSION . ' is too old' .
  172. ' to run the YouTube demo application and does not' .
  173. ' contain the new helper methods. Please check out a' .
  174. ' newer version from Zend\'s repository: ' .
  175. checkAndAddHTMLLink(self::ZEND_SUBVERSION_URI);
  176. $zendFrameworkInstallationErrors[] = $zendFrameworkMessage;
  177. }
  178. } else {
  179. if (count($zendFrameworkInstallationErrors) < 1) {
  180. $zendFrameworkInstallationErrors[] = 'Exception thrown trying' .
  181. ' to access Zend/Loader.php using \'use_include_path\' =' .
  182. ' true. Make sure you include Zend Framework in your' .
  183. ' include_path which currently contains: ' .
  184. ini_get('include_path');
  185. }
  186. }
  187. $this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['tested'] = true;
  188. if (count($zendFrameworkInstallationErrors) > 0) {
  189. $this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['errors'] =
  190. $zendFrameworkInstallationErrors;
  191. return false;
  192. }
  193. return true;
  194. }
  195. /**
  196. * Create HTML link from an input string if not in CLI mode.
  197. *
  198. * @param string The error message to be converted to a link.
  199. * @return string Either the original error message or an HTML version.
  200. */
  201. private function checkAndAddHTMLLink($inputString) {
  202. if (!$this->runningInCLIMode()) {
  203. return $this->makeHTMLLink($inputString);
  204. } else {
  205. return $inputString;
  206. }
  207. }
  208. /**
  209. * Create an HTML link from a string.
  210. *
  211. * @param string The string to be made into link text and anchor target.
  212. * @return string HTML link.
  213. */
  214. private function makeHTMLLink($inputString)
  215. {
  216. return '<a href="'. $inputString . '" target="_blank">' .
  217. $inputString . '</a>';
  218. }
  219. /**
  220. * Validate that SSL Capabilities are available.
  221. *
  222. * @return boolean False if there were errors.
  223. */
  224. private function testSSLCapabilities()
  225. {
  226. $sslCapabilitiesErrors = array();
  227. require_once 'Zend/Loader.php';
  228. Zend_Loader::loadClass('Zend_Http_Client');
  229. $httpClient = new Zend_Http_Client(
  230. 'https://www.google.com/accounts/AuthSubRequest');
  231. $response = $httpClient->request();
  232. $this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['tested'] = true;
  233. if ($response->isError()) {
  234. $sslCapabilitiesErrors[] = 'Response from trying to access' .
  235. ' \'https://www.google.com/accounts/AuthSubRequest\' ' .
  236. $response->getStatus() . ' - ' . $response->getMessage();
  237. }
  238. if (count($sslCapabilitiesErrors) > 0) {
  239. $this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['errors'] =
  240. $sslCapabilitiesErrors;
  241. return false;
  242. }
  243. return true;
  244. }
  245. /**
  246. * Validate that we can connect to the YouTube API.
  247. *
  248. * @return boolean False if there were errors.
  249. */
  250. private function validateYouTubeAPIConnectivity()
  251. {
  252. $connectivityErrors = array();
  253. require_once 'Zend/Loader.php';
  254. Zend_Loader::loadClass('Zend_Gdata_YouTube');
  255. $yt = new Zend_Gdata_YouTube();
  256. $topRatedFeed = $yt->getTopRatedVideoFeed();
  257. if ($topRatedFeed instanceof Zend_Gdata_YouTube_VideoFeed) {
  258. if ($topRatedFeed->getTotalResults()->getText() < 1) {
  259. $connectivityErrors[] = 'There was less than 1 video entry' .
  260. ' in the \'Top Rated Video Feed\'';
  261. }
  262. } else {
  263. $connectivityErrors[] = 'The call to \'getTopRatedVideoFeed()\' ' .
  264. 'did not result in a Zend_Gdata_YouTube_VideoFeed object';
  265. }
  266. $this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] =
  267. true;
  268. if (count($connectivityErrors) > 0) {
  269. $this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] =
  270. $connectivityErrors;
  271. return false;
  272. }
  273. return true;
  274. }
  275. /**
  276. * Dispatch a call to outputResultsInHTML or outputResultsInText pending
  277. * the current SAPI mode.
  278. *
  279. * @return void
  280. */
  281. public function outputResults()
  282. {
  283. if ($this->_sapiModeCLI) {
  284. print $this->getResultsInText();
  285. } else {
  286. print $this->getResultsInHTML();
  287. }
  288. }
  289. /**
  290. * Return a string representing the results of the verifications.
  291. *
  292. * @return string A string representing the results.
  293. */
  294. private function getResultsInText()
  295. {
  296. $output = "== Ran PHP Installation Checker using CLI ==\n";
  297. $error_count = 0;
  298. foreach($this->_allErrors as $key => $value) {
  299. $output .= $key . ' -- ';
  300. if (($value['tested'] == true) && (count($value['errors']) == 0)) {
  301. $output .= "No errors found\n";
  302. } elseif ($value['tested'] == true) {
  303. $output .= "Tested\n";
  304. $error_count = 0;
  305. foreach ($value['errors'] as $error) {
  306. $output .= "Error number: " . $error_count . "\n--" .
  307. $error . "\n";
  308. }
  309. } else {
  310. $output .= "Not tested\n";
  311. }
  312. $error_count++;
  313. }
  314. return $output;
  315. }
  316. /**
  317. * Return an HTML table representing the results of the verifications.
  318. *
  319. * @return string An HTML string representing the results.
  320. */
  321. private function getResultsInHTML()
  322. {
  323. $html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " .
  324. "\"http://www.w3.org/TR/html4/strict.dtd\">\n".
  325. "<html><head>\n<title>PHP Installation Checker</title>\n" .
  326. "<style type=\"text/css\">\n" .
  327. self::CSS_WARNING . "\n" .
  328. self::CSS_SUCCESS . "\n" .
  329. self::CSS_ERROR . "\n" .
  330. "</style></head>\n" .
  331. "<body>\n<table class=\"verification_table\">" .
  332. "<caption>Ran PHP Installation Checker on " .
  333. gmdate('c') . "</caption>\n";
  334. $error_count = 0;
  335. foreach($this->_allErrors as $key => $value) {
  336. $html .= "<tr><td class=\"verification_type\">" . $key . "</td>";
  337. if (($value['tested'] == true) && (count($value['errors']) == 0)) {
  338. $html .= "<td class=\"success\">Tested</td></tr>\n" .
  339. "<tr><td colspan=\"2\">No errors found</td></tr>\n";
  340. } elseif ($value['tested'] == true) {
  341. $html .= "<td class=\"warning\">Tested</td></tr>\n";
  342. $error_count = 0;
  343. foreach ($value['errors'] as $error) {
  344. $html .= "<tr><td class=\"error\">" . $error_count . "</td>" .
  345. "<td class=\"error\">" . $error . "</td></tr>\n";
  346. }
  347. } else {
  348. $html .= "<td class=\"warning\">Not tested</td></tr>\n";
  349. }
  350. $error_count++;
  351. }
  352. $html .= "</body></html>";
  353. return $html;
  354. }
  355. }
  356. $installationChecker = new InstallationChecker();