/** * Installs a packagist package * * @param string $package_name * @param string|boolean $version_param * @param boolean- * * @return boolean */ public static function install($package_name, $version_param = false, $die_on_duplicate = true) { $package_info = json_decode(file_get_contents(self::URL . "/{$package_name}.json"), true); if (!isset($package_info['status'])) { //has package already been added to the app's packagist file $exists = isset(self::$_packages[$package_name]) ? self::$_packages[$package_name] : false; //check for matching version either new or existing ugradable $to_install = self::match($package_info, $version_param); if ($to_install === false && $exists !== true && $exists !== false) { $to_install = self::match($package_info, $exists); } if ($to_install !== false) { echo "Downloading {$package_name} " . $to_install["version"] . "\n"; //download requires if (isset($to_install["require"])) { foreach ($to_install["require"] as $rpackage => $version) { if ($rpackage == "php") { $php_vmatch = []; preg_match('/([\\>\\=]+)\\s*([0-9\\.]+)/', $version, $php_vmatch); if (version_compare(phpversion(), $php_vmatch[2], $php_vmatch[1]) == false) { die("PHP version {$version} required"); } } elseif (strpos($rpackage, '/') !== false) { self::install($rpackage, $version, false); } } } //get directory names and create if not existing yet $name = $to_install["source"]["url"]; $name = substr($name, strlen('https://github.com/')); $name = str_replace('/', '-', substr($name, 0, strrpos($name, '.'))); $id = substr($to_install["dist"]["reference"], 0, 7); $package_directory = App::libs()->directory('Packagist.' . strtolower($name)); $package_sub = $package_directory->directory("{$name}-{$id}"); if ($package_sub->exists()) { if ($die_on_duplicate) { die("Package version already installed\n"); } else { echo "Package version already installed\n"; return false; } } if (!$package_directory->exists()) { $package_directory->create(); } //download file $package_zip = (string) FileHandler::system('package.zip'); $fp = fopen($package_zip, 'w'); $ch = curl_init($to_install["dist"]["url"]); curl_setopt($ch, CURLOPT_TIMEOUT, 50); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13'); curl_exec($ch); curl_close($ch); fclose($fp); //extract package.zip $zip = new \ZipArchive(); $zip->open($package_zip); $zip->extractTo($package_directory); //remove zip unlink($package_zip); //add .exclude file $package_sub->file(".exclude")->write(''); //get existing installed version $prev_versions = $package_directory->directories(); //remove any existing key from autoload $prev_version_found = false; foreach ($prev_versions as $prev_version) { $prev_version_name = $prev_version->name(); if ($prev_version_name !== "{$name}-{$id}" && isset(self::$_autoload[$prev_version_name])) { $prev_version_found = $prev_version_name; unset(self::$_autoload[$prev_version_name]); } } //let the user know the previous version has been removed from autoload if ($prev_version_found !== false) { echo "A previously installed version was detected and removed from the autoload.json in favor of the new version. The package files still exist in Libs/Packagist/{$name}/{$prev_version_found}\n"; } //add autoload $classmap = []; if (isset($to_install['autoload'])) { // go through autoload foreach ($to_install['autoload'] as $spec => $mapping) { if ($spec == 'classmap') { // loop through the files and fetch the fully qualified classnames // through regex foreach ($mapping as $file) { // can also be directory $d = $package_sub->directory($file); $f = $package_sub->file($file, substr_count($file, '.')); if ($d->exists()) { // look up files inside directory $d_files = $d->files(true); foreach ($d_files as $d_f) { $classes = $d_f->classes(); foreach ($classes as $class) { $source = substr("{$d_f}", strlen("{$d}") + 1); $classmap[$class] = "{$file}/{$source}"; } } } else { $classes = $f->classes(); foreach ($classes as $class) { $classmap[$class] = $file; } } } } else { if ($spec == 'files') { if (!isset($classmap['files'])) { $classmap['files'] = []; } foreach ($mapping as $file) { $classmap['files'][] = $file; } } else { // psr -> go through mapping foreach ($mapping as $prefix => $source) { // get all files in source $directory = $package_sub->directory($source); $files = $directory->files(true); // loop through files and add to class mapping foreach ($files as $file) { $classes = $file->classes(); foreach ($classes as $class) { $classmap[$class] = $source . substr($file, strlen($directory)); } } } } } } self::$_autoload["{$name}-{$id}"] = $classmap; } self::$_packages[$package_name] = '^' . trim($to_install["version"], 'v'); self::save(); return true; } } return false; }