From: Michael Wallner Date: Mon, 7 Dec 2015 07:09:59 +0000 (+0100) Subject: prepare for v1.0 X-Git-Tag: v1.0.0RC1~2 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-pq;a=commitdiff_plain;h=e125f60f2ca9863a2ad5eb2d5e615fab421c31e4 prepare for v1.0 --- diff --git a/EXPERIMENTAL b/EXPERIMENTAL deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md index c00b328..a62b85d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # pecl/pq -[![Build Status](https://travis-ci.org/m6w6/ext-pq.svg?branch=master)](https://travis-ci.org/m6w6/ext-pq) +[![Build Status](https://travis-ci.org/m6w6/ext-pq.svg?branch=v1.0.x)](https://travis-ci.org/m6w6/ext-pq) ## About: diff --git a/package.xml b/package.xml index 4a97e8e..46fcdb9 100644 --- a/package.xml +++ b/package.xml @@ -37,27 +37,18 @@ http://pear.php.net/dtd/package-2.0.xsd"> daverandom@php.net yes - 2015-09-05 + 2015-12-04 - 0.6.0 - 0.6.0 + 1.0.0RC1 + 1.0.0 beta - beta + stable BSD, revised diff --git a/php_pq.h b/php_pq.h index ef7d2dd..afcb165 100644 --- a/php_pq.h +++ b/php_pq.h @@ -14,7 +14,7 @@ #ifndef PHP_PQ_H #define PHP_PQ_H -#define PHP_PQ_VERSION "0.6.0" +#define PHP_PQ_VERSION "1.0.0RC1" #ifdef PHP_WIN32 # define PHP_PQ_API __declspec(dllexport) diff --git a/raphf-1.1.0.ext.phar b/raphf-1.1.0.ext.phar deleted file mode 100755 index 7152acb..0000000 --- a/raphf-1.1.0.ext.phar +++ /dev/null @@ -1,6240 +0,0 @@ -#!/usr/bin/env php -getUser(); - if (!is_dir($temp) && !mkdir($temp, 0700, true)) { - throw new Exception; - } - $this->name = $temp ."/". uniqid($prefix) . $suffix; - } - - private function getUser() { - if (extension_loaded("posix") && function_exists("posix_getpwuid")) { - return posix_getpwuid(posix_getuid())["name"]; - } - return trim(`whoami 2>/dev/null`) - ?: trim(`id -nu 2>/dev/null`) - ?: getenv("USER") - ?: get_current_user(); - } - - /** - * @return string - */ - public function __toString() { - return (string) $this->name; - } -} - - - -namespace pharext; - -/** - * Create a new temporary file - */ -class Tempfile extends \SplFileInfo -{ - /** - * @var resource - */ - private $handle; - - /** - * @param string $prefix uniqid() prefix - * @param string $suffix e.g. file extension - * @throws \pharext\Exception - */ - public function __construct($prefix, $suffix = ".tmp") { - $tries = 0; - $omask = umask(077); - do { - $path = new Tempname($prefix, $suffix); - $this->handle = fopen($path, "x"); - } while (!is_resource($this->handle) && $tries++ < 10); - umask($omask); - - if (!is_resource($this->handle)) { - throw new Exception("Could not create temporary file"); - } - - parent::__construct($path); - } - - /** - * Unlink the file - */ - public function __destruct() { - if (is_file($this->getPathname())) { - @unlink($this->getPathname()); - } - } - - /** - * Close the stream - */ - public function closeStream() { - fclose($this->handle); - } - - /** - * Retrieve the stream resource - * @return resource - */ - public function getStream() { - return $this->handle; - } -} - - - -namespace pharext; - -/** - * Create a temporary directory - */ -class Tempdir extends \SplFileInfo -{ - /** - * @param string $prefix prefix to uniqid() - * @throws \pharext\Exception - */ - public function __construct($prefix) { - $temp = new Tempname($prefix); - if (!is_dir($temp) && !mkdir($temp, 0700, true)) { - throw new Exception("Could not create tempdir: ".error_get_last()["message"]); - } - parent::__construct($temp); - } -} - - - -namespace pharext; - -use ArrayAccess; -use IteratorAggregate; -use RecursiveDirectoryIterator; -use SplFileInfo; - -use pharext\Exception; - -class Archive implements ArrayAccess, IteratorAggregate -{ - const HALT_COMPILER = "\137\137\150\141\154\164\137\143\157\155\160\151\154\145\162\50\51\73"; - const SIGNED = 0x10000; - const SIG_MD5 = 0x0001; - const SIG_SHA1 = 0x0002; - const SIG_SHA256 = 0x0003; - const SIG_SHA512 = 0x0004; - const SIG_OPENSSL= 0x0010; - - private static $siglen = [ - self::SIG_MD5 => 16, - self::SIG_SHA1 => 20, - self::SIG_SHA256 => 32, - self::SIG_SHA512 => 64, - self::SIG_OPENSSL=> 0 - ]; - - private static $sigalg = [ - self::SIG_MD5 => "md5", - self::SIG_SHA1 => "sha1", - self::SIG_SHA256 => "sha256", - self::SIG_SHA512 => "sha512", - self::SIG_OPENSSL=> "openssl" - ]; - - private static $sigtyp = [ - self::SIG_MD5 => "MD5", - self::SIG_SHA1 => "SHA-1", - self::SIG_SHA256 => "SHA-256", - self::SIG_SHA512 => "SHA-512", - self::SIG_OPENSSL=> "OpenSSL", - ]; - - const PERM_FILE_MASK = 0x01ff; - const COMP_FILE_MASK = 0xf000; - const COMP_GZ_FILE = 0x1000; - const COMP_BZ2_FILE = 0x2000; - - const COMP_PHAR_MASK= 0xf000; - const COMP_PHAR_GZ = 0x1000; - const COMP_PHAR_BZ2 = 0x2000; - - private $file; - private $fd; - private $stub; - private $manifest; - private $signature; - private $extracted; - - function __construct($file = null) { - if (strlen($file)) { - $this->open($file); - } - } - - function open($file) { - if (!$this->fd = @fopen($file, "r")) { - throw new Exception; - } - $this->file = $file; - $this->stub = $this->readStub(); - $this->manifest = $this->readManifest(); - $this->signature = $this->readSignature(); - } - - function getIterator() { - return new RecursiveDirectoryIterator($this->extract()); - } - - function extract() { - return $this->extracted ?: $this->extractTo(new Tempdir("archive")); - } - - function extractTo($dir) { - if ((string) $this->extracted == (string) $dir) { - return $this->extracted; - } - foreach ($this->manifest["entries"] as $file => $entry) { - fseek($this->fd, $this->manifest["offset"]+$entry["offset"]); - $path = "$dir/$file"; - $copy = stream_copy_to_stream($this->fd, $this->outFd($path, $entry["flags"]), $entry["csize"]); - if ($entry["osize"] != $copy) { - throw new Exception("Copied '$copy' of '$file', expected '{$entry["osize"]}' from '{$entry["csize"]}"); - } - - $crc = hexdec(hash_file("crc32b", $path)); - if ($crc !== $entry["crc32"]) { - throw new Exception("CRC mismatch of '$file': '$crc' != '{$entry["crc32"]}"); - } - - chmod($path, $entry["flags"] & self::PERM_FILE_MASK); - touch($path, $entry["stamp"]); - } - return $this->extracted = $dir; - } - - function offsetExists($o) { - return isset($this->entries[$o]); - } - - function offsetGet($o) { - $this->extract(); - return new SplFileInfo($this->extracted."/$o"); - } - - function offsetSet($o, $v) { - throw new Exception("Archive is read-only"); - } - - function offsetUnset($o) { - throw new Exception("Archive is read-only"); - } - - function getSignature() { - /* compatible with Phar::getSignature() */ - return [ - "hash_type" => self::$sigtyp[$this->signature["flags"]], - "hash" => strtoupper(bin2hex($this->signature["hash"])), - ]; - } - - function getPath() { - /* compatible with Phar::getPath() */ - return new SplFileInfo($this->file); - } - - function getMetadata($key = null) { - if (isset($key)) { - return $this->manifest["meta"][$key]; - } - return $this->manifest["meta"]; - } - - private function outFd($path, $flags) { - $dirn = dirname($path); - if (!is_dir($dirn) && !@mkdir($dirn, 0777, true)) { - throw new Exception; - } - if (!$fd = @fopen($path, "w")) { - throw new Exception; - } - switch ($flags & self::COMP_FILE_MASK) { - case self::COMP_GZ_FILE: - if (!@stream_filter_append($fd, "zlib.inflate")) { - throw new Exception; - } - break; - case self::COMP_BZ2_FILE: - if (!@stream_filter_append($fd, "bz2.decompress")) { - throw new Exception; - } - break; - } - - } - private function readVerified($fd, $len) { - if ($len != strlen($data = fread($fd, $len))) { - throw new Exception("Unexpected EOF"); - } - return $data; - } - - private function readFormat($format, $fd, $len) { - if (false === ($data = @unpack($format, $this->readVerified($fd, $len)))) { - throw new Exception; - } - return $data; - } - - private function readSingleFormat($format, $fd, $len) { - return current($this->readFormat($format, $fd, $len)); - } - - private function readStringBinary($fd) { - if (($length = $this->readSingleFormat("V", $fd, 4))) { - return $this->readVerified($this->fd, $length); - } - return null; - } - - private function readSerializedBinary($fd) { - if (($length = $this->readSingleFormat("V", $fd, 4))) { - if (false === ($data = unserialize($this->readVerified($fd, $length)))) { - throw new Exception; - } - return $data; - } - return null; - } - - private function readStub() { - $stub = ""; - while (!feof($this->fd)) { - $line = fgets($this->fd); - $stub .= $line; - if (false !== stripos($line, self::HALT_COMPILER)) { - /* check for '?>' on a separate line */ - if ('?>' === $this->readVerified($this->fd, 2)) { - $stub .= '?>' . fgets($this->fd); - } else { - fseek($this->fd, -2, SEEK_CUR); - } - break; - } - } - return $stub; - } - - private function readManifest() { - $current = ftell($this->fd); - $header = $this->readFormat("Vlen/Vnum/napi/Vflags", $this->fd, 14); - $alias = $this->readStringBinary($this->fd); - $meta = $this->readSerializedBinary($this->fd); - $entries = []; - for ($i = 0; $i < $header["num"]; ++$i) { - $this->readEntry($entries); - } - $offset = ftell($this->fd); - if (($length = $offset - $current - 4) != $header["len"]) { - throw new Exception("Manifest length read was '$length', expected '{$header["len"]}'"); - } - return $header + compact("alias", "meta", "entries", "offset"); - } - - private function readEntry(array &$entries) { - if (!count($entries)) { - $offset = 0; - } else { - $last = end($entries); - $offset = $last["offset"] + $last["csize"]; - } - $file = $this->readStringBinary($this->fd); - if (!strlen($file)) { - throw new Exception("Empty file name encountered at offset '$offset'"); - } - $header = $this->readFormat("Vosize/Vstamp/Vcsize/Vcrc32/Vflags", $this->fd, 20); - $meta = $this->readSerializedBinary($this->fd); - $entries[$file] = $header + compact("meta", "offset"); - } - - private function readSignature() { - fseek($this->fd, -8, SEEK_END); - $sig = $this->readFormat("Vflags/Z4magic", $this->fd, 8); - $end = ftell($this->fd); - - if ($sig["magic"] !== "GBMB") { - throw new Exception("Invalid signature magic value '{$sig["magic"]}"); - } - - switch ($sig["flags"]) { - case self::SIG_OPENSSL: - fseek($this->fd, -12, SEEK_END); - if (($hash = $this->readSingleFormat("V", $this->fd, 4))) { - $offset = 4 + $hash; - fseek($this->fd, -$offset, SEEK_CUR); - $hash = $this->readVerified($this->fd, $hash); - fseek($this->fd, 0, SEEK_SET); - $valid = openssl_verify($this->readVerified($this->fd, $end - $offset - 8), - $hash, @file_get_contents($this->file.".pubkey")) === 1; - } - break; - - case self::SIG_MD5: - case self::SIG_SHA1: - case self::SIG_SHA256: - case self::SIG_SHA512: - $offset = 8 + self::$siglen[$sig["flags"]]; - fseek($this->fd, -$offset, SEEK_END); - $hash = $this->readVerified($this->fd, self::$siglen[$sig["flags"]]); - $algo = hash_init(self::$sigalg[$sig["flags"]]); - fseek($this->fd, 0, SEEK_SET); - hash_update_stream($algo, $this->fd, $end - $offset); - $valid = hash_final($algo, true) === $hash; - break; - - default: - throw new Exception("Invalid signature type '{$sig["flags"]}"); - } - - return $sig + compact("hash", "valid"); - } -} - - -namespace pharext; - -if (extension_loaded("Phar")) { - \Phar::interceptFileFuncs(); - \Phar::mapPhar(); - $phardir = "phar://".__FILE__; -} else { - $archive = new Archive(__FILE__); - $phardir = $archive->extract(); -} - -set_include_path("$phardir:". get_include_path()); - -$installer = new Installer(); -$installer->run($argc, $argv); - -__HALT_COMPILER(); ?> -¢7(a:7:{s:7:"version";s:5:"4.1.1";s:6:"header";s:49:"pharext v4.1.1 (c) Michael Wallner ";s:4:"date";s:10:"2015-09-05";s:4:"name";s:5:"raphf";s:7:"release";s:5:"1.1.0";s:7:"license";s:1345:"Copyright (c) 2013, Michael Wallner . -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -";s:4:"type";s:9:"extension";}pharext/Archive.phpËéêU4-ÔI¶pharext/Cli/Args/Help.phpÉ ËéêUÉ gX'¶pharext/Cli/Args.phpËéêU?nö¶pharext/Cli/Command.phpk ËéêUk d„aê¶pharext/Command.phpËéêUÔm`Ͷpharext/Exception.phpcËéêUcU†Ï{¶pharext/ExecCmd.phpËéêU¹l”ʶpharext/Installer.php&ËéêU&ød&À¶pharext/License.php“ËéêU“îòE¶pharext/Metadata.php•ËéêU•¿Úž¶pharext/Openssl/PrivateKey.phpÁËéêUÁ&æP¶pharext/Packager.phpÌ!ËéêUÌ!0<¶pharext/SourceDir/Basic.phpzËéêUz÷+Ôâ¶pharext/SourceDir/Git.phpZËéêUZÉÎ\¶pharext/SourceDir/Pecl.phpøËéêUøãùжpharext/SourceDir.php½ËéêU½3·#¶pharext/Task/Activate.phpÜ ËéêUÜ I“¶pharext/Task/Askpass.phpUËéêUU‡*¶ pharext/Task/BundleGenerator.php}ËéêU} ï`Y¶pharext/Task/Cleanup.phpËéêUÉI€B¶pharext/Task/Configure.phpTËéêUT}Ëì¶pharext/Task/Extract.phppËéêUp[¨Û̶pharext/Task/GitClone.phpmËéêUmóyµ@¶pharext/Task/Make.phpªËéêUªœç6 ¶pharext/Task/PaxFixup.php¬ËéêU¬y⯶pharext/Task/PeclFixup.phpœËéêUœeùtš¶pharext/Task/PharBuild.phpâËéêUâζ0ɶpharext/Task/PharCompress.phpcËéêUc½³Ï¶pharext/Task/PharRename.phpäËéêUäŠ[Þ˶pharext/Task/PharSign.php¨ËéêU¨Ûº¦i¶pharext/Task/PharStub.phpæËéêUæY|­›¶pharext/Task/Phpize.phpËéêUù 2Ѷpharext/Task/StreamFetch.phpËéêUˆîs\¶pharext/Task.phpwËéêUw ÄIǶpharext/Tempdir.phpµËéêUµë–,¶pharext/Tempfile.phpËéêU®ô¶pharext/Tempname.phptËéêUtžn<¶pharext/Updater.phpËéêUžÏv¶pharext_installer.phpÝËéêUÝŒÞq¶pharext_packager.phpbËéêUbîVÓ϶pharext_updater.phphËéêUh Êúj¶pharext_package.php2ËéêU2vSTÒ¶ package.xmlÄËéêUÄ?z,e¶CREDITSËéêUCµ]²¶LICENSEAËéêUA¾¬Jþ¶DoxyfileW,ËéêUW,Zΰ¶ config.m4$ËéêU$Åê@›¶ -config.w32ÐËéêUÐýÍŽ¶ php_raphf.hËéêUZ1€ž¶php_raphf_api.hz5ËéêUz5{¯>¶ php_raphf.cHËéêUH™Çꀶtests/http001.phptËéêU *®¶tests/http002.phptLËéêUL€ÔïS¶tests/http003.phpt^ËéêU^ˆp¶tests/http004.phpt[ËéêU[Y諶 16, - self::SIG_SHA1 => 20, - self::SIG_SHA256 => 32, - self::SIG_SHA512 => 64, - self::SIG_OPENSSL=> 0 - ]; - - private static $sigalg = [ - self::SIG_MD5 => "md5", - self::SIG_SHA1 => "sha1", - self::SIG_SHA256 => "sha256", - self::SIG_SHA512 => "sha512", - self::SIG_OPENSSL=> "openssl" - ]; - - private static $sigtyp = [ - self::SIG_MD5 => "MD5", - self::SIG_SHA1 => "SHA-1", - self::SIG_SHA256 => "SHA-256", - self::SIG_SHA512 => "SHA-512", - self::SIG_OPENSSL=> "OpenSSL", - ]; - - const PERM_FILE_MASK = 0x01ff; - const COMP_FILE_MASK = 0xf000; - const COMP_GZ_FILE = 0x1000; - const COMP_BZ2_FILE = 0x2000; - - const COMP_PHAR_MASK= 0xf000; - const COMP_PHAR_GZ = 0x1000; - const COMP_PHAR_BZ2 = 0x2000; - - private $file; - private $fd; - private $stub; - private $manifest; - private $signature; - private $extracted; - - function __construct($file = null) { - if (strlen($file)) { - $this->open($file); - } - } - - function open($file) { - if (!$this->fd = @fopen($file, "r")) { - throw new Exception; - } - $this->file = $file; - $this->stub = $this->readStub(); - $this->manifest = $this->readManifest(); - $this->signature = $this->readSignature(); - } - - function getIterator() { - return new RecursiveDirectoryIterator($this->extract()); - } - - function extract() { - return $this->extracted ?: $this->extractTo(new Tempdir("archive")); - } - - function extractTo($dir) { - if ((string) $this->extracted == (string) $dir) { - return $this->extracted; - } - foreach ($this->manifest["entries"] as $file => $entry) { - fseek($this->fd, $this->manifest["offset"]+$entry["offset"]); - $path = "$dir/$file"; - $copy = stream_copy_to_stream($this->fd, $this->outFd($path, $entry["flags"]), $entry["csize"]); - if ($entry["osize"] != $copy) { - throw new Exception("Copied '$copy' of '$file', expected '{$entry["osize"]}' from '{$entry["csize"]}"); - } - - $crc = hexdec(hash_file("crc32b", $path)); - if ($crc !== $entry["crc32"]) { - throw new Exception("CRC mismatch of '$file': '$crc' != '{$entry["crc32"]}"); - } - - chmod($path, $entry["flags"] & self::PERM_FILE_MASK); - touch($path, $entry["stamp"]); - } - return $this->extracted = $dir; - } - - function offsetExists($o) { - return isset($this->entries[$o]); - } - - function offsetGet($o) { - $this->extract(); - return new SplFileInfo($this->extracted."/$o"); - } - - function offsetSet($o, $v) { - throw new Exception("Archive is read-only"); - } - - function offsetUnset($o) { - throw new Exception("Archive is read-only"); - } - - function getSignature() { - /* compatible with Phar::getSignature() */ - return [ - "hash_type" => self::$sigtyp[$this->signature["flags"]], - "hash" => strtoupper(bin2hex($this->signature["hash"])), - ]; - } - - function getPath() { - /* compatible with Phar::getPath() */ - return new SplFileInfo($this->file); - } - - function getMetadata($key = null) { - if (isset($key)) { - return $this->manifest["meta"][$key]; - } - return $this->manifest["meta"]; - } - - private function outFd($path, $flags) { - $dirn = dirname($path); - if (!is_dir($dirn) && !@mkdir($dirn, 0777, true)) { - throw new Exception; - } - if (!$fd = @fopen($path, "w")) { - throw new Exception; - } - switch ($flags & self::COMP_FILE_MASK) { - case self::COMP_GZ_FILE: - if (!@stream_filter_append($fd, "zlib.inflate")) { - throw new Exception; - } - break; - case self::COMP_BZ2_FILE: - if (!@stream_filter_append($fd, "bz2.decompress")) { - throw new Exception; - } - break; - } - - } - private function readVerified($fd, $len) { - if ($len != strlen($data = fread($fd, $len))) { - throw new Exception("Unexpected EOF"); - } - return $data; - } - - private function readFormat($format, $fd, $len) { - if (false === ($data = @unpack($format, $this->readVerified($fd, $len)))) { - throw new Exception; - } - return $data; - } - - private function readSingleFormat($format, $fd, $len) { - return current($this->readFormat($format, $fd, $len)); - } - - private function readStringBinary($fd) { - if (($length = $this->readSingleFormat("V", $fd, 4))) { - return $this->readVerified($this->fd, $length); - } - return null; - } - - private function readSerializedBinary($fd) { - if (($length = $this->readSingleFormat("V", $fd, 4))) { - if (false === ($data = unserialize($this->readVerified($fd, $length)))) { - throw new Exception; - } - return $data; - } - return null; - } - - private function readStub() { - $stub = ""; - while (!feof($this->fd)) { - $line = fgets($this->fd); - $stub .= $line; - if (false !== stripos($line, self::HALT_COMPILER)) { - /* check for '?>' on a separate line */ - if ('?>' === $this->readVerified($this->fd, 2)) { - $stub .= '?>' . fgets($this->fd); - } else { - fseek($this->fd, -2, SEEK_CUR); - } - break; - } - } - return $stub; - } - - private function readManifest() { - $current = ftell($this->fd); - $header = $this->readFormat("Vlen/Vnum/napi/Vflags", $this->fd, 14); - $alias = $this->readStringBinary($this->fd); - $meta = $this->readSerializedBinary($this->fd); - $entries = []; - for ($i = 0; $i < $header["num"]; ++$i) { - $this->readEntry($entries); - } - $offset = ftell($this->fd); - if (($length = $offset - $current - 4) != $header["len"]) { - throw new Exception("Manifest length read was '$length', expected '{$header["len"]}'"); - } - return $header + compact("alias", "meta", "entries", "offset"); - } - - private function readEntry(array &$entries) { - if (!count($entries)) { - $offset = 0; - } else { - $last = end($entries); - $offset = $last["offset"] + $last["csize"]; - } - $file = $this->readStringBinary($this->fd); - if (!strlen($file)) { - throw new Exception("Empty file name encountered at offset '$offset'"); - } - $header = $this->readFormat("Vosize/Vstamp/Vcsize/Vcrc32/Vflags", $this->fd, 20); - $meta = $this->readSerializedBinary($this->fd); - $entries[$file] = $header + compact("meta", "offset"); - } - - private function readSignature() { - fseek($this->fd, -8, SEEK_END); - $sig = $this->readFormat("Vflags/Z4magic", $this->fd, 8); - $end = ftell($this->fd); - - if ($sig["magic"] !== "GBMB") { - throw new Exception("Invalid signature magic value '{$sig["magic"]}"); - } - - switch ($sig["flags"]) { - case self::SIG_OPENSSL: - fseek($this->fd, -12, SEEK_END); - if (($hash = $this->readSingleFormat("V", $this->fd, 4))) { - $offset = 4 + $hash; - fseek($this->fd, -$offset, SEEK_CUR); - $hash = $this->readVerified($this->fd, $hash); - fseek($this->fd, 0, SEEK_SET); - $valid = openssl_verify($this->readVerified($this->fd, $end - $offset - 8), - $hash, @file_get_contents($this->file.".pubkey")) === 1; - } - break; - - case self::SIG_MD5: - case self::SIG_SHA1: - case self::SIG_SHA256: - case self::SIG_SHA512: - $offset = 8 + self::$siglen[$sig["flags"]]; - fseek($this->fd, -$offset, SEEK_END); - $hash = $this->readVerified($this->fd, self::$siglen[$sig["flags"]]); - $algo = hash_init(self::$sigalg[$sig["flags"]]); - fseek($this->fd, 0, SEEK_SET); - hash_update_stream($algo, $this->fd, $end - $offset); - $valid = hash_final($algo, true) === $hash; - break; - - default: - throw new Exception("Invalid signature type '{$sig["flags"]}"); - } - - return $sig + compact("hash", "valid"); - } -} -prog = $prog; - $this->args = $args; - } - - function __toString() { - $usage = "Usage:\n\n \$ "; - $usage .= $this->prog; - - list($flags, $required, $optional, $positional) = $this->listSpec(); - if ($flags) { - $usage .= $this->dumpFlags($flags); - } - if ($required) { - $usage .= $this->dumpRequired($required); - } - if ($optional) { - $usage .= $this->dumpOptional($optional); - } - if ($positional) { - $usage .= $this->dumpPositional($positional); - } - - $help = $this->dumpHelp($positional); - - return $usage . "\n\n" . $help . "\n"; - } - - function listSpec() { - $flags = []; - $required = []; - $optional = []; - $positional = []; - foreach ($this->args->getSpec() as $spec) { - if (is_numeric($spec[0])) { - $positional[] = $spec; - } elseif ($spec[3] & Args::REQUIRED) { - $required[] = $spec; - } elseif ($spec[3] & (Args::OPTARG|Args::REQARG)) { - $optional[] = $spec; - } else { - $flags[] = $spec; - } - } - - return [$flags, $required, $optional, $positional] - + compact("flags", "required", "optional", "positional"); - } - - function dumpFlags(array $flags) { - return sprintf(" [-%s]", implode("", array_column($flags, 0))); - } - - function dumpRequired(array $required) { - $dump = ""; - foreach ($required as $req) { - $dump .= sprintf(" -%s <%s>", $req[0], $req[1]); - } - return $dump; - } - - function dumpOptional(array $optional) { - $req = array_filter($optional, function($a) { - return $a[3] & Args::REQARG; - }); - $opt = array_filter($optional, function($a) { - return $a[3] & Args::OPTARG; - }); - - $dump = ""; - if ($req) { - $dump .= sprintf(" [-%s ]", implode("|-", array_column($req, 0))); - } - if ($opt) { - $dump .= sprintf(" [-%s []]", implode("|-", array_column($opt, 0))); - } - return $dump; - } - - function dumpPositional(array $positional) { - $dump = " [--]"; - foreach ($positional as $pos) { - if ($pos[3] & Args::REQUIRED) { - $dump .= sprintf(" <%s>", $pos[1]); - } else { - $dump .= sprintf(" [<%s>]", $pos[1]); - } - if ($pos[3] & Args::MULTI) { - $dump .= sprintf(" [<%s>]...", $pos[1]); - } - } - return $dump; - } - - function calcMaxLen() { - $spc = $this->args->getSpec(); - $max = max(array_map("strlen", array_column($spc, 1))); - $max += $max % 8 + 2; - return $max; - } - - function dumpHelp() { - $max = $this->calcMaxLen(); - $dump = ""; - foreach ($this->args->getSpec() as $spec) { - $dump .= " "; - if (is_numeric($spec[0])) { - $dump .= sprintf("-- %s ", $spec[1]); - } elseif (isset($spec[0])) { - $dump .= sprintf("-%s|", $spec[0]); - } - if (!is_numeric($spec[0])) { - $dump .= sprintf("--%s ", $spec[1]); - } - if ($spec[3] & Args::REQARG) { - $dump .= " "; - } elseif ($spec[3] & Args::OPTARG) { - $dump .= "[]"; - } else { - $dump .= " "; - } - - $dump .= str_repeat(" ", $max-strlen($spec[1])+3*!isset($spec[0])); - $dump .= $spec[2]; - - if ($spec[3] & Args::REQUIRED) { - $dump .= " (REQUIRED)"; - } - if ($spec[3] & Args::MULTI) { - $dump .= " (MULTIPLE)"; - } - if (isset($spec[4])) { - $dump .= sprintf(" [%s]", $spec[4]); - } - $dump .= "\n"; - } - return $dump; - } -} -compile($spec); - } - - } - - /** - * Compile the original spec - * @param array|Traversable $spec - * @return pharext\Cli\Args self - */ - public function compile($spec) { - foreach ($spec as $arg) { - if (isset($arg[0]) && is_numeric($arg[0])) { - $arg[3] &= ~0xf00; - $this->spec["--".$arg[0]] = $arg; - } elseif (isset($arg[0])) { - $this->spec["-".$arg[0]] = $arg; - $this->spec["--".$arg[1]] = $arg; - } else { - $this->spec["--".$arg[1]] = $arg; - } - $this->orig[] = $arg; - } - return $this; - } - - /** - * Get original spec - * @return array - */ - public function getSpec() { - return $this->orig; - } - - /** - * Get compiled spec - * @return array - */ - public function getCompiledSpec() { - return $this->spec; - } - - /** - * Parse command line arguments according to the compiled spec. - * - * The Generator yields any parsing errors. - * Parsing will stop when all arguments are processed or the first option - * flagged Cli\Args::HALT was encountered. - * - * @param int $argc - * @param array $argv - * @return Generator - */ - public function parse($argc, array $argv) { - for ($f = false, $p = 0, $i = 0; $i < $argc; ++$i) { - $o = $argv[$i]; - - if ($o{0} === "-" && strlen($o) > 2 && $o{1} !== "-") { - // multiple short opts, e.g. -vps - $argc += strlen($o) - 2; - array_splice($argv, $i, 1, array_map(function($s) { - return "-$s"; - }, str_split(substr($o, 1)))); - $o = $argv[$i]; - } elseif ($o{0} === "-" && strlen($o) > 2 && $o{1} === "-" && 0 < ($eq = strpos($o, "="))) { - // long opt with argument, e.g. --foo=bar - $argc++; - array_splice($argv, $i, 1, [ - substr($o, 0, $eq++), - substr($o, $eq) - ]); - $o = $argv[$i]; - } elseif ($o === "--") { - // only positional args following - $f = true; - continue; - } - - if ($f || !isset($this->spec[$o])) { - if ($o{0} !== "-" && isset($this->spec["--$p"])) { - $this[$p] = $o; - if (!$this->optIsMulti($p)) { - ++$p; - } - } else { - yield sprintf("Unknown option %s", $o); - } - } elseif (!$this->optAcceptsArg($o)) { - $this[$o] = true; - } elseif ($i+1 < $argc && !isset($this->spec[$argv[$i+1]])) { - $this[$o] = $argv[++$i]; - } elseif ($this->optRequiresArg($o)) { - yield sprintf("Option --%s requires an argument", $this->optLongName($o)); - } else { - // OPTARG - $this[$o] = $this->optDefaultArg($o); - } - - if ($this->optHalts($o)) { - return; - } - } - } - - /** - * Validate that all required options were given. - * - * The Generator yields any validation errors. - * - * @return Generator - */ - public function validate() { - $required = array_filter($this->orig, function($spec) { - return $spec[3] & self::REQUIRED; - }); - foreach ($required as $req) { - if ($req[3] & self::MULTI) { - if (is_array($this[$req[0]])) { - continue; - } - } elseif (strlen($this[$req[0]])) { - continue; - } - if (is_numeric($req[0])) { - yield sprintf("Argument <%s> is required", $req[1]); - } else { - yield sprintf("Option --%s is required", $req[1]); - } - } - } - - - public function toArray() { - $args = []; - foreach ($this->spec as $spec) { - $opt = $this->opt($spec[1]); - $args[$opt] = $this[$opt]; - } - return $args; - } - - /** - * Retreive the default argument of an option - * @param string $o - * @return mixed - */ - private function optDefaultArg($o) { - $o = $this->opt($o); - if (isset($this->spec[$o][4])) { - return $this->spec[$o][4]; - } - return null; - } - - /** - * Retrieve the help message of an option - * @param string $o - * @return string - */ - private function optHelp($o) { - $o = $this->opt($o); - if (isset($this->spec[$o][2])) { - return $this->spec[$o][2]; - } - return ""; - } - - /** - * Retrieve option's flags - * @param string $o - * @return int - */ - private function optFlags($o) { - $o = $this->opt($o); - if (isset($this->spec[$o])) { - return $this->spec[$o][3]; - } - return null; - } - - /** - * Check whether an option is flagged for halting argument processing - * @param string $o - * @return boolean - */ - private function optHalts($o) { - return $this->optFlags($o) & self::HALT; - } - - /** - * Check whether an option needs an argument - * @param string $o - * @return boolean - */ - private function optRequiresArg($o) { - return $this->optFlags($o) & self::REQARG; - } - - /** - * Check wether an option accepts any argument - * @param string $o - * @return boolean - */ - private function optAcceptsArg($o) { - return $this->optFlags($o) & 0xf00; - } - - /** - * Check whether an option can be used more than once - * @param string $o - * @return boolean - */ - private function optIsMulti($o) { - return $this->optFlags($o) & self::MULTI; - } - - /** - * Retreive the long name of an option - * @param string $o - * @return string - */ - private function optLongName($o) { - $o = $this->opt($o); - return is_numeric($this->spec[$o][0]) ? $this->spec[$o][0] : $this->spec[$o][1]; - } - - /** - * Retreive the short name of an option - * @param string $o - * @return string - */ - private function optShortName($o) { - $o = $this->opt($o); - return is_numeric($this->spec[$o][0]) ? null : $this->spec[$o][0]; - } - - /** - * Retreive the canonical name (--long-name) of an option - * @param string $o - * @return string - */ - private function opt($o) { - if (is_numeric($o)) { - return "--$o"; - } - if ($o{0} !== '-') { - if (strlen($o) > 1) { - $o = "-$o"; - } - $o = "-$o"; - } - return $o; - } - - /**@+ - * Implements ArrayAccess and virtual properties - */ - function offsetExists($o) { - $o = $this->opt($o); - return isset($this->args[$o]); - } - function __isset($o) { - return $this->offsetExists($o); - } - function offsetGet($o) { - $o = $this->opt($o); - if (isset($this->args[$o])) { - return $this->args[$o]; - } - return $this->optDefaultArg($o); - } - function __get($o) { - return $this->offsetGet($o); - } - function offsetSet($o, $v) { - $osn = $this->optShortName($o); - $oln = $this->optLongName($o); - if ($this->optIsMulti($o)) { - if (isset($osn)) { - $this->args["-$osn"][] = $v; - } - $this->args["--$oln"][] = $v; - } else { - if (isset($osn)) { - $this->args["-$osn"] = $v; - } - $this->args["--$oln"] = $v; - } - } - function __set($o, $v) { - $this->offsetSet($o, $v); - } - function offsetUnset($o) { - unset($this->args["-".$this->optShortName($o)]); - unset($this->args["--".$this->optLongName($o)]); - } - function __unset($o) { - $this->offsetUnset($o); - } - /**@-*/ -} -args; - } - - /** - * Retrieve metadata of the currently running phar - * @param string $key - * @return mixed - */ - public function metadata($key = null) { - if (extension_loaded("Phar")) { - $running = new Phar(Phar::running(false)); - } else { - $running = new Archive(PHAREXT_PHAR); - } - - if ($key === "signature") { - $sig = $running->getSignature(); - return sprintf("%s signature of %s\n%s", - $sig["hash_type"], - $this->metadata("name"), - chunk_split($sig["hash"], 64, "\n")); - } - - $metadata = $running->getMetadata(); - if (isset($key)) { - return $metadata[$key]; - } - return $metadata; - } - - /** - * Output pharext vX.Y.Z header - */ - public function header() { - if (!headers_sent()) { - /* only display header, if we didn't generate any output yet */ - printf("%s\n\n", $this->metadata("header")); - } - } - - /** - * @inheritdoc - * @see \pharext\Command::debug() - */ - public function debug($fmt) { - if ($this->args->verbose) { - vprintf($fmt, array_slice(func_get_args(), 1)); - } - } - - /** - * @inheritdoc - * @see \pharext\Command::info() - */ - public function info($fmt) { - if (!$this->args->quiet) { - vprintf($fmt, array_slice(func_get_args(), 1)); - } - } - - /** - * @inheritdoc - * @see \pharext\Command::warn() - */ - public function warn($fmt) { - if (!$this->args->quiet) { - if (!isset($fmt)) { - $fmt = "%s\n"; - $arg = error_get_last()["message"]; - } else { - $arg = array_slice(func_get_args(), 1); - } - vfprintf(STDERR, "Warning: $fmt", $arg); - } - } - - /** - * @inheritdoc - * @see \pharext\Command::error() - */ - public function error($fmt) { - if (!isset($fmt)) { - $fmt = "%s\n"; - $arg = error_get_last()["message"]; - } else { - $arg = array_slice(func_get_args(), 1); - } - vfprintf(STDERR, "ERROR: $fmt", $arg); - } - - /** - * Output command line help message - * @param string $prog - */ - public function help($prog) { - print new Args\Help($prog, $this->args); - } - - /** - * Verbosity - * @return boolean - */ - public function verbosity() { - if ($this->args->verbose) { - return true; - } elseif ($this->args->quiet) { - return false; - } else { - return null; - } - } -} -command = $command; - $this->verbose = $verbose; - } - - /** - * (Re-)set sudo command - * @param string $sudo - */ - public function setSu($sudo = false) { - $this->sudo = $sudo; - } - - /** - * Execute a program with escalated privileges handling interactive password prompt - * @param string $command - * @param bool $verbose - * @return int exit status - */ - private function suExec($command, $verbose = null) { - if (!($proc = proc_open($command, [STDIN,["pipe","w"],["pipe","w"]], $pipes))) { - $this->status = -1; - throw new Exception("Failed to run {$command}"); - } - - $stdout = $pipes[1]; - $passwd = 0; - $checks = 10; - - while (!feof($stdout)) { - $R = [$stdout]; $W = []; $E = []; - if (!stream_select($R, $W, $E, null)) { - continue; - } - $data = fread($stdout, 0x1000); - /* only check a few times */ - if ($passwd < $checks) { - $passwd++; - if (stristr($data, "password")) { - $passwd = $checks + 1; - printf("\n%s", $data); - continue; - } - } elseif ($passwd > $checks) { - /* new line after pw entry */ - printf("\n"); - $passwd = $checks; - } - - if ($verbose === null) { - print $this->progress($data, 0); - } else { - if ($verbose) { - printf("%s", $data); - } - $this->output .= $data; - } - } - if ($verbose === null) { - $this->progress("", PHP_OUTPUT_HANDLER_FINAL); - } - return $this->status = proc_close($proc); - } - - /** - * Output handler that displays some progress while soaking output - * @param string $string - * @param int $flags - * @return string - */ - private function progress($string, $flags) { - static $counter = 0; - static $symbols = ["\\","|","/","-"]; - - $this->output .= $string; - - if (false !== strpos($string, "\n")) { - ++$counter; - } - - return $flags & PHP_OUTPUT_HANDLER_FINAL - ? " \r" - : sprintf(" %s\r", $symbols[$counter % 4]); - } - - /** - * Run the command - * @param array $args - * @return \pharext\ExecCmd self - * @throws \pharext\Exception - */ - public function run(array $args = null) { - $exec = escapeshellcmd($this->command); - if ($args) { - $exec .= " ". implode(" ", array_map("escapeshellarg", (array) $args)); - } - - if ($this->sudo) { - $this->suExec(sprintf($this->sudo." 2>&1", $exec), $this->verbose); - } elseif ($this->verbose) { - ob_start(function($s) { - $this->output .= $s; - return $s; - }, 1); - passthru($exec, $this->status); - ob_end_flush(); - } elseif ($this->verbose !== false /* !quiet */) { - ob_start([$this, "progress"], 1); - passthru($exec . " 2>&1", $this->status); - ob_end_flush(); - } else { - exec($exec ." 2>&1", $output, $this->status); - $this->output = implode("\n", $output); - } - - if ($this->status) { - throw new Exception("Command {$exec} failed ({$this->status})"); - } - - return $this; - } - - /** - * Retrieve exit code of cmd run - * @return int - */ - public function getStatus() { - return $this->status; - } - - /** - * Retrieve output of cmd run - * @return string - */ - public function getOutput() { - return $this->output; - } -} -args = new Cli\Args([ - ["h", "help", "Display help", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - ["v", "verbose", "More output", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["q", "quiet", "Less output", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["p", "prefix", "PHP installation prefix if phpize is not in \$PATH, e.g. /opt/php7", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::REQARG], - ["n", "common-name", "PHP common program name, e.g. php5 or zts-php", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::REQARG, - "php"], - ["c", "configure", "Additional extension configure flags, e.g. -c --with-flag", - Cli\Args::OPTIONAL|Cli\Args::MULTI|Cli\Args::REQARG], - ["s", "sudo", "Installation might need increased privileges", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::OPTARG, - "sudo -S %s"], - ["i", "ini", "Activate in this php.ini instead of loaded default php.ini", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::REQARG], - [null, "signature", "Show package signature", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "license", "Show package license", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "name", "Show package name", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "date", "Show package release date", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "release", "Show package release version", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "version", "Show pharext version", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - ]); - } - - /** - * Perform cleaniup - */ - function __destruct() { - foreach ($this->cleanup as $cleanup) { - $cleanup->run(); - } - } - - private function extract($phar) { - $temp = (new Task\Extract($phar))->run($this->verbosity()); - $this->cleanup[] = new Task\Cleanup($temp); - return $temp; - } - - private function hooks(SplObjectStorage $phars) { - $hook = []; - foreach ($phars as $phar) { - if (isset($phar["pharext_package.php"])) { - $sdir = include $phar["pharext_package.php"]; - if ($sdir instanceof SourceDir) { - $this->args->compile($sdir->getArgs()); - $hook[] = $sdir; - } - } - } - return $hook; - } - - private function load() { - $list = new SplObjectStorage(); - $phar = extension_loaded("Phar") - ? new Phar(Phar::running(false)) - : new Archive(PHAREXT_PHAR); - $temp = $this->extract($phar); - - foreach ($phar as $entry) { - $dep_file = $entry->getBaseName(); - if (fnmatch("*.ext.phar*", $dep_file)) { - $dep_phar = extension_loaded("Phar") - ? new Phar("$temp/$dep_file") - : new Archive("$temp/$dep_file"); - $list[$dep_phar] = $this->extract($dep_phar); - } - } - - /* the actual ext.phar at last */ - $list[$phar] = $temp; - return $list; - } - - /** - * @inheritdoc - * @see \pharext\Command::run() - */ - public function run($argc, array $argv) { - try { - /* load the phar(s) */ - $list = $this->load(); - /* installer hooks */ - $hook = $this->hooks($list); - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EEXTRACT); - } - - /* standard arg stuff */ - $errs = []; - $prog = array_shift($argv); - foreach ($this->args->parse(--$argc, $argv) as $error) { - $errs[] = $error; - } - - if ($this->args["help"]) { - $this->header(); - $this->help($prog); - exit; - } - try { - foreach (["signature", "name", "date", "license", "release", "version"] as $opt) { - if ($this->args[$opt]) { - printf("%s\n", $this->metadata($opt)); - exit; - } - } - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EARGS); - } - - foreach ($this->args->validate() as $error) { - $errs[] = $error; - } - - if ($errs) { - if (!$this->args["quiet"]) { - $this->header(); - } - foreach ($errs as $err) { - $this->error("%s\n", $err); - } - if (!$this->args["quiet"]) { - $this->help($prog); - } - exit(self::EARGS); - } - - try { - /* post process hooks */ - foreach ($hook as $sdir) { - $sdir->setArgs($this->args); - } - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EARGS); - } - - /* install packages */ - try { - foreach ($list as $phar) { - $this->info("Installing %s ...\n", basename($phar->getPath())); - $this->install($list[$phar]); - $this->activate($list[$phar]); - $this->info("Successfully installed %s!\n", basename($phar->getPath())); - } - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EINSTALL); - } - } - - /** - * Phpize + trinity - */ - private function install($temp) { - // phpize - $phpize = new Task\Phpize($temp, $this->args->prefix, $this->args->{"common-name"}); - $phpize->run($this->verbosity()); - - // configure - $configure = new Task\Configure($temp, $this->args->configure, $this->args->prefix, $this->args->{"common-name"}); - $configure->run($this->verbosity()); - - // make - $make = new Task\Make($temp); - $make->run($this->verbosity()); - - // install - $sudo = isset($this->args->sudo) ? $this->args->sudo : null; - $install = new Task\Make($temp, ["install"], $sudo); - $install->run($this->verbosity()); - } - - private function activate($temp) { - if ($this->args->ini) { - $files = [$this->args->ini]; - } else { - $files = array_filter(array_map("trim", explode(",", php_ini_scanned_files()))); - $files[] = php_ini_loaded_file(); - } - - $sudo = isset($this->args->sudo) ? $this->args->sudo : null; - $type = $this->metadata("type") ?: "extension"; - - $activate = new Task\Activate($temp, $files, $type, $this->args->prefix, $this->args{"common-name"}, $sudo); - if (!$activate->run($this->verbosity())) { - $this->info("Extension already activated ...\n"); - } - } -} -mergeLicensePattern($name, strtolower($name)); - } - $exts = []; - foreach (["t{,e}xt", "rst", "asc{,i,ii}", "m{,ark}d{,own}", "htm{,l}"] as $ext) { - $exts[] = $this->mergeLicensePattern(strtoupper($ext), $ext); - } - - $pattern = "{". implode(",", $names) ."}{,.{". implode(",", $exts) ."}}"; - - if (($glob = glob("$dir/$pattern", GLOB_BRACE))) { - return current($glob); - } - } - - private function mergeLicensePattern($upper, $lower) { - $pattern = ""; - $length = strlen($upper); - for ($i = 0; $i < $length; ++$i) { - if ($lower{$i} === $upper{$i}) { - $pattern .= $upper{$i}; - } else { - $pattern .= "[" . $upper{$i} . $lower{$i} . "]"; - } - } - return $pattern; - } - - public function readLicense($file) { - $text = file_get_contents($file); - switch (strtolower(pathinfo($file, PATHINFO_EXTENSION))) { - case "htm": - case "html": - $text = strip_tags($text); - break; - } - return $text; - } -} -", self::version()); - } - - static function date() { - return gmdate("Y-m-d"); - } - - static function all() { - return [ - "version" => self::version(), - "header" => self::header(), - "date" => self::date(), - ]; - } -} -key); - $this->pub = openssl_pkey_get_details($key)["key"]; - } - - /** - * Sign the PHAR - * @param \Phar $package - */ - function sign(\Phar $package) { - $package->setSignatureAlgorithm(\Phar::OPENSSL, $this->key); - } - - /** - * Export the public key to a file - * @param string $file - * @throws \pharext\Exception - */ - function exportPublicKey($file) { - if (!file_put_contents("$file.tmp", $this->pub) || !rename("$file.tmp", $file)) { - throw new Exception; - } - } -} -args = new Cli\Args([ - ["h", "help", "Display this help", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - ["v", "verbose", "More output", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["q", "quiet", "Less output", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["n", "name", "Extension name", - Cli\Args::REQUIRED|Cli\Args::SINGLE|Cli\Args::REQARG], - ["r", "release", "Extension release version", - Cli\Args::REQUIRED|Cli\Args::SINGLE|Cli\Args::REQARG], - ["s", "source", "Extension source directory", - Cli\Args::REQUIRED|Cli\Args::SINGLE|Cli\Args::REQARG], - ["g", "git", "Use `git ls-tree` to determine file list", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["b", "branch", "Checkout this tag/branch", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::REQARG], - ["p", "pecl", "Use PECL package.xml to determine file list, name and release", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["d", "dest", "Destination directory", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::REQARG, - "."], - ["z", "gzip", "Create additional PHAR compressed with gzip", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["Z", "bzip", "Create additional PHAR compressed with bzip", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["S", "sign", "Sign the PHAR with a private key", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::REQARG], - ["E", "zend", "Mark as Zend Extension", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - [null, "signature", "Show pharext signature", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "license", "Show pharext license", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "version", "Show pharext version", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - ]); - } - - /** - * Perform cleaniup - */ - function __destruct() { - foreach ($this->cleanup as $cleanup) { - $cleanup->run(); - } - } - - /** - * @inheritdoc - * @see \pharext\Command::run() - */ - public function run($argc, array $argv) { - $errs = []; - $prog = array_shift($argv); - foreach ($this->args->parse(--$argc, $argv) as $error) { - $errs[] = $error; - } - - if ($this->args["help"]) { - $this->header(); - $this->help($prog); - exit; - } - try { - foreach (["signature", "license", "version"] as $opt) { - if ($this->args[$opt]) { - printf("%s\n", $this->metadata($opt)); - exit; - } - } - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EARGS); - } - - try { - /* source needs to be evaluated before Cli\Args validation, - * so e.g. name and version can be overriden and Cli\Args - * does not complain about missing arguments - */ - $this->loadSource(); - } catch (\Exception $e) { - $errs[] = $e->getMessage(); - } - - foreach ($this->args->validate() as $error) { - $errs[] = $error; - } - - if ($errs) { - if (!$this->args["quiet"]) { - $this->header(); - } - foreach ($errs as $err) { - $this->error("%s\n", $err); - } - printf("\n"); - if (!$this->args["quiet"]) { - $this->help($prog); - } - exit(self::EARGS); - } - - $this->createPackage(); - } - - /** - * Download remote source - * @param string $source - * @return string local source - */ - private function download($source) { - if ($this->args->git) { - $task = new Task\GitClone($source, $this->args->branch); - } else { - /* print newline only once */ - $done = false; - $task = new Task\StreamFetch($source, function($bytes_pct) use(&$done) { - if (!$done) { - $this->info(" %3d%% [%s>%s] \r", - floor($bytes_pct*100), - str_repeat("=", round(50*$bytes_pct)), - str_repeat(" ", round(50*(1-$bytes_pct))) - ); - if ($bytes_pct == 1) { - $done = true; - $this->info("\n"); - } - } - }); - } - $local = $task->run($this->verbosity()); - - $this->cleanup[] = new Task\Cleanup($local); - return $local; - } - - /** - * Extract local archive - * @param stirng $source - * @return string extracted directory - */ - private function extract($source) { - try { - $task = new Task\Extract($source); - $dest = $task->run($this->verbosity()); - } catch (\Exception $e) { - if (false === strpos($e->getMessage(), "checksum mismatch")) { - throw $e; - } - $dest = (new Task\PaxFixup($source))->run($this->verbosity()); - } - - $this->cleanup[] = new Task\Cleanup($dest); - return $dest; - } - - /** - * Localize a possibly remote source - * @param string $source - * @return string local source directory - */ - private function localize($source) { - if (!stream_is_local($source) || ($this->args->git && isset($this->args->branch))) { - $source = $this->download($source); - $this->cleanup[] = new Task\Cleanup($source); - } - $source = realpath($source); - if (!is_dir($source)) { - $source = $this->extract($source); - $this->cleanup[] = new Task\Cleanup($source); - - if (!$this->args->git) { - $source = (new Task\PeclFixup($source))->run($this->verbosity()); - } - } - return $source; - } - - /** - * Load the source dir - * @throws \pharext\Exception - */ - private function loadSource(){ - if ($this->args["source"]) { - $source = $this->localize($this->args["source"]); - - if ($this->args["pecl"]) { - $this->source = new SourceDir\Pecl($source); - } elseif ($this->args["git"]) { - $this->source = new SourceDir\Git($source); - } elseif (is_file("$source/pharext_package.php")) { - $this->source = include "$source/pharext_package.php"; - } else { - $this->source = new SourceDir\Basic($source); - } - - if (!$this->source instanceof SourceDir) { - throw new Exception("Unknown source dir $source"); - } - - foreach ($this->source->getPackageInfo() as $key => $val) { - $this->args->$key = $val; - } - } - } - - /** - * Creates the extension phar - */ - private function createPackage() { - try { - $meta = array_merge(Metadata::all(), [ - "name" => $this->args->name, - "release" => $this->args->release, - "license" => $this->source->getLicense(), - "type" => $this->args->zend ? "zend_extension" : "extension", - ]); - $file = (new Task\PharBuild($this->source, __DIR__."/../pharext_installer.php", $meta))->run($this->verbosity()); - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EBUILD); - } - - try { - if ($this->args->sign) { - $this->info("Using private key to sign phar ...\n"); - $pass = (new Task\Askpass)->run($this->verbosity()); - $sign = new Task\PharSign($file, $this->args->sign, $pass); - $pkey = $sign->run($this->verbosity()); - } - - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::ESIGN); - } - - if ($this->args->gzip) { - try { - $gzip = (new Task\PharCompress($file, Phar::GZ))->run(); - $move = new Task\PharRename($gzip, $this->args->dest, $this->args->name ."-". $this->args->release); - $name = $move->run($this->verbosity()); - - $this->info("Created gzipped phar %s\n", $name); - - if ($this->args->sign) { - $sign = new Task\PharSign($name, $this->args->sign, $pass); - $sign->run($this->verbosity())->exportPublicKey($name.".pubkey"); - } - - } catch (\Exception $e) { - $this->warn("%s\n", $e->getMessage()); - } - } - - if ($this->args->bzip) { - try { - $bzip = (new Task\PharCompress($file, Phar::BZ2))->run(); - $move = new Task\PharRename($bzip, $this->args->dest, $this->args->name ."-". $this->args->release); - $name = $move->run($this->verbosity()); - - $this->info("Created bzipped phar %s\n", $name); - - if ($this->args->sign) { - $sign = new Task\PharSign($name, $this->args->sign, $pass); - $sign->run($this->verbosity())->exportPublicKey($name.".pubkey"); - } - - } catch (\Exception $e) { - $this->warn("%s\n", $e->getMessage()); - } - } - - try { - $move = new Task\PharRename($file, $this->args->dest, $this->args->name ."-". $this->args->release); - $name = $move->run($this->verbosity()); - - $this->info("Created executable phar %s\n", $name); - - if (isset($pkey)) { - $pkey->exportPublicKey($name.".pubkey"); - } - - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EBUILD); - } - } -} -path = $path; - } - - public function getBaseDir() { - return $this->path; - } - - public function getPackageInfo() { - return []; - } - - public function getLicense() { - if (($file = $this->findLicense($this->getBaseDir()))) { - return $this->readLicense($file); - } - return "UNKNOWN"; - } - - public function getArgs() { - return []; - } - - public function setArgs(Args $args) { - } - - public function filter($current, $key, $iterator) { - $sub = $current->getSubPath(); - if ($sub === ".git" || $sub === ".hg" || $sub === ".svn") { - return false; - } - return true; - } - - public function getIterator() { - $rdi = new RecursiveDirectoryIterator($this->path, - FilesystemIterator::CURRENT_AS_SELF | // needed for 5.5 - FilesystemIterator::KEY_AS_PATHNAME | - FilesystemIterator::SKIP_DOTS); - $rci = new RecursiveCallbackFilterIterator($rdi, [$this, "filter"]); - $rii = new RecursiveIteratorIterator($rci); - foreach ($rii as $path => $child) { - if (!$child->isDir()) { - yield realpath($path); - } - } - } -} -path = $path; - } - - /** - * @inheritdoc - * @see \pharext\SourceDir::getBaseDir() - */ - public function getBaseDir() { - return $this->path; - } - - /** - * @inheritdoc - * @return array - */ - public function getPackageInfo() { - return []; - } - - /** - * @inheritdoc - * @return string - */ - public function getLicense() { - if (($file = $this->findLicense($this->getBaseDir()))) { - return $this->readLicense($file); - } - return "UNKNOWN"; - } - - /** - * @inheritdoc - * @return array - */ - public function getArgs() { - return []; - } - - /** - * @inheritdoc - */ - public function setArgs(Args $args) { - } - - /** - * Generate a list of files by `git ls-files` - * @return Generator - */ - private function generateFiles() { - $pwd = getcwd(); - chdir($this->path); - if (($pipe = popen("git ls-tree -r --name-only HEAD", "r"))) { - $path = realpath($this->path); - while (!feof($pipe)) { - if (strlen($file = trim(fgets($pipe)))) { - /* there may be symlinks, so no realpath here */ - yield "$path/$file"; - } - } - pclose($pipe); - } - chdir($pwd); - } - - /** - * Implements IteratorAggregate - * @see IteratorAggregate::getIterator() - */ - public function getIterator() { - return $this->generateFiles(); - } -} -file = "$path/package2.xml"); - } elseif (is_file("$path/package.xml")) { - $sxe = simplexml_load_file($this->file = "$path/package.xml"); - } else { - throw new Exception("Missing package.xml in $path"); - } - - $sxe->registerXPathNamespace("pecl", $sxe->getDocNamespaces()[""]); - - $this->sxe = $sxe; - $this->path = realpath($path); - } - - /** - * @inheritdoc - * @see \pharext\SourceDir::getBaseDir() - */ - public function getBaseDir() { - return $this->path; - } - - /** - * Retrieve gathered package info - * @return Generator - */ - public function getPackageInfo() { - if (($name = $this->sxe->xpath("/pecl:package/pecl:name"))) { - yield "name" => (string) $name[0]; - } - if (($release = $this->sxe->xpath("/pecl:package/pecl:version/pecl:release"))) { - yield "release" => (string) $release[0]; - } - if ($this->sxe->xpath("/pecl:package/pecl:zendextsrcrelease")) { - yield "zend" => true; - } - } - - /** - * @inheritdoc - * @return string - */ - public function getLicense() { - if (($license = $this->sxe->xpath("/pecl:package/pecl:license"))) { - if (($file = $this->findLicense($this->getBaseDir(), $license[0]["filesource"]))) { - return $this->readLicense($file); - } - } - if (($file = $this->findLicense($this->getBaseDir()))) { - return $this->readLicense($file); - } - if ($license) { - return $license[0] ." ". $license[0]["uri"]; - } - return "UNKNOWN"; - } - - /** - * @inheritdoc - * @see \pharext\SourceDir::getArgs() - */ - public function getArgs() { - $configure = $this->sxe->xpath("/pecl:package/pecl:extsrcrelease/pecl:configureoption"); - foreach ($configure as $cfg) { - yield [null, $cfg["name"], ucfirst($cfg["prompt"]), Args::OPTARG, - strlen($cfg["default"]) ? $cfg["default"] : null]; - } - $configure = $this->sxe->xpath("/pecl:package/pecl:zendextsrcrelease/pecl:configureoption"); - foreach ($configure as $cfg) { - yield [null, $cfg["name"], ucfirst($cfg["prompt"]), Args::OPTARG, - strlen($cfg["default"]) ? $cfg["default"] : null]; - } - } - - /** - * @inheritdoc - * @see \pharext\SourceDir::setArgs() - */ - public function setArgs(Args $args) { - $configure = $this->sxe->xpath("/pecl:package/pecl:extsrcrelease/pecl:configureoption"); - foreach ($configure as $cfg) { - if (isset($args[$cfg["name"]])) { - $args->configure = "--{$cfg["name"]}={$args[$cfg["name"]]}"; - } - } - $configure = $this->sxe->xpath("/pecl:package/pecl:zendextsrcrelease/pecl:configureoption"); - foreach ($configure as $cfg) { - if (isset($args[$cfg["name"]])) { - $args->configure = "--{$cfg["name"]}={$args[$cfg["name"]]}"; - } - } - } - - /** - * Compute the path of a file by parent dir nodes - * @param \SimpleXMLElement $ele - * @return string - */ - private function dirOf($ele) { - $path = ""; - while (($ele = current($ele->xpath(".."))) && $ele->getName() == "dir") { - $path = trim($ele["name"], "/") ."/". $path ; - } - return trim($path, "/"); - } - - /** - * Generate a list of files from the package.xml - * @return Generator - */ - private function generateFiles() { - /* hook */ - $temp = tmpfile(); - fprintf($temp, " $temp; - - /* deps */ - $dependencies = $this->sxe->xpath("/pecl:package/pecl:dependencies/pecl:required/pecl:package"); - foreach ($dependencies as $key => $dep) { - if (($glob = glob("{$this->path}/{$dep->name}-*.ext.phar*"))) { - usort($glob, function($a, $b) { - return version_compare( - substr($a, strpos(".ext.phar", $a)), - substr($b, strpos(".ext.phar", $b)) - ); - }); - yield end($glob); - } - } - - /* files */ - yield realpath($this->file); - foreach ($this->sxe->xpath("//pecl:file") as $file) { - yield realpath($this->path ."/". $this->dirOf($file) ."/". $file["name"]); - } - } - - /** - * Implements IteratorAggregate - * @see IteratorAggregate::getIterator() - */ - public function getIterator() { - return $this->generateFiles(); - } -} -cwd = $cwd; - $this->type = $type; - $this->sudo = $sudo; - if (!$this->inis = $inis) { - throw new Exception("No PHP INIs given"); - } - $cmd = $common_name . "-config"; - if (isset($prefix)) { - $cmd = $prefix . "/bin/" . $cmd; - } - $this->php_config = $cmd; - } - - /** - * @param bool $verbose - * @return boolean false, if extension was already activated - */ - public function run($verbose = false) { - if ($verbose !== false) { - printf("Running INI activation ...\n"); - } - $extension = basename(current(glob("{$this->cwd}/modules/*.so"))); - - if ($this->type === "zend_extension") { - $pattern = preg_quote((new ExecCmd($this->php_config))->run(["--extension-dir"])->getOutput() . "/$extension", "/"); - } else { - $pattern = preg_quote($extension, "/"); - } - - foreach ($this->inis as $file) { - if ($verbose) { - printf("Checking %s ...\n", $file); - } - if (!file_exists($file)) { - throw new Exception(sprintf("INI file '%s' does not exist", $file)); - } - $temp = new Tempfile("phpini"); - foreach (file($file) as $line) { - if (preg_match("/^\s*{$this->type}\s*=\s*[\"']?{$pattern}[\"']?\s*(;.*)?\$/", $line)) { - return false; - } - fwrite($temp->getStream(), $line); - } - } - - /* not found; append to last processed file, which is the main by default */ - if ($verbose) { - printf("Activating in %s ...\n", $file); - } - fprintf($temp->getStream(), $this->type . "=%s\n", $extension); - $temp->closeStream(); - - $path = $temp->getPathname(); - $stat = stat($file); - - // owner transfer - $ugid = sprintf("%d:%d", $stat["uid"], $stat["gid"]); - $cmd = new ExecCmd("chown", $verbose); - if (isset($this->sudo)) { - $cmd->setSu($this->sudo); - } - $cmd->run([$ugid, $path]); - - // permission transfer - $perm = decoct($stat["mode"] & 0777); - $cmd = new ExecCmd("chmod", $verbose); - if (isset($this->sudo)) { - $cmd->setSu($this->sudo); - } - $cmd->run([$perm, $path]); - - // rename - $cmd = new ExecCmd("mv", $verbose); - if (isset($this->sudo)) { - $cmd->setSu($this->sudo); - } - $cmd->run([$path, $file]); - - if ($verbose) { - printf("Replaced %s ...\n", $file); - } - - return true; - } -} -prompt = $prompt; - } - - /** - * @param bool $verbose - * @return string - */ - public function run($verbose = false) { - system("stty -echo"); - printf("%s ", $this->prompt); - $pass = fgets(STDIN, 1024); - printf("\n"); - system("stty echo"); - if (substr($pass, -1) == "\n") { - $pass = substr($pass, 0, -1); - } - return $pass; - } -} -rewind(); $rii->valid(); $rii->next()) { - if (!$rii->isDot()) { - yield $rii->getSubPathname() => $rii->key(); - } - } - } -} -rm = $rm; - } - - /** - * @param bool $verbose - */ - public function run($verbose = false) { - if ($verbose) { - printf("Cleaning up %s ...\n", $this->rm); - } - if ($this->rm instanceof Tempfile) { - unset($this->rm); - } elseif (is_dir($this->rm)) { - $rdi = new RecursiveDirectoryIterator($this->rm, - FilesystemIterator::CURRENT_AS_SELF | // needed for 5.5 - FilesystemIterator::KEY_AS_PATHNAME | - FilesystemIterator::SKIP_DOTS); - $rii = new RecursiveIteratorIterator($rdi, - RecursiveIteratorIterator::CHILD_FIRST); - foreach ($rii as $path => $child) { - if ($child->isDir()) { - @rmdir($path); - } else { - @unlink($path); - } - } - @rmdir($this->rm); - } elseif (file_exists($this->rm)) { - @unlink($this->rm); - } - } -} -cwd = $cwd; - $cmd = $common_name . "-config"; - if (isset($prefix)) { - $cmd = $prefix . "/bin/" . $cmd; - } - $this->args = ["--with-php-config=$cmd"]; - if ($args) { - $this->args = array_merge($this->args, $args); - } - } - - public function run($verbose = false) { - if ($verbose !== false) { - printf("Running ./configure ...\n"); - } - $pwd = getcwd(); - if (!chdir($this->cwd)) { - throw new Exception; - } - try { - $cmd = new ExecCmd("./configure", $verbose); - $cmd->run($this->args); - } finally { - chdir($pwd); - } - } -} -source = $source; - } else { - $this->source = new PharData($source); - } - } - - /** - * @param bool $verbose - * @return \pharext\Tempdir - */ - public function run($verbose = false) { - if ($verbose) { - printf("Extracting %s ...\n", basename($this->source->getPath())); - } - if ($this->source instanceof Archive) { - return $this->source->extract(); - } - $dest = new Tempdir("extract"); - $this->source->extractTo($dest); - return $dest; - } -} -source = $source; - $this->branch = $branch; - } - - /** - * @param bool $verbose - * @return \pharext\Tempdir - */ - public function run($verbose = false) { - if ($verbose !== false) { - printf("Fetching %s ...\n", $this->source); - } - $local = new Tempdir("gitclone"); - $cmd = new ExecCmd("git", $verbose); - if (strlen($this->branch)) { - $cmd->run(["clone", "--depth", 1, "--branch", $this->branch, $this->source, $local]); - } else { - $cmd->run(["clone", $this->source, $local]); - } - return $local; - } -} -cwd = $cwd; - $this->sudo = $sudo; - $this->args = $args; - } - - /** - * - * @param bool $verbose - * @throws \pharext\Exception - */ - public function run($verbose = false) { - if ($verbose !== false) { - printf("Running make"); - if ($this->args) { - foreach ($this->args as $arg) { - printf(" %s", $arg); - } - } - printf(" ...\n"); - } - $pwd = getcwd(); - if (!chdir($this->cwd)) { - throw new Exception; - } - try { - $cmd = new ExecCmd("make", $verbose); - if (isset($this->sudo)) { - $cmd->setSu($this->sudo); - } - $args = $this->args; - if (!$verbose) { - $args = array_merge((array) $args, ["-s"]); - } - $cmd->run($args); - } finally { - chdir($pwd); - } - } -} -source = $source; - } - - private function openArchive($source) { - $hdr = file_get_contents($source, false, null, 0, 3); - if ($hdr === "\x1f\x8b\x08") { - $fd = fopen("compress.zlib://$source", "r"); - } elseif ($hdr === "BZh") { - $fd = fopen("compress.bzip2://$source", "r"); - } else { - $fd = fopen($source, "r"); - } - if (!is_resource($fd)) { - throw new Exception; - } - return $fd; - } - - public function run($verbose = false) { - if ($verbose !== false) { - printf("Fixing up a tarball with global pax header ...\n"); - } - $temp = new Tempfile("paxfix"); - stream_copy_to_stream($this->openArchive($this->source), - $temp->getStream(), -1, 1024); - $temp->closeStream(); - return (new Extract((string) $temp))->run($verbose); - } -}source = $source; - } - - /** - * @param bool $verbose - * @return string sanitized source location - * @throws \pahrext\Exception - */ - public function run($verbose = false) { - if ($verbose !== false) { - printf("Sanitizing PECL dir ...\n"); - } - $dirs = glob("{$this->source}/*", GLOB_ONLYDIR); - $files = array_diff(glob("{$this->source}/*"), $dirs); - $check = array_reduce($files, function($r, $v) { - return $v && fnmatch("package*.xml", basename($v)); - }, true); - - if (count($dirs) !== 1 || !$check) { - throw new Exception("Does not look like an extracted PECL dir: {$this->source}"); - } - - $dest = current($dirs); - - foreach ($files as $file) { - if ($verbose) { - printf("Moving %s into %s ...\n", basename($file), basename($dest)); - } - if (!rename($file, "$dest/" . basename($file))) { - throw new Exception; - } - } - - return $dest; - } -} -source = $source; - $this->stub = $stub; - $this->meta = $meta; - $this->readonly = $readonly; - } - - /** - * @param bool $verbose - * @return \pharext\Tempname - * @throws \pharext\Exception - */ - public function run($verbose = false) { - /* Phar::compress() and ::convert*() use strtok("."), ugh! - * so, be sure to not use any other dots in the filename - * except for .phar - */ - $temp = new Tempname("", "-pharext.phar"); - - $phar = new Phar($temp); - $phar->startBuffering(); - - if ($this->meta) { - $phar->setMetadata($this->meta); - } - if ($this->stub) { - (new PharStub($phar, $this->stub))->run($verbose); - } - - $phar->buildFromIterator((new Task\BundleGenerator)->run()); - - if ($this->source) { - if ($verbose) { - $bdir = $this->source->getBaseDir(); - $blen = strlen($bdir); - foreach ($this->source as $index => $file) { - if (is_resource($file)) { - printf("Packaging %s ...\n", $index); - $phar[$index] = $file; - } else { - printf("Packaging %s ...\n", $index = trim(substr($file, $blen), "/")); - $phar->addFile($file, $index); - } - } - } else { - $phar->buildFromIterator($this->source, $this->source->getBaseDir()); - } - } - - $phar->stopBuffering(); - - if (!chmod($temp, fileperms($temp) | 0111)) { - throw new Exception; - } - - return $temp; - } -}file = $file; - $this->package = new Phar($file); - $this->encoding = $encoding; - - switch ($encoding) { - case Phar::GZ: - $this->extension = ".gz"; - break; - case Phar::BZ2: - $this->extension = ".bz2"; - break; - } - } - - /** - * @param bool $verbose - * @return string - */ - public function run($verbose = false) { - if ($verbose) { - printf("Compressing %s ...\n", basename($this->package->getPath())); - } - /* stop shebang */ - $stub = $this->package->getStub(); - $phar = $this->package->compress($this->encoding); - $phar->setStub(substr($stub, strpos($stub, "\n")+1)); - return $this->file . $this->extension; - } -} -phar = $phar; - $this->dest = $dest; - $this->name = $name; - } - - /** - * @param bool $verbose - * @return string path to renamed phar - * @throws \pharext\Exception - */ - public function run($verbose = false) { - $extension = substr(strstr($this->phar, "-pharext.phar"), 8); - $name = sprintf("%s/%s.ext%s", $this->dest, $this->name, $extension); - - if ($verbose) { - printf("Renaming %s to %s ...\n", basename($this->phar), basename($name)); - } - - if (!rename($this->phar, $name)) { - throw new Exception; - } - - return $name; - } -} -phar = $phar; - } else { - $this->phar = new Phar($phar); - } - $this->pkey = new Openssl\PrivateKey($pkey, $pass); - } - - /** - * @param bool $verbose - * @return \pharext\Openssl\PrivateKey - */ - public function run($verbose = false) { - if ($verbose) { - printf("Signing %s ...\n", basename($this->phar->getPath())); - } - $this->pkey->sign($this->phar); - return $this->pkey; - } -} -phar = $phar; - if (!file_exists($this->stub = $stub)) { - throw new Exception("File '$stub' does not exist"); - } - } - - /** - * @param bool $verbose - */ - function run($verbose = false) { - if ($verbose) { - printf("Using stub '%s'...\n", basename($this->stub)); - } - $stub = preg_replace_callback('/^#include <([^>]+)>/m', function($includes) { - return file_get_contents($includes[1], true, null, 5); - }, file_get_contents($this->stub)); - if ($this->phar->isCompressed() && substr($stub, 0, 2) === "#!") { - $stub = substr($stub, strpos($stub, "\n")+1); - } - $this->phar->setStub($stub); - } -} -cwd = $cwd; - $cmd = $common_name . "ize"; - if (isset($prefix)) { - $cmd = $prefix . "/bin/" . $cmd; - } - $this->phpize = $cmd; - } - - /** - * @param bool $verbose - * @throws \pharext\Exception - */ - public function run($verbose = false) { - if ($verbose !== false) { - printf("Running %s ...\n", $this->phpize); - } - $pwd = getcwd(); - if (!chdir($this->cwd)) { - throw new Exception; - } - try { - $cmd = new ExecCmd($this->phpize, $verbose); - $cmd->run(); - } finally { - chdir($pwd); - } - } -} -source = $source; - $this->progress = $progress; - } - - private function createStreamContext() { - $progress = $this->progress; - - /* avoid bytes_max bug of older PHP versions */ - $maxbytes = 0; - return stream_context_create([],["notification" => function($notification, $severity, $message, $code, $bytes_cur, $bytes_max) use($progress, &$maxbytes) { - if ($bytes_max > $maxbytes) { - $maxbytes = $bytes_max; - } - switch ($notification) { - case STREAM_NOTIFY_CONNECT: - $progress(0); - break; - case STREAM_NOTIFY_PROGRESS: - $progress($maxbytes > 0 ? $bytes_cur/$maxbytes : .5); - break; - case STREAM_NOTIFY_COMPLETED: - /* this is sometimes not generated, why? */ - $progress(1); - break; - } - }]); - } - - /** - * @param bool $verbose - * @return \pharext\Task\Tempfile - * @throws \pharext\Exception - */ - public function run($verbose = false) { - if ($verbose !== false) { - printf("Fetching %s ...\n", $this->source); - } - $context = $this->createStreamContext(); - - if (!$remote = fopen($this->source, "r", false, $context)) { - throw new Exception; - } - - $local = new Tempfile("remote"); - if (!stream_copy_to_stream($remote, $local->getStream())) { - throw new Exception; - } - $local->closeStream(); - - /* STREAM_NOTIFY_COMPLETED is not generated, see above */ - call_user_func($this->progress, 1); - - return $local; - } -} -handle = fopen($path, "x"); - } while (!is_resource($this->handle) && $tries++ < 10); - umask($omask); - - if (!is_resource($this->handle)) { - throw new Exception("Could not create temporary file"); - } - - parent::__construct($path); - } - - /** - * Unlink the file - */ - public function __destruct() { - if (is_file($this->getPathname())) { - @unlink($this->getPathname()); - } - } - - /** - * Close the stream - */ - public function closeStream() { - fclose($this->handle); - } - - /** - * Retrieve the stream resource - * @return resource - */ - public function getStream() { - return $this->handle; - } -} -getUser(); - if (!is_dir($temp) && !mkdir($temp, 0700, true)) { - throw new Exception; - } - $this->name = $temp ."/". uniqid($prefix) . $suffix; - } - - private function getUser() { - if (extension_loaded("posix") && function_exists("posix_getpwuid")) { - return posix_getpwuid(posix_getuid())["name"]; - } - return trim(`whoami 2>/dev/null`) - ?: trim(`id -nu 2>/dev/null`) - ?: getenv("USER") - ?: get_current_user(); - } - - /** - * @return string - */ - public function __toString() { - return (string) $this->name; - } -} -args = new Cli\Args([ - ["h", "help", "Display this help", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - ["v", "verbose", "More output", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - ["q", "quiet", "Less output", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG], - [null, "signature", "Show pharext signature", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "license", "Show pharext license", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [null, "version", "Show pharext version", - Cli\Args::OPTIONAL|Cli\Args::SINGLE|Cli\Args::NOARG|Cli\Args::HALT], - [0, "path", "Path to .ext.phar to update", - Cli\Args::REQUIRED|Cli\Args::MULTI], - ]); - } - - /** - * @inheritdoc - * @see \pharext\Command::run() - */ - public function run($argc, array $argv) { - $errs = []; - $prog = array_shift($argv); - foreach ($this->args->parse(--$argc, $argv) as $error) { - $errs[] = $error; - } - - if ($this->args["help"]) { - $this->header(); - $this->help($prog); - exit; - } - - try { - foreach (["signature", "license", "version"] as $opt) { - if ($this->args[$opt]) { - printf("%s\n", $this->metadata($opt)); - exit; - } - } - } catch (\Exception $e) { - $this->error("%s\n", $e->getMessage()); - exit(self::EARGS); - } - - - foreach ($this->args->validate() as $error) { - $errs[] = $error; - } - - if ($errs) { - if (!$this->args["quiet"]) { - $this->header(); - } - foreach ($errs as $err) { - $this->error("%s\n", $err); - } - printf("\n"); - if (!$this->args["quiet"]) { - $this->help($prog); - } - exit(self::EARGS); - } - - foreach ($this->args[0] as $file) { - $info = new SplFileInfo($file); - - while ($info->isLink()) { - $info = new SplFileInfo($info->getLinkTarget()); - } - - if ($info->isFile()) { - if (!$this->updatePackage($info)) { - $this->warn("Cannot upgrade pre-v3 packages\n"); - } - } else { - $this->error("File '%s' does not exist\n", $file); - exit(self::EARGS); - } - } - } - - /** - * Replace the pharext core in an .ext.phar package - * @param string $temp path to temp phar - * @return boolean FALSE if the package is too old (pre-v3) to upgrade - */ - private function replacePharext($temp) { - $phar = new Phar($temp, Phar::CURRENT_AS_SELF); - $phar->startBuffering(); - - if (!$meta = $phar->getMetadata()) { - // don't upgrade pre-v3 packages - return false; - } - - // replace current pharext files - $core = (new Task\BundleGenerator)->run($this->verbosity()); - $phar->buildFromIterator($core); - $stub = __DIR__."/../pharext_installer.php"; - (new Task\PharStub($phar, $stub))->run($this->verbosity()); - - // check dependencies - foreach ($phar as $info) { - if (fnmatch("*.ext.phar*", $info->getBasename())) { - $this->updatePackage($info, $phar); - } - } - - $phar->stopBuffering(); - - $phar->setMetadata([ - "version" => Metadata::version(), - "header" => Metadata::header(), - ] + $meta); - - $this->info("Updated pharext version from '%s' to '%s'\n", - isset($meta["version"]) ? $meta["version"] : "(unknown)", - $phar->getMetadata()["version"]); - - return true; - } - - /** - * Update an .ext.phar package to the current pharext version - * @param SplFileInfo $file - * @param Phar $phar the parent phar containing $file as dependency - * @return boolean FALSE if the package is too old (pre-v3) to upgrade - * @throws Exception - */ - private function updatePackage(SplFileInfo $file, Phar $phar = null) { - $this->info("Updating pharext core in '%s'...\n", basename($file)); - - $temp = new Tempname("update", substr(strstr($file, ".ext.phar"), 4)); - - if (!copy($file->getPathname(), $temp)) { - throw new Exception; - } - if (!chmod($temp, $file->getPerms())) { - throw new Exception; - } - - if (!$this->replacePharext($temp)) { - return false; - } - - if ($phar) { - $phar->addFile($temp, $file); - } elseif (!rename($temp, $file->getPathname())) { - throw new Exception; - } - - return true; - } -} -#!/usr/bin/env php - -#include -#include -#include -#include - -namespace pharext; - -if (extension_loaded("Phar")) { - \Phar::interceptFileFuncs(); - \Phar::mapPhar(); - $phardir = "phar://".__FILE__; -} else { - $archive = new Archive(__FILE__); - $phardir = $archive->extract(); -} - -set_include_path("$phardir:". get_include_path()); - -$installer = new Installer(); -$installer->run($argc, $argv); - -__HALT_COMPILER(); -#!/usr/bin/php -dphar.readonly=0 -run($argc, $argv); - -__HALT_COMPILER(); -#!/usr/bin/php -dphar.readonly=0 -run($argc, $argv); - -__HALT_COMPILER(); - - - raphf - pecl.php.net - Resource and persistent handles factory - A reusable split-off of pecl_http's persistent handle and resource factory API. - - Michael Wallner - mike - mike@php.net - yes - - 2015-07-28 - - 1.1.0 - 1.0.0 - - - stable - stable - - BSD, revised - - - - - - - - - - - - - - - - - - - - - - - 5.3.0 - 7.0.0 - 7.0.0 - - - 1.4.0 - - - - raphf - - - -raphf -Michael Wallner -Copyright (c) 2013, Michael Wallner . -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Doxyfile 1.8.9.1 - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "Resource and persistent handle factory API" -PROJECT_NUMBER = -PROJECT_BRIEF = "A facility to manage possibly persistent resources with a comprehensible API. Provides simliar functionality like the zend_list API, but with more flexiblity and freedom." -PROJECT_LOGO = raphf.png -OUTPUT_DIRECTORY = -CREATE_SUBDIRS = NO -ALLOW_UNICODE_NAMES = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = YES -STRIP_FROM_PATH = -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = YES -QT_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 4 -ALIASES = -TCL_SUBST = -OPTIMIZE_OUTPUT_FOR_C = YES -OPTIMIZE_OUTPUT_JAVA = NO -OPTIMIZE_FOR_FORTRAN = NO -OPTIMIZE_OUTPUT_VHDL = NO -EXTENSION_MAPPING = -MARKDOWN_SUPPORT = YES -AUTOLINK_SUPPORT = YES -BUILTIN_STL_SUPPORT = NO -CPP_CLI_SUPPORT = NO -SIP_SUPPORT = NO -IDL_PROPERTY_SUPPORT = YES -DISTRIBUTE_GROUP_DOC = NO -SUBGROUPING = YES -INLINE_GROUPED_CLASSES = NO -INLINE_SIMPLE_STRUCTS = YES -TYPEDEF_HIDES_STRUCT = NO -LOOKUP_CACHE_SIZE = 0 -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = YES -EXTRACT_PRIVATE = NO -EXTRACT_PACKAGE = NO -EXTRACT_STATIC = NO -EXTRACT_LOCAL_CLASSES = NO -EXTRACT_LOCAL_METHODS = NO -EXTRACT_ANON_NSPACES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -HIDE_COMPOUND_REFERENCE= NO -SHOW_INCLUDE_FILES = YES -SHOW_GROUPED_MEMB_INC = NO -FORCE_LOCAL_INCLUDES = NO -INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -SORT_BRIEF_DOCS = NO -SORT_MEMBERS_CTORS_1ST = NO -SORT_GROUP_NAMES = NO -SORT_BY_SCOPE_NAME = NO -STRICT_PROTO_MATCHING = NO -GENERATE_TODOLIST = YES -GENERATE_TESTLIST = YES -GENERATE_BUGLIST = YES -GENERATE_DEPRECATEDLIST= YES -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -SHOW_FILES = YES -SHOW_NAMESPACES = YES -FILE_VERSION_FILTER = -LAYOUT_FILE = -CITE_BIB_FILES = -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = YES -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = php_raphf.h -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = -RECURSIVE = NO -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = -EXCLUDE_SYMBOLS = -EXAMPLE_PATH = -EXAMPLE_PATTERNS = -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -FILTER_SOURCE_PATTERNS = -USE_MDFILE_AS_MAINPAGE = -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = NO -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = YES -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES -SOURCE_TOOLTIPS = YES -USE_HTAGS = NO -VERBATIM_HEADERS = YES -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = YES -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = . -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = -HTML_STYLESHEET = -HTML_EXTRA_STYLESHEET = -HTML_EXTRA_FILES = -HTML_COLORSTYLE_HUE = 220 -HTML_COLORSTYLE_SAT = 100 -HTML_COLORSTYLE_GAMMA = 80 -HTML_TIMESTAMP = NO -HTML_DYNAMIC_SECTIONS = NO -HTML_INDEX_NUM_ENTRIES = 100 -GENERATE_DOCSET = NO -DOCSET_FEEDNAME = "Doxygen generated docs" -DOCSET_BUNDLE_ID = org.doxygen.Project -DOCSET_PUBLISHER_ID = org.doxygen.Publisher -DOCSET_PUBLISHER_NAME = Publisher -GENERATE_HTMLHELP = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -CHM_INDEX_ENCODING = -BINARY_TOC = NO -TOC_EXPAND = NO -GENERATE_QHP = NO -QCH_FILE = -QHP_NAMESPACE = org.doxygen.Project -QHP_VIRTUAL_FOLDER = doc -QHP_CUST_FILTER_NAME = -QHP_CUST_FILTER_ATTRS = -QHP_SECT_FILTER_ATTRS = -QHG_LOCATION = -GENERATE_ECLIPSEHELP = NO -ECLIPSE_DOC_ID = org.doxygen.Project -DISABLE_INDEX = NO -GENERATE_TREEVIEW = YES -ENUM_VALUES_PER_LINE = 4 -TREEVIEW_WIDTH = 250 -EXT_LINKS_IN_WINDOW = NO -FORMULA_FONTSIZE = 10 -FORMULA_TRANSPARENT = YES -USE_MATHJAX = NO -MATHJAX_FORMAT = HTML-CSS -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest -MATHJAX_EXTENSIONS = -MATHJAX_CODEFILE = -SEARCHENGINE = YES -SERVER_BASED_SEARCH = NO -EXTERNAL_SEARCH = NO -SEARCHENGINE_URL = -SEARCHDATA_FILE = searchdata.xml -EXTERNAL_SEARCH_ID = -EXTRA_SEARCH_MAPPINGS = -#--------------------------------------------------------------------------- -# Configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4 -EXTRA_PACKAGES = -LATEX_HEADER = -LATEX_FOOTER = -LATEX_EXTRA_STYLESHEET = -LATEX_EXTRA_FILES = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -LATEX_SOURCE_CODE = NO -LATEX_BIB_STYLE = plain -#--------------------------------------------------------------------------- -# Configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -RTF_SOURCE_CODE = NO -#--------------------------------------------------------------------------- -# Configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_SUBDIR = -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# Configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_PROGRAMLISTING = YES -#--------------------------------------------------------------------------- -# Configuration options related to the DOCBOOK output -#--------------------------------------------------------------------------- -GENERATE_DOCBOOK = NO -DOCBOOK_OUTPUT = docbook -DOCBOOK_PROGRAMLISTING = NO -#--------------------------------------------------------------------------- -# Configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# Configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = YES -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = DOXYGEN \ - TSRMLS_C= \ - TSRMLS_D= \ - TSRMLS_CC= \ - TSRMLS_DC= \ - PHP_RAPHF_API= -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -#--------------------------------------------------------------------------- -# Configuration options related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -EXTERNAL_PAGES = YES -PERL_PATH = /usr/bin/perl -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = YES -MSCGEN_PATH = -DIA_PATH = -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = YES -DOT_NUM_THREADS = 0 -DOT_FONTNAME = Helvetica -DOT_FONTSIZE = 10 -DOT_FONTPATH = -CLASS_GRAPH = NO -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = NO -UML_LIMIT_NUM_FIELDS = 10 -TEMPLATE_RELATIONS = NO -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = YES -CALLER_GRAPH = YES -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -INTERACTIVE_SVG = NO -DOT_PATH = -DOTFILE_DIRS = -MSCFILE_DIRS = -DIAFILE_DIRS = -PLANTUML_JAR_PATH = -PLANTUML_INCLUDE_PATH = -DOT_GRAPH_MAX_NODES = 50 -MAX_DOT_GRAPH_DEPTH = 0 -DOT_TRANSPARENT = NO -DOT_MULTI_TARGETS = NO -GENERATE_LEGEND = YES -DOT_CLEANUP = YES -PHP_ARG_ENABLE(raphf, whether to enable raphf support, -[ --enable-raphf Enable resource and persistent handles factory support]) - -if test "$PHP_RAPHF" != "no"; then - PHP_INSTALL_HEADERS(ext/raphf, php_raphf.h php_raphf_api.h) - PHP_NEW_EXTENSION(raphf, php_raphf.c, $ext_shared) -fi - - -ARG_ENABLE("raphf", "for raphf support", "no"); - -if (PHP_RAPHF == "yes") { - EXTENSION("raphf", "php_raphf.c"); - - AC_DEFINE("HAVE_RAPHF", 1); - PHP_INSTALL_HEADERS("ext/raphf", "php_raphf.h"); -} -/* - +--------------------------------------------------------------------+ - | PECL :: raphf | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2013, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_RAPHF_H -#define PHP_RAPHF_H - -extern zend_module_entry raphf_module_entry; -#define phpext_raphf_ptr &raphf_module_entry - -#define PHP_RAPHF_VERSION "1.1.0" - -#ifdef PHP_WIN32 -# define PHP_RAPHF_API __declspec(dllexport) -#elif defined(__GNUC__) && __GNUC__ >= 4 -# define PHP_RAPHF_API extern __attribute__ ((visibility("default"))) -#else -# define PHP_RAPHF_API extern -#endif - -#ifdef ZTS -# include "TSRM.h" -#endif - -#include "php_raphf_api.h" - -#endif /* PHP_RAPHF_H */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ -/* - +--------------------------------------------------------------------+ - | PECL :: raphf | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2013, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifndef PHP_RAPHF_API_H -#define PHP_RAPHF_API_H - -/** - * A resource constructor. - * - * @param opaque is the \a data from php_persistent_handle_provide() - * @param init_arg is the \a init_arg from php_resource_factory_init() - * @return the created (persistent) handle - */ -typedef void *(*php_resource_factory_handle_ctor_t)(void *opaque, - void *init_arg TSRMLS_DC); - -/** - * The copy constructor of a resource. - * - * @param opaque the factory's data - * @param handle the (persistent) handle to copy - */ -typedef void *(*php_resource_factory_handle_copy_t)(void *opaque, - void *handle TSRMLS_DC); - -/** - * The destructor of a resource. - * - * @param opaque the factory's data - * @param handle the handle to destroy - */ -typedef void (*php_resource_factory_handle_dtor_t)(void *opaque, - void *handle TSRMLS_DC); - -/** - * The resource ops consisting of a ctor, a copy ctor and a dtor. - * - * Define this ops and register them with php_persistent_handle_provide() - * in MINIT. - */ -typedef struct php_resource_factory_ops { - /** The resource constructor */ - php_resource_factory_handle_ctor_t ctor; - /** The resource's copy constructor */ - php_resource_factory_handle_copy_t copy; - /** The resource's destructor */ - php_resource_factory_handle_dtor_t dtor; -} php_resource_factory_ops_t; - -/** - * The resource factory. - */ -typedef struct php_resource_factory { - /** The resource ops */ - php_resource_factory_ops_t fops; - /** Opaque user data */ - void *data; - /** User data destructor */ - void (*dtor)(void *data); - /** How often this factory is referenced */ - unsigned refcount; -} php_resource_factory_t; - -/** - * Initialize a resource factory. - * - * If you register a \a dtor for a resource factory used with a persistent - * handle provider, be sure to call php_persistent_handle_cleanup() for your - * registered provider in MSHUTDOWN, else the dtor will point to no longer - * available memory if the extension has already been unloaded. - * - * @param f the factory to initialize; if NULL allocated on the heap - * @param fops the resource ops to assign to the factory - * @param data opaque user data; may be NULL - * @param dtor a destructor for the data; may be NULL - * @return \a f or an allocated resource factory - */ -PHP_RAPHF_API php_resource_factory_t *php_resource_factory_init( - php_resource_factory_t *f, php_resource_factory_ops_t *fops, void *data, - void (*dtor)(void *data)); - -/** - * Increase the refcount of the resource factory. - * - * @param rf the resource factory - * @return the new refcount - */ -PHP_RAPHF_API unsigned php_resource_factory_addref(php_resource_factory_t *rf); - -/** - * Destroy the resource factory. - * - * If the factory's refcount reaches 0, the \a dtor for \a data is called. - * - * @param f the resource factory - */ -PHP_RAPHF_API void php_resource_factory_dtor(php_resource_factory_t *f); - -/** - * Destroy and free the resource factory. - * - * Calls php_resource_factory_dtor() and frees \æ f if the factory's refcount - * reached 0. - * - * @param f the resource factory - */ -PHP_RAPHF_API void php_resource_factory_free(php_resource_factory_t **f); - -/** - * Construct a resource by the resource factory \a f - * - * @param f the resource factory - * @param init_arg for the resource constructor - * @return the new resource - */ -PHP_RAPHF_API void *php_resource_factory_handle_ctor(php_resource_factory_t *f, - void *init_arg TSRMLS_DC); - -/** - * Create a copy of the resource \a handle - * - * @param f the resource factory - * @param handle the resource to copy - * @return the copy - */ -PHP_RAPHF_API void *php_resource_factory_handle_copy(php_resource_factory_t *f, - void *handle TSRMLS_DC); - -/** - * Destroy (and free) the resource - * - * @param f the resource factory - * @param handle the resource to destroy - */ -PHP_RAPHF_API void php_resource_factory_handle_dtor(php_resource_factory_t *f, - void *handle TSRMLS_DC); - -/** - * Persistent handles storage - */ -typedef struct php_persistent_handle_list { - /** Storage of free resources */ - HashTable free; - /** Count of acquired resources */ - ulong used; -} php_persistent_handle_list_t; - -/** - * Definition of a persistent handle provider. - * Holds a resource factory an a persistent handle list. - */ -typedef struct php_persistent_handle_provider { - /** - * The list of free handles. - * Hash of "ident" => array(handles) entries. Persistent handles are - * acquired out of this list. - */ - php_persistent_handle_list_t list; - - /** - * The resource factory. - * New handles are created by this factory. - */ - php_resource_factory_t rf; -} php_persistent_handle_provider_t; - -typedef struct php_persistent_handle_factory php_persistent_handle_factory_t; - -/** - * Wakeup the persistent handle on re-acquisition. - */ -typedef void (*php_persistent_handle_wakeup_t)( - php_persistent_handle_factory_t *f, void **handle TSRMLS_DC); -/** - * Retire the persistent handle on release. - */ -typedef void (*php_persistent_handle_retire_t)( - php_persistent_handle_factory_t *f, void **handle TSRMLS_DC); - -/** - * Definition of a persistent handle factory. - * - * php_persistent_handle_concede() will return a pointer to a - * php_persistent_handle_factory if a provider for the \a name_str has - * been registered with php_persistent_handle_provide(). - */ -struct php_persistent_handle_factory { - /** The persistent handle provider */ - php_persistent_handle_provider_t *provider; - /** The persistent handle wakeup routine; may be NULL */ - php_persistent_handle_wakeup_t wakeup; - /** The persistent handle retire routine; may be NULL */ - php_persistent_handle_retire_t retire; - - /** The ident for which this factory manages resources */ - struct { - /** ident string */ - char *str; - /** ident length */ - size_t len; - } ident; - - /** Whether it has to be free'd on php_persistent_handle_abandon() */ - unsigned free_on_abandon:1; -}; - -/** - * Register a persistent handle provider in MINIT. - * - * Registers a factory provider for \a name_str with \a fops resource factory - * ops. Call this in your MINIT. - * - * A php_resource_factory will be created with \a fops, \a data and \a dtor - * and will be stored together with a php_persistent_handle_list in the global - * raphf hash. - * - * A php_persistent_handle_factory can then be retrieved by - * php_persistent_handle_concede() at runtime. - * - * @param name_str the provider name, e.g. "http\Client\Curl" - * @param name_len the provider name length, e.g. strlen("http\Client\Curl") - * @param fops the resource factory ops - * @param data opaque user data - * @param dtor \a data destructor - * @return SUCCESS/FAILURE - */ -PHP_RAPHF_API int /* SUCCESS|FAILURE */ php_persistent_handle_provide( - const char *name_str, size_t name_len, php_resource_factory_ops_t *fops, - void *data, void (*dtor)(void *) TSRMLS_DC); - -/** - * Retrieve a persistent handle factory at runtime. - * - * If a persistent handle provider has been registered for \a name_str, a new - * php_persistent_handle_factory creating resources in the \a ident_str - * namespace will be constructed. - * - * The wakeup routine \a wakeup and the retire routine \a retire will be - * assigned to the new php_persistent_handle_factory. - * - * @param a pointer to a factory; allocated on the heap if NULL - * @param name_str the provider name, e.g. "http\Client\Curl" - * @param name_len the provider name length, e.g. strlen("http\Client\Curl") - * @param ident_str the subsidiary namespace, e.g. "php.net:80" - * @param ident_len the subsidiary namespace lenght, e.g. strlen("php.net:80") - * @param wakeup any persistent handle wakeup routine - * @param retire any persistent handle retire routine - * @return \a a or an allocated persistent handle factory - */ -PHP_RAPHF_API php_persistent_handle_factory_t *php_persistent_handle_concede( - php_persistent_handle_factory_t *a, const char *name_str, - size_t name_len, const char *ident_str, size_t ident_len, - php_persistent_handle_wakeup_t wakeup, - php_persistent_handle_retire_t retire TSRMLS_DC); - -/** - * Abandon the persistent handle factory. - * - * Destroy a php_persistent_handle_factory created by - * php_persistent_handle_concede(). If the memory for the factory was allocated, - * it will automatically be free'd. - * - * @param a the persistent handle factory to destroy - */ -PHP_RAPHF_API void php_persistent_handle_abandon( - php_persistent_handle_factory_t *a); - -/** - * Acquire a persistent handle. - * - * That is, either re-use a resource from the free list or create a new handle. - * - * If a handle is acquired from the free list, the - * php_persistent_handle_factory::wakeup callback will be executed for that - * handle. - * - * @param a the persistent handle factory - * @param init_arg the \a init_arg for php_resource_factory_handle_ctor() - * @return the acquired resource - */ -PHP_RAPHF_API void *php_persistent_handle_acquire( - php_persistent_handle_factory_t *a, void *init_arg TSRMLS_DC); - -/** - * Release a persistent handle. - * - * That is, either put it back into the free list for later re-use or clean it - * up with php_resource_factory_handle_dtor(). - * - * If a handle is put back into the free list, the - * php_persistent_handle_factory::retire callback will be executed for that - * handle. - * - * @param a the persistent handle factory - * @param handle the handle to release - */ -PHP_RAPHF_API void php_persistent_handle_release( - php_persistent_handle_factory_t *a, void *handle TSRMLS_DC); - -/** - * Copy a persistent handle. - * - * Let the underlying resource factory copy the \a handle. - * - * @param a the persistent handle factory - * @param handle the resource to accrete - */ -PHP_RAPHF_API void *php_persistent_handle_accrete( - php_persistent_handle_factory_t *a, void *handle TSRMLS_DC); - -/** - * Retrieve persistent handle resource factory ops. - * - * These ops can be used to mask a persistent handle factory as - * resource factory itself, so you can transparently use the - * resource factory API, both for persistent and non-persistent - * ressources. - * - * Example: - * ~~~~~~~~~~~~~~~{.c} - * php_resource_factory_t *create_my_rf(const char *persistent_id_str, - * size_t persistent_id_len TSRMLS_DC) - * { - * php_resource_factory_t *rf; - * - * if (persistent_id_str) { - * php_persistent_handle_factory_t *pf; - * php_resource_factory_ops_t *ops; - * - * ops = php_persistent_handle_get_resource_factory_ops(); - * - * pf = php_persistent_handle_concede(NULL, "my", 2, - * persistent_id_str, persistent_id_len, NULL, NULL TSRMLS_CC); - * - * rf = php_persistent_handle_resource_factory_init(NULL, pf); - * } else { - * rf = php_resource_factory_init(NULL, &myops, NULL, NULL); - * } - * return rf; - * } - * ~~~~~~~~~~~~~~~ - */ -PHP_RAPHF_API php_resource_factory_ops_t * -php_persistent_handle_get_resource_factory_ops(void); - -/** - * Create a resource factory for persistent handles. - * - * This will create a resource factory with persistent handle ops, which wraps - * the provided reource factory \a pf. - * - * @param a the persistent handle resource factory to initialize - * @param pf the resource factory to wrap - */ -PHP_RAPHF_API php_resource_factory_t * -php_persistent_handle_resource_factory_init(php_resource_factory_t *a, - php_persistent_handle_factory_t *pf); - -/** - * Check whether a resource factory is a persistent handle resource factory. - * - * @param a the resource factory to check - */ -PHP_RAPHF_API zend_bool php_resource_factory_is_persistent( - php_resource_factory_t *a); - -/** - * Clean persistent handles up. - * - * Destroy persistent handles of provider \a name_str and in subsidiary - * namespace \a ident_str. - * - * If \a name_str is NULL, all persistent handles of all providers with a - * matching \a ident_str will be cleaned up. - * - * If \a ident_str is NULL all persistent handles of the provider will be - * cleaned up. - * - * Ergo, if both, \a name_str and \a ident_str are NULL, then all - * persistent handles will be cleaned up. - * - * You must call this in MSHUTDOWN, if your resource factory ops hold a - * registered php_resource_factory::dtor, else the dtor will point to - * memory not any more available if the extension has already been unloaded. - * - * @param name_str the provider name; may be NULL - * @param name_len the provider name length - * @param ident_str the subsidiary namespace name; may be NULL - * @param ident_len the subsidiary namespace name length - */ -PHP_RAPHF_API void php_persistent_handle_cleanup(const char *name_str, - size_t name_len, const char *ident_str, size_t ident_len TSRMLS_DC); - -/** - * Retrieve statistics about the current process/thread's persistent handles. - * - * @return a HashTable like: - * ~~~~~~~~~~~~~~~ - * [ - * "name" => [ - * "ident" => [ - * "used" => 1, - * "free" => 0, - * ] - * ] - * ] - * ~~~~~~~~~~~~~~~ - */ -PHP_RAPHF_API HashTable *php_persistent_handle_statall(HashTable *ht TSRMLS_DC); - -#endif /* PHP_RAPHF_API_H */ - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ -/* - +--------------------------------------------------------------------+ - | PECL :: raphf | - +--------------------------------------------------------------------+ - | Redistribution and use in source and binary forms, with or without | - | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met. | - +--------------------------------------------------------------------+ - | Copyright (c) 2013, Michael Wallner | - +--------------------------------------------------------------------+ -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "php_raphf.h" - -struct php_persistent_handle_globals { - ulong limit; - HashTable hash; -}; - -ZEND_BEGIN_MODULE_GLOBALS(raphf) - struct php_persistent_handle_globals persistent_handle; -ZEND_END_MODULE_GLOBALS(raphf) - -#ifdef ZTS -# define PHP_RAPHF_G ((zend_raphf_globals *) \ - (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(raphf_globals_id)]) -#else -# define PHP_RAPHF_G (&raphf_globals) -#endif - -ZEND_DECLARE_MODULE_GLOBALS(raphf) - -#if PHP_VERSION_ID < 50500 -#undef SUCCESS -#undef FAILURE -typedef enum { - SUCCESS = 0, - FAILURE = -1 -} ZEND_RESULT_CODE; -#endif - -#ifndef PHP_RAPHF_DEBUG_PHANDLES -# define PHP_RAPHF_DEBUG_PHANDLES 0 -#endif -#if PHP_RAPHF_DEBUG_PHANDLES -# undef inline -# define inline -#endif - -php_resource_factory_t *php_resource_factory_init(php_resource_factory_t *f, - php_resource_factory_ops_t *fops, void *data, void (*dtor)(void *data)) -{ - if (!f) { - f = emalloc(sizeof(*f)); - } - memset(f, 0, sizeof(*f)); - - memcpy(&f->fops, fops, sizeof(*fops)); - - f->data = data; - f->dtor = dtor; - - f->refcount = 1; - - return f; -} - -unsigned php_resource_factory_addref(php_resource_factory_t *rf) -{ - return ++rf->refcount; -} - -void php_resource_factory_dtor(php_resource_factory_t *f) -{ - --f->refcount; - - if (!f->refcount) { - if (f->dtor) { - f->dtor(f->data); - } - } -} - -void php_resource_factory_free(php_resource_factory_t **f) -{ - if (*f) { - php_resource_factory_dtor(*f); - if (!(*f)->refcount) { - efree(*f); - *f = NULL; - } - } -} - -void *php_resource_factory_handle_ctor(php_resource_factory_t *f, - void *init_arg TSRMLS_DC) -{ - if (f->fops.ctor) { - return f->fops.ctor(f->data, init_arg TSRMLS_CC); - } - return NULL; -} - -void *php_resource_factory_handle_copy(php_resource_factory_t *f, - void *handle TSRMLS_DC) -{ - if (f->fops.copy) { - return f->fops.copy(f->data, handle TSRMLS_CC); - } - return NULL; -} - -void php_resource_factory_handle_dtor(php_resource_factory_t *f, - void *handle TSRMLS_DC) -{ - if (f->fops.dtor) { - f->fops.dtor(f->data, handle TSRMLS_CC); - } -} - -php_resource_factory_t *php_persistent_handle_resource_factory_init( - php_resource_factory_t *a, php_persistent_handle_factory_t *pf) -{ - return php_resource_factory_init(a, - php_persistent_handle_get_resource_factory_ops(), pf, - (void(*)(void*)) php_persistent_handle_abandon); -} - -zend_bool php_resource_factory_is_persistent(php_resource_factory_t *a) -{ - return a->dtor == (void(*)(void *)) php_persistent_handle_abandon; -} - - -static inline php_persistent_handle_list_t *php_persistent_handle_list_init( - php_persistent_handle_list_t *list) -{ - int free_list; - - if ((free_list = !list)) { - list = pemalloc(sizeof(php_persistent_handle_list_t), 1); - } - - list->used = 0; - - if (SUCCESS != zend_hash_init(&list->free, 0, NULL, NULL, 1)) { - if (free_list) { - pefree(list, 1); - } - list = NULL; - } - - return list; -} - -static int php_persistent_handle_apply_stat(void *p TSRMLS_DC, int argc, - va_list argv, zend_hash_key *key) -{ - php_persistent_handle_list_t **list = p; - zval *zsubentry, *zentry = va_arg(argv, zval *); - - MAKE_STD_ZVAL(zsubentry); - array_init(zsubentry); - add_assoc_long_ex(zsubentry, ZEND_STRS("used"), (*list)->used); - add_assoc_long_ex(zsubentry, ZEND_STRS("free"), - zend_hash_num_elements(&(*list)->free)); - add_assoc_zval_ex(zentry, key->arKey, key->nKeyLength, zsubentry); - - return ZEND_HASH_APPLY_KEEP; -} - -static int php_persistent_handle_apply_statall(void *p TSRMLS_DC, int argc, - va_list argv, zend_hash_key *key) -{ - php_persistent_handle_provider_t *provider = p; - HashTable *ht = va_arg(argv, HashTable *); - zval *zentry; - - MAKE_STD_ZVAL(zentry); - array_init(zentry); - - zend_hash_apply_with_arguments(&provider->list.free TSRMLS_CC, - php_persistent_handle_apply_stat, 1, zentry); - zend_symtable_update(ht, key->arKey, key->nKeyLength, &zentry, - sizeof(zval *), NULL); - - return ZEND_HASH_APPLY_KEEP; -} - -static int php_persistent_handle_apply_cleanup_ex(void *pp, void *arg TSRMLS_DC) -{ - php_resource_factory_t *rf = arg; - void **handle = pp; - -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "DESTROY: %p\n", *handle); -#endif - php_resource_factory_handle_dtor(rf, *handle TSRMLS_CC); - return ZEND_HASH_APPLY_REMOVE; -} - -static int php_persistent_handle_apply_cleanup(void *pp, void *arg TSRMLS_DC) -{ - php_resource_factory_t *rf = arg; - php_persistent_handle_list_t **listp = pp; - - zend_hash_apply_with_argument(&(*listp)->free, - php_persistent_handle_apply_cleanup_ex, rf TSRMLS_CC); - if ((*listp)->used) { - return ZEND_HASH_APPLY_KEEP; - } - zend_hash_destroy(&(*listp)->free); -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "LSTFREE: %p\n", *listp); -#endif - pefree(*listp, 1); - *listp = NULL; - return ZEND_HASH_APPLY_REMOVE; -} - -static inline void php_persistent_handle_list_dtor( - php_persistent_handle_list_t *list, - php_persistent_handle_provider_t *provider TSRMLS_DC) -{ -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "LSTDTOR: %p\n", list); -#endif - zend_hash_apply_with_argument(&list->free, - php_persistent_handle_apply_cleanup_ex, &provider->rf TSRMLS_CC); - zend_hash_destroy(&list->free); -} - -static inline void php_persistent_handle_list_free( - php_persistent_handle_list_t **list, - php_persistent_handle_provider_t *provider TSRMLS_DC) -{ - php_persistent_handle_list_dtor(*list, provider TSRMLS_CC); -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "LSTFREE: %p\n", *list); -#endif - pefree(*list, 1); - *list = NULL; -} - -static int php_persistent_handle_list_apply_dtor(void *listp, - void *provider TSRMLS_DC) -{ - php_persistent_handle_list_free(listp, provider TSRMLS_CC); - return ZEND_HASH_APPLY_REMOVE; -} - -static inline php_persistent_handle_list_t *php_persistent_handle_list_find( - php_persistent_handle_provider_t *provider, const char *ident_str, - size_t ident_len TSRMLS_DC) -{ - php_persistent_handle_list_t **list, *new_list; - ZEND_RESULT_CODE rv = zend_symtable_find(&provider->list.free, ident_str, - ident_len + 1, (void *) &list); - - if (SUCCESS == rv) { -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "LSTFIND: %p\n", *list); -#endif - return *list; - } - - if ((new_list = php_persistent_handle_list_init(NULL))) { - rv = zend_symtable_update(&provider->list.free, ident_str, ident_len+1, - (void *) &new_list, sizeof(php_persistent_handle_list_t *), - (void *) &list); - if (SUCCESS == rv) { -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "LSTFIND: %p (new)\n", *list); -#endif - return *list; - } - php_persistent_handle_list_free(&new_list, provider TSRMLS_CC); - } - - return NULL; -} - -static int php_persistent_handle_apply_cleanup_all(void *p TSRMLS_DC, int argc, - va_list argv, zend_hash_key *key) -{ - php_persistent_handle_provider_t *provider = p; - const char *ident_str = va_arg(argv, const char *); - size_t ident_len = va_arg(argv, size_t); - php_persistent_handle_list_t *list; - - if (ident_str && ident_len) { - if ((list = php_persistent_handle_list_find(provider, ident_str, - ident_len TSRMLS_CC))) { - zend_hash_apply_with_argument(&list->free, - php_persistent_handle_apply_cleanup_ex, - &provider->rf TSRMLS_CC); - } - } else { - zend_hash_apply_with_argument(&provider->list.free, - php_persistent_handle_apply_cleanup, &provider->rf TSRMLS_CC); - } - - return ZEND_HASH_APPLY_KEEP; -} - -static void php_persistent_handle_hash_dtor(void *p) -{ - php_persistent_handle_provider_t *provider; - TSRMLS_FETCH(); - - provider = (php_persistent_handle_provider_t *) p; - zend_hash_apply_with_argument(&provider->list.free, - php_persistent_handle_list_apply_dtor, provider TSRMLS_CC); - zend_hash_destroy(&provider->list.free); - php_resource_factory_dtor(&provider->rf); -} - -PHP_RAPHF_API ZEND_RESULT_CODE php_persistent_handle_provide(const char *name_str, - size_t name_len, php_resource_factory_ops_t *fops, void *data, - void (*dtor)(void *) TSRMLS_DC) -{ - ZEND_RESULT_CODE status = FAILURE; - php_persistent_handle_provider_t provider; - - if (php_persistent_handle_list_init(&provider.list)) { - if (php_resource_factory_init(&provider.rf, fops, data, dtor)) { -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "PROVIDE: %p %s\n", PHP_RAPHF_G, name_str); -#endif - - status = zend_symtable_update(&PHP_RAPHF_G->persistent_handle.hash, - name_str, name_len+1, (void *) &provider, - sizeof(php_persistent_handle_provider_t), NULL); - if (SUCCESS != status) { - php_resource_factory_dtor(&provider.rf); - } - } - } - - return status; -} - -php_persistent_handle_factory_t *php_persistent_handle_concede( - php_persistent_handle_factory_t *a, const char *name_str, - size_t name_len, const char *ident_str, size_t ident_len, - php_persistent_handle_wakeup_t wakeup, - php_persistent_handle_retire_t retire TSRMLS_DC) -{ - ZEND_RESULT_CODE status = FAILURE; - php_persistent_handle_factory_t *free_a = NULL; - - if (!a) { - free_a = a = emalloc(sizeof(*a)); - } - memset(a, 0, sizeof(*a)); - - status = zend_symtable_find(&PHP_RAPHF_G->persistent_handle.hash, name_str, - name_len+1, (void *) &a->provider); - - if (SUCCESS == status) { - a->ident.str = estrndup(ident_str, ident_len); - a->ident.len = ident_len; - - a->wakeup = wakeup; - a->retire = retire; - - if (free_a) { - a->free_on_abandon = 1; - } - } else { - if (free_a) { - efree(free_a); - } - a = NULL; - } - -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "CONCEDE: %p %p (%s) (%s)\n", PHP_RAPHF_G, - a ? a->provider : NULL, name_str, ident_str); -#endif - - return a; -} - -PHP_RAPHF_API void php_persistent_handle_abandon( - php_persistent_handle_factory_t *a) -{ - zend_bool f = a->free_on_abandon; - -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "ABANDON: %p\n", a->provider); -#endif - - STR_FREE(a->ident.str); - memset(a, 0, sizeof(*a)); - if (f) { - efree(a); - } -} - -void *php_persistent_handle_acquire( - php_persistent_handle_factory_t *a, void *init_arg TSRMLS_DC) -{ - int key; - ZEND_RESULT_CODE rv; - ulong index; - void **handle_ptr, *handle = NULL; - php_persistent_handle_list_t *list; - - list = php_persistent_handle_list_find(a->provider, a->ident.str, - a->ident.len TSRMLS_CC); - if (list) { - zend_hash_internal_pointer_end(&list->free); - key = zend_hash_get_current_key(&list->free, NULL, &index, 0); - rv = zend_hash_get_current_data(&list->free, (void *) &handle_ptr); - if (HASH_KEY_NON_EXISTANT != key && SUCCESS == rv) { - handle = *handle_ptr; - if (a->wakeup) { - a->wakeup(a, &handle TSRMLS_CC); - } - zend_hash_index_del(&list->free, index); - } else { - handle = php_resource_factory_handle_ctor(&a->provider->rf, - init_arg TSRMLS_CC); - } -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "CREATED: %p\n", *handle); -#endif - if (handle) { - ++a->provider->list.used; - ++list->used; - } - } - - return handle; -} - -void *php_persistent_handle_accrete( - php_persistent_handle_factory_t *a, void *handle TSRMLS_DC) -{ - void *new_handle = NULL; - php_persistent_handle_list_t *list; - - new_handle = php_resource_factory_handle_copy(&a->provider->rf, - handle TSRMLS_CC); - if (handle) { - list = php_persistent_handle_list_find(a->provider, a->ident.str, - a->ident.len TSRMLS_CC); - if (list) { - ++list->used; - } - ++a->provider->list.used; - } - - return new_handle; -} - -void php_persistent_handle_release( - php_persistent_handle_factory_t *a, void *handle TSRMLS_DC) -{ - php_persistent_handle_list_t *list; - - list = php_persistent_handle_list_find(a->provider, a->ident.str, - a->ident.len TSRMLS_CC); - if (list) { - if (a->provider->list.used >= PHP_RAPHF_G->persistent_handle.limit) { -#if PHP_RAPHF_DEBUG_PHANDLES - fprintf(stderr, "DESTROY: %p\n", *handle); -#endif - php_resource_factory_handle_dtor(&a->provider->rf, - handle TSRMLS_CC); - } else { - if (a->retire) { - a->retire(a, &handle TSRMLS_CC); - } - zend_hash_next_index_insert(&list->free, (void *) &handle, - sizeof(void *), NULL); - } - - --a->provider->list.used; - --list->used; - } -} - -void php_persistent_handle_cleanup(const char *name_str, size_t name_len, - const char *ident_str, size_t ident_len TSRMLS_DC) -{ - php_persistent_handle_provider_t *provider; - php_persistent_handle_list_t *list; - ZEND_RESULT_CODE rv; - - if (name_str && name_len) { - rv = zend_symtable_find(&PHP_RAPHF_G->persistent_handle.hash, name_str, - name_len+1, (void *) &provider); - - if (SUCCESS == rv) { - if (ident_str && ident_len) { - list = php_persistent_handle_list_find(provider, ident_str, - ident_len TSRMLS_CC); - if (list) { - zend_hash_apply_with_argument(&list->free, - php_persistent_handle_apply_cleanup_ex, - &provider->rf TSRMLS_CC); - } - } else { - zend_hash_apply_with_argument(&provider->list.free, - php_persistent_handle_apply_cleanup, - &provider->rf TSRMLS_CC); - } - } - } else { - zend_hash_apply_with_arguments( - &PHP_RAPHF_G->persistent_handle.hash TSRMLS_CC, - php_persistent_handle_apply_cleanup_all, 2, ident_str, - ident_len); - } -} - -HashTable *php_persistent_handle_statall(HashTable *ht TSRMLS_DC) -{ - if (zend_hash_num_elements(&PHP_RAPHF_G->persistent_handle.hash)) { - if (!ht) { - ALLOC_HASHTABLE(ht); - zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0); - } - zend_hash_apply_with_arguments( - &PHP_RAPHF_G->persistent_handle.hash TSRMLS_CC, - php_persistent_handle_apply_statall, 1, ht); - } else if (ht) { - ht = NULL; - } - - return ht; -} - -static php_resource_factory_ops_t php_persistent_handle_resource_factory_ops = { - (php_resource_factory_handle_ctor_t) php_persistent_handle_acquire, - (php_resource_factory_handle_copy_t) php_persistent_handle_accrete, - (php_resource_factory_handle_dtor_t) php_persistent_handle_release -}; - -php_resource_factory_ops_t *php_persistent_handle_get_resource_factory_ops(void) -{ - return &php_persistent_handle_resource_factory_ops; -} - -ZEND_BEGIN_ARG_INFO_EX(ai_raphf_stat_persistent_handles, 0, 0, 0) -ZEND_END_ARG_INFO(); -static PHP_FUNCTION(raphf_stat_persistent_handles) -{ - if (SUCCESS == zend_parse_parameters_none()) { - object_init(return_value); - if (php_persistent_handle_statall(HASH_OF(return_value) TSRMLS_CC)) { - return; - } - zval_dtor(return_value); - } - RETURN_FALSE; -} - -ZEND_BEGIN_ARG_INFO_EX(ai_raphf_clean_persistent_handles, 0, 0, 0) - ZEND_ARG_INFO(0, name) - ZEND_ARG_INFO(0, ident) -ZEND_END_ARG_INFO(); -static PHP_FUNCTION(raphf_clean_persistent_handles) -{ - char *name_str = NULL, *ident_str = NULL; - int name_len = 0, ident_len = 0; - - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!", - &name_str, &name_len, &ident_str, &ident_len)) { - php_persistent_handle_cleanup(name_str, name_len, ident_str, - ident_len TSRMLS_CC); - } -} - -static const zend_function_entry raphf_functions[] = { - ZEND_NS_FENTRY("raphf", stat_persistent_handles, - ZEND_FN(raphf_stat_persistent_handles), - ai_raphf_stat_persistent_handles, 0) - ZEND_NS_FENTRY("raphf", clean_persistent_handles, - ZEND_FN(raphf_clean_persistent_handles), - ai_raphf_clean_persistent_handles, 0) - {0} -}; - -PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("raphf.persistent_handle.limit", "-1", PHP_INI_SYSTEM, - OnUpdateLong, persistent_handle.limit, zend_raphf_globals, - raphf_globals) -PHP_INI_END() - -static HashTable *php_persistent_handles_global_hash; - -static PHP_GINIT_FUNCTION(raphf) -{ - raphf_globals->persistent_handle.limit = -1; - - zend_hash_init(&raphf_globals->persistent_handle.hash, 0, NULL, - php_persistent_handle_hash_dtor, 1); - if (php_persistent_handles_global_hash) { - zend_hash_copy(&raphf_globals->persistent_handle.hash, - php_persistent_handles_global_hash, NULL, NULL, - sizeof(php_persistent_handle_provider_t)); - } -} - -static PHP_GSHUTDOWN_FUNCTION(raphf) -{ - zend_hash_destroy(&raphf_globals->persistent_handle.hash); -} - -PHP_MINIT_FUNCTION(raphf) -{ - php_persistent_handles_global_hash = &PHP_RAPHF_G->persistent_handle.hash; - REGISTER_INI_ENTRIES(); - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(raphf) -{ - UNREGISTER_INI_ENTRIES(); - php_persistent_handles_global_hash = NULL; - return SUCCESS; -} - -static int php_persistent_handle_apply_info_ex(void *p TSRMLS_DC, int argc, - va_list argv, zend_hash_key *key) -{ - php_persistent_handle_list_t **list = p; - zend_hash_key *super_key = va_arg(argv, zend_hash_key *); - char used[21], free[21]; - - slprintf(used, sizeof(used), "%u", (*list)->used); - slprintf(free, sizeof(free), "%d", zend_hash_num_elements(&(*list)->free)); - - php_info_print_table_row(4, super_key->arKey, key->arKey, used, free); - - return ZEND_HASH_APPLY_KEEP; -} - -static int php_persistent_handle_apply_info(void *p TSRMLS_DC, int argc, - va_list argv, zend_hash_key *key) -{ - php_persistent_handle_provider_t *provider = p; - - zend_hash_apply_with_arguments(&provider->list.free TSRMLS_CC, - php_persistent_handle_apply_info_ex, 1, key); - - return ZEND_HASH_APPLY_KEEP; -} - -PHP_MINFO_FUNCTION(raphf) -{ - php_info_print_table_start(); - php_info_print_table_header(2, - "Resource and persistent handle factory support", "enabled"); - php_info_print_table_row(2, "Extension version", PHP_RAPHF_VERSION); - php_info_print_table_end(); - - php_info_print_table_start(); - php_info_print_table_colspan_header(4, "Persistent handles in this " -#ifdef ZTS - "thread" -#else - "process" -#endif - ); - php_info_print_table_header(4, "Provider", "Ident", "Used", "Free"); - zend_hash_apply_with_arguments( - &PHP_RAPHF_G->persistent_handle.hash TSRMLS_CC, - php_persistent_handle_apply_info, 0); - php_info_print_table_end(); - - DISPLAY_INI_ENTRIES(); -} - -zend_module_entry raphf_module_entry = { - STANDARD_MODULE_HEADER, - "raphf", - raphf_functions, - PHP_MINIT(raphf), - PHP_MSHUTDOWN(raphf), - NULL, - NULL, - PHP_MINFO(raphf), - PHP_RAPHF_VERSION, - ZEND_MODULE_GLOBALS(raphf), - PHP_GINIT(raphf), - PHP_GSHUTDOWN(raphf), - NULL, - STANDARD_MODULE_PROPERTIES_EX -}; -/* }}} */ - -#ifdef COMPILE_DL_RAPHF -ZEND_GET_MODULE(raphf) -#endif - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ ---TEST-- -pecl/http-v2 - general and stat ---SKIPIF-- - ---FILE-- -enqueue(new http\Client\Request("GET", "http://php.net")); -} while (count($c) < 3); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -unset($c); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -?> -Done ---EXPECTF-- -Test -array(2) { - ["http\Client\Curl"]=> - array(0) { - } - ["http\Client\Curl\Request"]=> - array(0) { - } -} -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(1) - ["free"]=> - int(0) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(3) - ["free"]=> - int(0) - } - } -} -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(1) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(3) - } - } -} -Done ---TEST-- -pecl/http-v2 - clean with name and id ---SKIPIF-- - ---FILE-- -enqueue(new http\Client\Request("GET", "http://php.net")); -} while (count($c) < 3); - -unset($c); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - - -raphf\clean_persistent_handles("http\\Client\\Curl"); -raphf\clean_persistent_handles("http\\Client\\Curl\\Request", "php.net:80"); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -?> -Done ---EXPECTF-- -Test -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(1) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(3) - } - } -} -array(2) { - ["http\Client\Curl"]=> - array(0) { - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(0) - } - } -} -Done ---TEST-- -pecl/http-v2 - clean with id only ---SKIPIF-- - ---FILE-- -enqueue(new http\Client\Request("GET", "http://php.net")); -} while (count($c) < 3); - -unset($c); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -raphf\clean_persistent_handles(null, "php.net:80"); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -?> -Done ---EXPECTF-- -Test -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(1) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(3) - } - } -} -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(0) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(0) - ["free"]=> - int(0) - } - } -} -Done ---TEST-- -pecl/http-v2 - partial clean ---SKIPIF-- - ---FILE-- -enqueue(new http\Client\Request("GET", "http://php.net")); - $c2->enqueue(new http\Client\Request("GET", "http://php.net")); -} while (count($c) < 3); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -unset($c); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -raphf\clean_persistent_handles(); - -$h = (array) raphf\stat_persistent_handles(); -var_dump(array_intersect_key($h, array_flip(preg_grep("/^http/", array_keys($h))))); - -?> -Done ---EXPECTF-- -Test -array(2) { - ["http\Client\Curl"]=> - array(0) { - } - ["http\Client\Curl\Request"]=> - array(0) { - } -} -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(2) - ["free"]=> - int(0) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(6) - ["free"]=> - int(0) - } - } -} -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(1) - ["free"]=> - int(1) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(3) - ["free"]=> - int(3) - } - } -} -array(2) { - ["http\Client\Curl"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(1) - ["free"]=> - int(0) - } - } - ["http\Client\Curl\Request"]=> - array(1) { - ["php.net:80"]=> - array(2) { - ["used"]=> - int(3) - ["free"]=> - int(0) - } - } -} -Done -©œÝÆ¿¢è‰õp¡4ºÈ0¸.|—¯GBMB \ No newline at end of file