*/ class StubGenerator { /** * The list of server variables that are allowed to be modified. * * @var array */ private static $allowedMung = array( 'PHP_SELF', 'REQUEST_URI', 'SCRIPT_FILENAME', 'SCRIPT_NAME' ); /** * The alias to be used in "phar://" URLs. * * @var string */ private $alias; /** * The top header comment banner text. * * @var string. */ private $banner = 'Generated by Box. @link https://github.com/herrera-io/php-box/'; /** * Embed the Extract class in the stub? * * @var boolean */ private $extract = false; /** * The processed extract code. * * @var array */ private $extractCode = array(); /** * Force the use of the Extract class? * * @var boolean */ private $extractForce = false; /** * The location within the Phar of index script. * * @var string */ private $index; /** * Use the Phar::interceptFileFuncs() method? * * @var boolean */ private $intercept = false; /** * The map for file extensions and their mimetypes. * * @var array */ private $mimetypes = array(); /** * The list of server variables to modify. * * @var array */ private $mung = array(); /** * The location of the script to run when a file is not found. * * @var string */ private $notFound; /** * The rewrite function. * * @var string */ private $rewrite; /** * The shebang line. * * @var string */ private $shebang = '#!/usr/bin/env php'; /** * Use Phar::webPhar() instead of Phar::mapPhar()? * * @var boolean */ private $web = false; /** * Sets the alias to be used in "phar://" URLs. * * @param string $alias The alias. * * @return StubGenerator The stub generator. */ public function alias($alias) { $this->alias = $alias; return $this; } /** * Sets the top header comment banner text. * * @param string $banner The banner text. * * @return StubGenerator The stub generator. */ public function banner($banner) { $this->banner = $banner; return $this; } /** * Creates a new instance of the stub generator. * * @return StubGenerator The stub generator. */ public static function create() { return new static(); } /** * Embed the Extract class in the stub? * * @param boolean $extract Embed the class? * @param boolean $force Force the use of the class? * * @return StubGenerator The stub generator. */ public function extract($extract, $force = false) { $this->extract = $extract; $this->extractForce = $force; if ($extract) { $this->extractCode = array( 'constants' => array(), 'class' => array(), ); $code = file_get_contents(__DIR__ . '/Extract.min.php'); $code = preg_replace('/\n+/', "\n", $code); $code = explode("\n", $code); $code = array_slice($code, 2); foreach ($code as $i => $line) { if ((0 === strpos($line, 'use')) && (false === strpos($line, '\\')) ) { unset($code[$i]); } elseif (0 === strpos($line, 'define')) { $this->extractCode['constants'][] = $line; } else { $this->extractCode['class'][] = $line; } } } return $this; } /** * Sets location within the Phar of index script. * * @param string $index The index file. * * @return StubGenerator The stub generator. */ public function index($index) { $this->index = $index; return $this; } /** * Use the Phar::interceptFileFuncs() method in the stub? * * @param boolean $intercept Use interceptFileFuncs()? * * @return StubGenerator The stub generator. */ public function intercept($intercept) { $this->intercept = $intercept; return $this; } /** * Generates the stub. * * @return string The stub. */ public function generate() { $stub = array(); if ('' !== $this->shebang) { $stub[] = $this->shebang; } $stub[] = 'banner) { $stub[] = $this->getBanner(); } if ($this->extract) { $stub[] = join("\n", $this->extractCode['constants']); if ($this->extractForce) { $stub = array_merge($stub, $this->getExtractSections()); } } $stub = array_merge($stub, $this->getPharSections()); if ($this->extract) { if ($this->extractForce) { if ($this->index && !$this->web) { $stub[] = "require \"\$dir/{$this->index}\";"; } } else { end($stub); $stub[key($stub)] .= ' else {'; $stub = array_merge($stub, $this->getExtractSections()); if ($this->index) { $stub[] = "require \"\$dir/{$this->index}\";"; } $stub[] = '}'; } $stub[] = join("\n", $this->extractCode['class']); } $stub[] = "__HALT_COMPILER();"; return join("\n", $stub); } /** * Sets the map for file extensions and their mimetypes. * * @param array $mimetypes The map. * * @return StubGenerator The stub generator. */ public function mimetypes(array $mimetypes) { $this->mimetypes = $mimetypes; return $this; } /** * Sets the list of server variables to modify. * * @param array $list The list. * * @return StubGenerator The stub generator. * * @throws \InvalidArgumentException If the list contains an invalid value. */ public function mung(array $list) { foreach ($list as $value) { if (false === in_array($value, self::$allowedMung)) { throw new \InvalidArgumentException(sprintf( 'The $_SERVER variable "%s" is not allowed.', $value )); } } $this->mung = $list; return $this; } /** * Sets the location of the script to run when a file is not found. * * @param string $script The script. * * @return StubGenerator The stub generator. */ public function notFound($script) { $this->notFound = $script; return $this; } /** * Sets the rewrite function. * * @param string $function The function. * * @return StubGenerator The stub generator. */ public function rewrite($function) { $this->rewrite = $function; return $this; } /** * Sets the shebang line. * * @param string $shebang The shebang line. * * @return StubGenerator The stub generator. */ public function shebang($shebang) { $this->shebang = $shebang; return $this; } /** * Use Phar::webPhar() instead of Phar::mapPhar()? * * @param boolean $web Use Phar::webPhar()? * * @return StubGenerator The stub generator. */ public function web($web) { $this->web = $web; return $this; } /** * Escapes an argument so it can be written as a string in a call. * * @param string $arg The argument. * @param string $quote The quote. * * @return string The escaped argument. */ private function arg($arg, $quote = "'") { return $quote . addcslashes($arg, $quote) . $quote; } /** * Returns the alias map. * * @return string The alias map. */ private function getAlias() { $stub = ''; $prefix = ''; if ($this->extractForce) { $prefix = '$dir/'; } if ($this->web) { $stub .= 'Phar::webPhar(' . $this->arg($this->alias); if ($this->index) { $stub .= ', ' . $this->arg($prefix . $this->index, '"'); if ($this->notFound) { $stub .= ', ' . $this->arg($prefix . $this->notFound, '"'); if ($this->mimetypes) { $stub .= ', ' . var_export( $this->mimetypes, true ); if ($this->rewrite) { $stub .= ', ' . $this->arg($this->rewrite); } } } } $stub .= ');'; } else { $stub .= 'Phar::mapPhar(' . $this->arg($this->alias) . ');'; } return $stub; } /** * Returns the banner after it has been processed. * * @return string The processed banner. */ private function getBanner() { $banner = "/**\n * "; $banner .= str_replace( " \n", "\n", str_replace("\n", "\n * ", $this->banner) ); $banner .= "\n */"; return $banner; } /** * Returns the self extracting sections of the stub. * * @return array The stub sections. */ private function getExtractSections() { return array( '$extract = new Extract(__FILE__, Extract::findStubLength(__FILE__));', '$dir = $extract->go();', 'set_include_path($dir . PATH_SEPARATOR . get_include_path());', ); } /** * Returns the sections of the stub that use the Phar class. * * @return array The stub sections. */ private function getPharSections() { $stub = array( 'if (class_exists(\'Phar\')) {', $this->getAlias(), ); if ($this->intercept) { $stub[] = "Phar::interceptFileFuncs();"; } if ($this->mung) { $stub[] = 'Phar::mungServer(' . var_export($this->mung, true) . ");"; } if ($this->index && !$this->web && !$this->extractForce) { $stub[] = "require 'phar://' . __FILE__ . '/{$this->index}';"; } $stub[] = '}'; return $stub; } }