PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/samples/install.php

https://github.com/jesuszazueta/merchant-sdk-php
PHP | 476 lines | 373 code | 41 blank | 62 comment | 57 complexity | 1a48cbea6b2eba70b544a83f670d3d15 MD5 | raw file
Possible License(s): BitTorrent-1.0
  1. <?php
  2. /**
  3. * Downloads PayPal PHP SDK dependencies based on your composer.json file
  4. */
  5. define('DS', DIRECTORY_SEPARATOR);
  6. define('COMPOSER_FILE', 'composer.json');
  7. // name of the bootstrap file in custom installation
  8. define('BOOTSTRAP_FILE', 'PPBootStrap.php');
  9. // name of the SDK configuration file
  10. define('CONFIGURATION_FILE', 'sdk_config.ini');
  11. // URL from where the composer.json is downloaded if not present
  12. define('COMPOSER_URL', 'https://raw.github.com/paypal/merchant-sdk-php/stable/samples/composer.json');
  13. // Flag to control whether composer should be used for installation
  14. $useComposer = false;
  15. init($useComposer);
  16. createAutoload();
  17. createConfig(CONFIGURATION_FILE);
  18. createBootStrap(BOOTSTRAP_FILE);
  19. echo "Installation successful";
  20. exit(0);
  21. function init($useComposer) {
  22. // download if composer.json is not present
  23. if(!file_exists(COMPOSER_FILE)) {
  24. $fp = fopen(COMPOSER_FILE, "w");
  25. curlExec(COMPOSER_URL, $fp);
  26. fclose($fp);
  27. }
  28. // check if composer is installed
  29. if($useComposer) {
  30. @exec('composer', $output, $status);
  31. if( $status == 0) {
  32. @exec('composer update', $output, $status);
  33. var_dump($output);
  34. exit($status);
  35. } else {
  36. @exec('composer.phar', $output, $status);
  37. if( $status == 0)
  38. {
  39. @exec('composer.phar update', $output, $status);
  40. var_dump($output);
  41. exit($status);
  42. }
  43. }
  44. } else {
  45. echo "composer not installed or 'useComposer' is set to false in install.php." . PHP_EOL;
  46. echo "Running custom installation ... " . PHP_EOL;
  47. $extensions = array('zip', 'curl', 'openssl');
  48. foreach($extensions as $e) {
  49. if (!extension_loaded($e)) {
  50. echo PHP_EOL . "Please enable the $e extension. This script requires the " . implode(", ", $extensions) . " extensions to work correctly.";
  51. exit(1);
  52. }
  53. }
  54. $json = @file_get_contents(COMPOSER_FILE);
  55. $json_a = json_decode($json, true);
  56. //array $processsed contains list of dependencies that have already been downloaded
  57. $processed = array();
  58. foreach (getDependency($json_a) as $dependency ) {
  59. customInstall($dependency, $dependency['group'], $processed);
  60. }
  61. }
  62. }
  63. /*
  64. * get the correct tag based on the tag in composer.json
  65. * ex: get v3.1.4 if the entry in composer.json is 3.1.*
  66. * @param $inputTag the tag in composer.json
  67. * @param array $array array of all the tags fetched from github
  68. */
  69. function getTag($inputTag, $tagArray, $branchArray)
  70. {
  71. natsort($tagArray);
  72. if(strpos($inputTag, '*') === 0 )
  73. {
  74. return end($tagArray);
  75. }
  76. else if(((strpos($inputTag, '>')) !== false) && (strpos($inputTag, '>') >=0))
  77. {
  78. if(!in_array($inputTag, $tagArray))
  79. {
  80. echo "error: invalid version tag in composer.json";
  81. exit();
  82. }
  83. return end($tagArray);
  84. }
  85. else
  86. {
  87. if(strpos($inputTag, '<=') === 0)
  88. {
  89. $strippedTag = 'v'.str_replace('<=', '', $inputTag);
  90. foreach ($tagArray as $version)
  91. {
  92. if(version_compare($strippedTag, strtolower($version)) == 1 || version_compare($strippedTag, strtolower($version)) == 0)
  93. {
  94. $tag = $version;
  95. }
  96. }
  97. if(!in_array($tag, $tagArray))
  98. {
  99. echo "error: invalid version tag in composer.json";
  100. exit();
  101. }
  102. return $tag;
  103. }
  104. else if(strpos($inputTag, '<') === 0)
  105. {
  106. $strippedTag = 'v'.str_replace('<', '', $inputTag);
  107. foreach ($tagArray as $version)
  108. {
  109. if(version_compare($strippedTag, strtolower($version)) == 1)
  110. {
  111. $tag = $version;
  112. }
  113. }
  114. if(!in_array($tag, $tagArray))
  115. {
  116. echo "error: invalid version tag in composer.json";
  117. exit();
  118. }
  119. return $tag;
  120. }
  121. else if(strpos($inputTag, '*'))
  122. {
  123. $exp = explode('*', $inputTag);
  124. $tag = 'v'.str_replace('*', '0', $inputTag);
  125. foreach ($tagArray as $version)
  126. {
  127. if(strpos($version, $exp['0']) == 1 && version_compare($tag, $version) == -1)
  128. {
  129. $tag = $version;
  130. }
  131. }
  132. if(!in_array($tag, $tagArray))
  133. {
  134. echo "error: invalid version tag in composer.json";
  135. exit();
  136. }
  137. return $tag;
  138. }
  139. else
  140. {
  141. $inputTag = str_replace('dev-', '', $inputTag);
  142. if(!in_array($inputTag, $tagArray) && !in_array($inputTag, $branchArray))
  143. {
  144. echo "error: invalid version tag or branch in composer.json";
  145. exit();
  146. }
  147. return $inputTag;
  148. }
  149. }
  150. }
  151. /*
  152. * extract the tags/branches from github reference API response
  153. */
  154. function extractRef($url)
  155. {
  156. $reference = json_decode(curlExec($url));
  157. if(strpos($reference['0']->ref, 'refs/tags/') === 0)
  158. {
  159. foreach ($reference as $ref)
  160. {
  161. $array[] = str_replace('refs/tags/', '', $ref->ref);
  162. }
  163. }
  164. else
  165. {
  166. foreach ($reference as $ref)
  167. {
  168. $array[] = str_replace('refs/heads/', '', $ref->ref);
  169. }
  170. }
  171. return $array;
  172. }
  173. /**
  174. * @param array $dependency
  175. * @param array $installDir directory where the dependency must be copied to
  176. * @param array $processed contains list of directories already scanned for dependency
  177. */
  178. function customInstall($dependency, $installDir, &$processed) {
  179. if(isset($dependency['autoload']['psr-0']))
  180. {
  181. echo "error: The SDK you are trying to install or one of its dependeincies is namespace based. enter the specific version in composer.json to install non-namespace based SDK. Else download the latest SDK from github for namespace based SDK";
  182. exit();
  183. }
  184. $tagUrl = sprintf('https://api.github.com/repos/%s/%s/git/refs/tags/',
  185. $dependency['group'], $dependency['artifact']);
  186. $branchUrl = sprintf('https://api.github.com/repos/%s/%s/git/refs/heads/',
  187. $dependency['group'], $dependency['artifact']);
  188. $branchArray = extractRef($branchUrl);
  189. $tagsArray = extractRef($tagUrl);
  190. $dependency['branch'] = getTag($dependency['branch'], $tagsArray, $branchArray);
  191. // download zip from github
  192. $downloadUrl = sprintf('https://api.github.com/repos/%s/%s/zipball/%s',
  193. $dependency['group'], $dependency['artifact'], $dependency['branch']);
  194. if(!in_array($downloadUrl, $processed)) {
  195. echo "Downloading " . $dependency['artifact'] . ' - ' . $dependency['branch'] . PHP_EOL;
  196. $dest = 'vendor/' . $installDir . '/';
  197. $fileZip = tempnam(sys_get_temp_dir(), 'ppzip');
  198. $fp = fopen($fileZip, "w");
  199. curlExec($downloadUrl, $fp);
  200. $processed[] = $downloadUrl;
  201. // extract the downloaded zip
  202. $zip = new ZipArchive;
  203. if($zip->open($fileZip) != "true") {
  204. echo PHP_EOL . "Could not open $fileZip";
  205. exit;
  206. }
  207. $zip->extractTo($dest);
  208. $zip->close();
  209. fclose($fp);
  210. unlink($fileZip);
  211. // scan extracted directory for nested dependency
  212. foreach (glob("$dest/**/composer.json") as $composer) {
  213. $json = file_get_contents($composer);
  214. $json_a = json_decode($json, true);
  215. $dependencies = getDependency($json_a);
  216. foreach ($dependencies as $dependency ) {
  217. customInstall($dependency, $dependency['group'], $processed);
  218. }
  219. }
  220. }
  221. }
  222. /*
  223. * @param array $json_a composer.json converted to array
  224. */
  225. function getDependency($json_a) {
  226. if( !array_key_exists('require', $json_a)) {
  227. return array();
  228. }
  229. $res = array();
  230. foreach ($json_a['require'] as $key => $val) {
  231. if(strpos($key, '/')) {
  232. $parts = explode('/', $key);
  233. // Convert versions such as "dev-xyz" to "xyz"
  234. $pos = strpos($val, '-');
  235. if($pos == null || empty($pos)) {
  236. $branch = $val;
  237. } else {
  238. $branch = substr($val, $pos+1);
  239. }
  240. $batch['group'] = $parts[0] ;
  241. $batch['artifact'] = $parts[1];
  242. $batch['branch'] = $branch;
  243. $res[] = $batch;
  244. }
  245. }
  246. return $res;
  247. }
  248. /*
  249. * curl execute
  250. * @param $targetUrl url to hit
  251. * @param $writeToFile file to which the received data to be written
  252. */
  253. function curlExec($targetUrl, $writeToFile = null) {
  254. $ch = curl_init();
  255. curl_setopt($ch, CURLOPT_URL, $targetUrl);
  256. curl_setopt($ch, CURLOPT_FAILONERROR, true);
  257. curl_setopt($ch, CURLOPT_HEADER, 0);
  258. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  259. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  260. curl_setopt($ch, CURLOPT_USERAGENT, 'curl/installScript');
  261. curl_setopt($ch, CURLOPT_BINARYTRANSFER,true);
  262. curl_setopt($ch, CURLOPT_TIMEOUT, 60);
  263. curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
  264. curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
  265. curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
  266. if($writeToFile != null)
  267. {
  268. curl_setopt($ch, CURLOPT_FILE, $writeToFile);
  269. }
  270. $res = curl_exec($ch);
  271. if (!$res) {
  272. echo PHP_EOL . "cURL error number:" .curl_errno($ch) . " for $targetUrl";
  273. echo PHP_EOL . "cURL error:" . curl_error($ch);
  274. exit;
  275. }
  276. curl_close($ch);
  277. return $res;
  278. }
  279. /**
  280. * Autoloads all the classes
  281. * contributor: https://github.com/rrehbeindoi
  282. */
  283. function createAutoload() {
  284. $libraryPath = dirname(__FILE__) . '/';
  285. $loaderClass = 'PPAutoloader';
  286. $loaderFile = $loaderClass . '.php';
  287. echo "Generating autoload file ".PHP_EOL;
  288. /**
  289. * From comment by "Mike" on http://us2.php.net/manual/en/function.glob.php
  290. *
  291. * @param string $pattern
  292. * @param int $flags - as per glob function
  293. * @return array of strings
  294. */
  295. function glob_recursive($pattern, $flags = 0) {
  296. $files = glob($pattern, $flags);
  297. foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir)
  298. {
  299. $files = array_merge($files, glob_recursive($dir.'/'.basename($pattern), $flags));
  300. }
  301. return $files;
  302. }
  303. /**
  304. * Use built in parser to get class and interface names from a script
  305. *
  306. * Based on code from http://stackoverflow.com/questions/7153000/get-class-name-from-file
  307. *
  308. * @param string $source php source to parse
  309. * @return array of strings
  310. */
  311. function get_classes_defined($source) {
  312. $classes = array();
  313. $i = 0;
  314. $tokens = token_get_all($source);
  315. $length = count($tokens);
  316. for ($i = 0; $i < $length; $i++) {
  317. if (in_array($tokens[$i][0], array(T_CLASS, T_INTERFACE))) {
  318. for ($j = $i + 1; $j < $length; $j++) {
  319. if ($tokens[$j] === '{') {
  320. $classes[] = $tokens[$i+2][1];
  321. break;
  322. }
  323. }
  324. }
  325. }
  326. return $classes;
  327. }
  328. $fileList = glob_recursive($libraryPath . '*.php');
  329. $classes = array();
  330. foreach ($fileList as $file) {
  331. // Trim off the absolute path
  332. $filename = str_replace($libraryPath, '', $file);
  333. if ($filename === $loaderFile) {
  334. // Don't include the autoloader in the autoloader map
  335. continue;
  336. }
  337. $found = get_classes_defined(file_get_contents($file));
  338. foreach ($found as $class) {
  339. $class = strtolower($class);
  340. if (isset($classes[$class])) {
  341. ;
  342. //echo "Warning: class [{$class}] is defined in both\n\t{$filename}\n\t{$classes[$class]}\n";
  343. }
  344. $classes[$class] = $filename;
  345. }
  346. }
  347. ksort($classes, SORT_STRING);
  348. $classList = var_export($classes, true);
  349. $script = <<< SCRIPT
  350. <?php
  351. /**
  352. * Basic class-map auto loader generated by install.php.
  353. * Do not modify.
  354. */
  355. class {$loaderClass} {
  356. private static \$map = {$classList};
  357. public static function loadClass(\$class) {
  358. \$class = strtolower(trim(\$class, '\\\\'));
  359. if (isset(self::\$map[\$class])) {
  360. require dirname(__FILE__) . '/' . self::\$map[\$class];
  361. }
  362. }
  363. public static function register() {
  364. spl_autoload_register(array(__CLASS__, 'loadClass'), true);
  365. }
  366. }
  367. SCRIPT;
  368. file_put_contents($loaderFile, $script);
  369. }
  370. /**
  371. * Creates a config file if one is not present
  372. * @param string $configFile name of the configuration file
  373. */
  374. function createConfig($configFile) {
  375. if(!file_exists($configFile)) {
  376. echo "Generating $configFile. You must update it with your account details." . PHP_EOL;
  377. $script = <<< SCRIPT
  378. ; Integration mode - Must be one of sandbox/live
  379. mode = sandbox
  380. ;Account credentials
  381. [Account]
  382. ; Update your account credentials from developer portal here
  383. acct1.UserName =
  384. acct1.Password =
  385. acct1.Signature =
  386. ;Connection Information
  387. [Http]
  388. http.ConnectionTimeOut = 30
  389. http.Retry = 1
  390. ;Logging Information
  391. [Log]
  392. log.FileName=PayPal.log
  393. log.LogLevel=INFO
  394. log.LogEnabled=true
  395. SCRIPT;
  396. file_put_contents($configFile, $script);
  397. }
  398. }
  399. /**
  400. * initiates and installs the SDK
  401. */
  402. function createBootStrap($bootstrapFile) {
  403. if(!file_exists($bootstrapFile)) {
  404. $script = <<< SCRIPT
  405. <?php
  406. /**
  407. * Include this file in your application. This file sets up the required classloader based on
  408. * whether you used composer or the custom installer.
  409. */
  410. // Let the SDK know where the config file resides.
  411. define('PP_CONFIG_PATH', dirname(__FILE__));
  412. if(file_exists( dirname(__FILE__). '/vendor/autoload.php')) {
  413. require 'vendor/autoload.php';
  414. } else {
  415. require 'PPAutoloader.php';
  416. PPAutoloader::register();
  417. }
  418. SCRIPT;
  419. file_put_contents($bootstrapFile, $script);
  420. }
  421. }