From 1409885bcef1c517fc0bd23adb6a108aecb98afe Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 15 May 2015 09:48:31 +0200 Subject: [PATCH 01/16] use additional file_exists checks --- bin/pharext | Bin 70972 -> 71043 bytes src/pharext/Task/Cleanup.php | 2 +- src/pharext/Tempfile.php | 4 +++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/pharext b/bin/pharext index a6b0d4a7fe78400f52ea1eda2a0370b7d3fcf78c..1d9f2b0f94a8618855746a559250b7241dac11ed 100755 GIT binary patch delta 463 zcmdn9iluoq%Z3dKOly`*-lSjwqTVRzf+%T4JrL!ss1KrQ6iqF245oaQO?W_x-?B3>EOvQ1 zZ?d7f@Z<%`LLenul+8iZTV=2fN-AJ$BUB7Qg54@+AnLFR*b%=}^aSLf)`IAho()cu zb5$jU+%rp@bMo_2^$Icya+yKynw+c(Hf{!lI;#q?e-2Pr>d%r{lP{==2s!6u>N^&t z7lU+tkOb>8Rs&m`rlt#at{_nPvyzk;uyZ%5ft`CyO%E)mqQt;(;o&4#u$-_uSWaCX z9CQ)tpn%-mp>F8IotdVfky#v{mYI_}`9QH4tENIV7w6>d#Y#+^wVSUO|1*&WsQ^jG zr&eSZmlSKLlw@QU>)I9NYHDu2y23k0#%qdnt6EJ}z}&CVo(s4)8GQ}eaE%EV=F245oaQO?W_x-?B3>EOvQ1 zZ?d7f@Z<%`LLenul+8iZTV=2fN-AJ$BUB7Qg54@+AnLFR*b%=}^aPk$Al8Ct=82wO zlXF!ih1@esoOAN?QuPWl3Ua~jnw+c(Hf{!lI;#q?e-2Pr>d%r{lP{==2s!6u>N^&t z7lU+tkOUb!*;oy1ZJL@c*tvp0<FT)}d}>R>r_ zb#Tx{sDlD>bBDU2&*X>23Y%F={+Mi*S?Qf46ZUrm); - } else { + } elseif (file_exists($this->rm)) { @unlink($this->rm); } } diff --git a/src/pharext/Tempfile.php b/src/pharext/Tempfile.php index e720551..2ec6836 100644 --- a/src/pharext/Tempfile.php +++ b/src/pharext/Tempfile.php @@ -37,7 +37,9 @@ class Tempfile extends \SplFileInfo * Unlink the file */ public function __destruct() { - @unlink($this->getPathname()); + if (is_file($this->getPathname())) { + @unlink($this->getPathname()); + } } /** -- 2.30.2 From c61404bba9e446429740a134deb5cf8f29f1e0f3 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 15 May 2015 10:18:01 +0200 Subject: [PATCH 02/16] use a Metadata class --- Makefile | 4 ++-- bin/pharext | Bin 71043 -> 71607 bytes build/Metadata.php.in | 26 ++++++++++++++++++++++++++ build/Version.php.in | 5 ----- build/create-phar.php | 5 +---- src/pharext/Metadata.php | 26 ++++++++++++++++++++++++++ src/pharext/Packager.php | 11 ++++++++--- src/pharext/Version.php | 5 ----- 8 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 build/Metadata.php.in delete mode 100644 build/Version.php.in create mode 100644 src/pharext/Metadata.php delete mode 100644 src/pharext/Version.php diff --git a/Makefile b/Makefile index 4c78e66..41b8041 100644 --- a/Makefile +++ b/Makefile @@ -21,11 +21,11 @@ release: @echo "Previous Version: $$(git tag --list | tail -n1)"; \ read -p "Release Version: v" VERSION; \ echo "Preparing release ... "; \ - sed -e "s/@PHAREXT_VERSION@/$$VERSION/" build/Version.php.in > src/pharext/Version.php && \ + sed -e "s/@dev-master/$$VERSION/" build/Metadata.php.in > src/pharext/Metadata.php && \ $(MAKE) -B SIGN=1 && \ git ci -am "release v$$VERSION" && \ git tag v$$VERSION && \ - cp build/Version.php.in src/pharext/Version.php && \ + cp build/Metadata.php.in src/pharext/Metadata.php && \ git ci -am "back to dev" .PHONY: all clean test release diff --git a/bin/pharext b/bin/pharext index 1d9f2b0f94a8618855746a559250b7241dac11ed..bd2b67f161c939c4a1e80babffb8537677b4650d 100755 GIT binary patch delta 1070 zcmZ`&OKTHR6rPl{I?+;_7Bp!aZf+)-NoW#cUoxeowpI-_5iG4Ot;m?UNd_mAbY@zW zT8g+4Tojo_eIvM%E?Qb8KR|FNxOAmhXhE>(QeAoPoy4Ysi{WF=`OZ1tdEC2e&hol* zBk9e|H8KpxFibQ49Qb3HNCU%2Vz0PphqfgywCL#c+1hUzd4#L7NpFK4G(R2AG9kxbutY4Wj?k(gj(GrsuDk~=M2*14-aj! zD?}4#Ls2TI8Pj)7d6o*=3{gSvLXl&Spgl5z{ZlK)slSD%ex9cznc`{N_xRXq(e0>D zRwwRSbg_mhnMwv^=e3N9*9_E%^+0$0x7$sfN%&f3~ z0YL*Vo?Gq&22!)4_&0O7e?LQQX?z6eVBK7S+Te7w5S8Ko;v`i)7&e2Iv(>{LhhSjv zUkRO*QMufGzikl0wwu(h3AW`C*A;6+gj;X;^Isa3ED!`Prxve)0kB$T9dS1u9LsX5 zl0lk*i2WJs@HS9Z*qZBVS?0{VVnhdTNV+D#k>b261FdL+tfI+40vD1aqv`R{SOgnX z~(NxClGx>`Vb4hhvwiy|FTC!nKQJK p4_C95cUi}sBke04pDxY#oZque%yn;f@ME&v1nTf}J2#vf{sURWL#hA( delta 560 zcmdnKo~3y;%LY#=4_{se24w~Y20L@P6^>S7?Fl#!a4l3Ju>4dfVF zDHUWS7Nu5{D3mz_csK^RMufzNxdsJ$`ujOdUL&QhY;L7gmReMtnV$#JU}DS6TGq)s6{MNgESY>w!2(1HDC&YJdqq7Em9MA|q82Ec@T^%98p0#UXQs!-Vk#9OWmw(N$oIfy5yVhp0(RKRjIDuy85dKEJe^<2diM9HZdfvuHe zVPH7v+2AyJqN?QNQdI$vT)Qe*`yL4OQ59^8x*FIm;c8&Ry41j4-Khq)_LZ8JfQk|W z1IV8s`ohCWu9G(^i%hmq7X%sTtqxXJqYgG=jk@0EQcd@V(Yo`EWXedSM=IW*>Y3fYh!Oa-O=rEm&n^9`|NiIhH o?NU69jodO`Q>0tfYN`U}evS5Az`e=nYsiLcOu+Qu?&RwP06t8*LI3~& diff --git a/build/Metadata.php.in b/build/Metadata.php.in new file mode 100644 index 0000000..db3ab81 --- /dev/null +++ b/build/Metadata.php.in @@ -0,0 +1,26 @@ +", self::version()); + } + + static function date() { + return gmdate("Y-m-d"); + } + + static function all() { + return [ + "version" => self::version(), + "header" => self::header(), + "date" => self::date(), + ]; + } +} diff --git a/build/Version.php.in b/build/Version.php.in deleted file mode 100644 index 50a2875..0000000 --- a/build/Version.php.in +++ /dev/null @@ -1,5 +0,0 @@ - sprintf("pharext v%s (c) Michael Wallner ", pharext\VERSION), - "version" => pharext\VERSION, +$file = (new pharext\Task\PharBuild(null, pharext\Metadata::all() + [ "name" => "pharext", - "date" => date("Y-m-d"), "stub" => "pharext_packager.php", "license" => file_get_contents(__DIR__."/../LICENSE") ], false))->run(); diff --git a/src/pharext/Metadata.php b/src/pharext/Metadata.php new file mode 100644 index 0000000..db3ab81 --- /dev/null +++ b/src/pharext/Metadata.php @@ -0,0 +1,26 @@ +", self::version()); + } + + static function date() { + return gmdate("Y-m-d"); + } + + static function all() { + return [ + "version" => self::version(), + "header" => self::header(), + "date" => self::date(), + ]; + } +} diff --git a/src/pharext/Packager.php b/src/pharext/Packager.php index c08fce0..cd3b4d6 100644 --- a/src/pharext/Packager.php +++ b/src/pharext/Packager.php @@ -243,11 +243,16 @@ class Packager implements Command */ private function createPackage() { try { - $meta = array_merge($this->metadata(), [ - "date" => date("Y-m-d"), + if (($glob = glob($this->source->getBaseDir()."/LICENSE*"))) { + $license = file_get_contents(current($glob)); + } else { + $this->warn("Could not find any LICENSE.* files!\n"); + $license = "UNKNOWN\n"; + } + $meta = array_merge(Metadata::all(), [ "name" => $this->args->name, "release" => $this->args->release, - "license" => @file_get_contents(current(glob($this->source->getBaseDir()."/LICENSE*"))), + "license" => $license, "stub" => "pharext_installer.php", "type" => $this->args->zend ? "zend_extension" : "extension", ]); diff --git a/src/pharext/Version.php b/src/pharext/Version.php deleted file mode 100644 index 50a2875..0000000 --- a/src/pharext/Version.php +++ /dev/null @@ -1,5 +0,0 @@ - Date: Fri, 15 May 2015 10:27:17 +0200 Subject: [PATCH 03/16] fix build --- bin/pharext | Bin 71607 -> 71501 bytes build/create-phar.php | 2 -- 2 files changed, 2 deletions(-) diff --git a/bin/pharext b/bin/pharext index bd2b67f161c939c4a1e80babffb8537677b4650d..e9c765d71c5d00aa95454691248432fc1c20a00d 100755 GIT binary patch delta 407 zcmdnKp5^R1mJOa#tWLZP49c7Rq{7*Fgw}?J&Sqp_kcoUGJNbcv9+S}8$pVVHAj)15 z%*$8Q2k{mtnt&Da2{16Mm*JZ>`J;-+WNjs`$^R62LGrvx#$fqIRtAQo*-w)vZ&VPO zoS?)Hk}FgKo3v0#3&cCCWCfx)m5o4@ErcpmHUaULD}yb&p==J~391-_C^r?bT#bq$ zh__zF3`9LwF$Ga_szzXIiGcwWC?I-~x{>PSjmjdEEz|`;270T5mDQ+&jM%(J{V3z+ zjhZVT3guNQ_;@wRTc!v zRVagvUa4#jR#L>mz#yR@`)IPRs^nx=6#Lj!=lx|j_*xh2w$zRn}LH5b0gO&KIgS2n1RX@t8Zq3D&oS#=*q7dd96zu8mr(mm~6g716fMW{ ZK8>FtTgpWBhUa#E1z>0~xI6he0RXXqkjDT3 diff --git a/build/create-phar.php b/build/create-phar.php index 409bf8e..d2804a8 100644 --- a/build/create-phar.php +++ b/build/create-phar.php @@ -9,8 +9,6 @@ spl_autoload_register(function($c) { return include strtr($c, "\\_", "//") . ".php"; }); -require_once __DIR__."/../src/pharext/Version.php"; - $file = (new pharext\Task\PharBuild(null, pharext\Metadata::all() + [ "name" => "pharext", "stub" => "pharext_packager.php", -- 2.30.2 From e44f0adc7b18845a2cd3dc63fdab5d9bcdc10f76 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 15 May 2015 12:52:54 +0200 Subject: [PATCH 04/16] license helper --- bin/pharext | Bin 71501 -> 73515 bytes src/pharext/License.php | 51 ++++++++++++++++++++++++++++++++ src/pharext/Packager.php | 8 +---- src/pharext/SourceDir.php | 6 ++++ src/pharext/SourceDir/Basic.php | 10 +++++++ src/pharext/SourceDir/Git.php | 15 +++++++++- src/pharext/SourceDir/Pecl.php | 23 +++++++++++++- 7 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 src/pharext/License.php diff --git a/bin/pharext b/bin/pharext index e9c765d71c5d00aa95454691248432fc1c20a00d..8f90155d7cc18f523256040d4e7df0eba2315e07 100755 GIT binary patch delta 2387 zcmb7Gdu&rx7;l$t>~;bjlgE&m)3e*{cHDNnL}U!4vyKMn2xEYZrIzk=y;*zP-Fq7r znp%yTh*6_CfAEJ<|ML-u0UJf5l4zm{COR=u6MQ6MOh`<8B_t62!|yxy-aU9kY0`f8 zJig!e`+n#9&h6)K)}K6Ae>%RhVRE6zBi9lu4>Z5Id>opvBflnP9P zcH`(}x*5$yx(>~vj&*k+`mc51bNR)uc|dOCtfK|jraA-X9a1$#KXZh z-XQyN%W`=Gn%(kRG>^&~(Y!0)gXVWxMCb^v$I(ICJR4juz`k$xc;bB33K8#@pon)h zD0nKJ0&JvH2=a92YX65o4oRY2f3{;W|D=;_`zBydqCNH2#trXyJ>t^}zr}3IU{hAl zE-lS;lSPWzA_w+}f%dohzheAKXApU<>Jmxr?!wr$N>^7;qwU2{?tfxY$z;R<>Gesq z@PTjxC;0_@;#hn8IJ2B3B}B?TNzyVzQRJM6$y<`$Rr`_AP{`ik?8s<2M*4_sWi>Or zHKXZcE{-z=$kCL^9?%RWq!I^_jjS0Rq3CNCN=BN|(HU6DU{=Y{T||SW1maFeU6Iiv z1mq>D0zde*dEOR_5P$xwWmOk=KCTPt@^o@_IXNN#dlI39M&{>JGBi4h>=4Cqp~H!t ziNOO23iB18PwMIJ_DQ6h@M6A&zjA3ICkLBr#^EKt1&(gKy1$M4CmQ(cudd*yGN-RQ zHhyUQV$_v*?or*o1UleQ09xI?A<= zCqDIJmBnsRWw%eg`~Op~rSkVZ&i}q3wOUz5GNoLOSkO*H93?+|O!dvOsy*|^M{OsR zX76Jw?RvJWGrVdM862qR*b0 zW}3`$YI=U1L3X)f%E~HK2LB%6PDR~g2}!b^%6l1qVY;x<9U!^n;PF4X2~wqE5lOMBs)bh!LbzRsYJrlN2P8?$(6U;-m@AAig{nZ(Rv-l3 zTq&!O8<&xTSgk+<1DJi?jOPkR01l0NL?XyKLkG-(U4zkNbno{5*vzHo^i#TI7)*yV zM^Bq0PrkH#?@d(~S>cU|lG~chO$9F$NzO5S+{ywM5CWbRS$Ktd`Gxb#2JOXOvU;_w zIieze8?h{F71GxSSGRD%p|fXJvB=!jUOxF`YuM2eR_F*NZ~@ME<3Ml~$Pq$E>4`rZ zy-TZ({>}whEFFQ?gGO|^<;G4H?;lw-X&*FGjwPY}lIenOfp+Gcmw zmDTi2!QQ2kJ=^zHcf=D94klv<_r(%J@xjE*p`_upL@1OW-3(GnGsB!cmRt$|uN9M4 zY8+xCD{*j=bOe}BxOL{fAaGqITJde!25)MgPv?ubw4U8`r}tXjs`saV`0lfBk3V-| Y>=EVIw&QPq@K602_#5CEi0+R53wZ|$5C8xG delta 657 zcmZ3zkLBz-mJOa#tWLZP49c7Rq{7*lgw{@8u3!P89xCX9C;>%15apn#526Yc4FvcE z7#M`shK7RZ^)h_ZCT~aXk>*5g6O2#Pm?FhDk+0ZaZ&=C zS)`-|;>}aC0#Ub=j6f8hvJnr+^w&%b3@2aAzB*Y^MRIbgvLHyVLK*CcmCEK|B}G8H zBot&HP1aSFoXn~s08%2ZVgjOkRSZE?gNhl5+M!|!qTZ{3ZBSM<2Js>wRIjQr*swd? z3=E!=WhB7%JyiwU_d^xzP7O7%VbN;f0O?ZG7KjBp4&+D>9n9IuIQgiWg1|f_h#-hw zq;8}-Sw&qHWRbTz*wr=aAj3AVQCHWW+&W)q@{_R2&AH*)tdkc!<=xy6C(AW?PZ;;) zy%}dG&&s^9nJ@bl6MKGcZem`F_2dn9qLceG_`nKu^9nbw%R9oj*}71udGp#YnCUv7sC{IJlIlnX~MIkT0L?JCRFGV3SuTlYOo}Ly^C?~a8F(yw* z(;CHC1zQEBP(N=!|8PH`Bv`I?dJG?9D?8NQ?Z5dLJ2mergeLicensePattern($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; + } +} diff --git a/src/pharext/Packager.php b/src/pharext/Packager.php index cd3b4d6..b54d284 100644 --- a/src/pharext/Packager.php +++ b/src/pharext/Packager.php @@ -243,16 +243,10 @@ class Packager implements Command */ private function createPackage() { try { - if (($glob = glob($this->source->getBaseDir()."/LICENSE*"))) { - $license = file_get_contents(current($glob)); - } else { - $this->warn("Could not find any LICENSE.* files!\n"); - $license = "UNKNOWN\n"; - } $meta = array_merge(Metadata::all(), [ "name" => $this->args->name, "release" => $this->args->release, - "license" => $license, + "license" => $this->source->getLicense(), "stub" => "pharext_installer.php", "type" => $this->args->zend ? "zend_extension" : "extension", ]); diff --git a/src/pharext/SourceDir.php b/src/pharext/SourceDir.php index 8620668..c7068ba 100644 --- a/src/pharext/SourceDir.php +++ b/src/pharext/SourceDir.php @@ -19,6 +19,12 @@ interface SourceDir extends \Traversable */ public function getPackageInfo(); + /** + * Retrieve the full text license + * @return string + */ + public function getLicense(); + /** * Provide installer command line args * @return array|Traversable diff --git a/src/pharext/SourceDir/Basic.php b/src/pharext/SourceDir/Basic.php index 414c201..fa180fe 100644 --- a/src/pharext/SourceDir/Basic.php +++ b/src/pharext/SourceDir/Basic.php @@ -3,6 +3,7 @@ namespace pharext\SourceDir; use pharext\Cli\Args; +use pharext\License; use pharext\SourceDir; use FilesystemIterator; @@ -14,6 +15,8 @@ use RecursiveIteratorIterator; class Basic implements IteratorAggregate, SourceDir { + use License; + private $path; public function __construct($path) { @@ -28,6 +31,13 @@ class Basic implements IteratorAggregate, SourceDir return []; } + public function getLicense() { + if (($file = $this->findLicense($this->getBaseDir()))) { + return $this->readLicense($file); + } + return "UNKNOWN"; + } + public function getArgs() { return []; } diff --git a/src/pharext/SourceDir/Git.php b/src/pharext/SourceDir/Git.php index e17a305..62dc24f 100644 --- a/src/pharext/SourceDir/Git.php +++ b/src/pharext/SourceDir/Git.php @@ -2,8 +2,8 @@ namespace pharext\SourceDir; -use pharext\Command; use pharext\Cli\Args; +use pharext\License; use pharext\SourceDir; /** @@ -11,6 +11,8 @@ use pharext\SourceDir; */ class Git implements \IteratorAggregate, SourceDir { + use License; + /** * Base directory * @var string @@ -41,6 +43,17 @@ class Git implements \IteratorAggregate, SourceDir return []; } + /** + * @inheritdoc + * @return string + */ + public function getLicense() { + if (($file = $this->findLicense($this->getBaseDir()))) { + return $this->readLicense($file); + } + return "UNKNOWN"; + } + /** * @inheritdoc * @return array diff --git a/src/pharext/SourceDir/Pecl.php b/src/pharext/SourceDir/Pecl.php index 351eaa2..277e122 100644 --- a/src/pharext/SourceDir/Pecl.php +++ b/src/pharext/SourceDir/Pecl.php @@ -5,13 +5,15 @@ namespace pharext\SourceDir; use pharext\Cli\Args; use pharext\Exception; use pharext\SourceDir; -use pharext\Tempfile; +use pharext\License; /** * A PECL extension source directory containing a v2 package.xml */ class Pecl implements \IteratorAggregate, SourceDir { + use License; + /** * The package.xml * @var SimpleXmlElement @@ -73,6 +75,25 @@ class Pecl implements \IteratorAggregate, SourceDir } } + /** + * @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() -- 2.30.2 From 605f3e81a9c0e1d16b2d22297569c1d164635c5c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 18 May 2015 15:20:52 +0200 Subject: [PATCH 05/16] add Cli\Args\Help --- Makefile | 2 +- bin/pharext | Bin 73515 -> 74552 bytes src/pharext/Cli/Args/Help.php | 108 ++++++++++++++++++++++++++++++++++ src/pharext/Cli/Command.php | 55 +---------------- 4 files changed, 110 insertions(+), 55 deletions(-) create mode 100644 src/pharext/Cli/Args/Help.php diff --git a/Makefile b/Makefile index 41b8041..161d2de 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ all: bin/pharext -bin/pharext: src/* src/pharext/* src/pharext/*/* +bin/pharext: src/* src/pharext/* src/pharext/*/* src/pharext/*/*/* @echo "Linting changed source files ... " @for file in $?; do php -l $$file | sed -ne '/^No syntax errors/!p' && exit $${PIPESTATUS[0]}; done @echo "Creating bin/pharext ... " diff --git a/bin/pharext b/bin/pharext index 8f90155d7cc18f523256040d4e7df0eba2315e07..0858fa6cda382d7d846bfd179b2ebe0305f5f249 100755 GIT binary patch delta 1826 zcmaJ?U2GIp6dr0D*+pY3r0i}H@7%ewKX!LZiz01tlNJ%0@S_VQVs}X<%e38OyB%g` zu>?u2)&~QDhx=dSJr5(3dgfk#M;50Yq_m{7V+d^3bZx#!%O*%BJ&Vb9Dx zf8Y0=d+&a8wfWMo%@>DaEnhvWC_3L8`+U{bxq9q!%Twi_5Am-*J;0!d)iMC2TAiZg_eil8qs1~Y(6d0lX zkSV=ck=3Zt9~PcU*>RI>v|@}oX~JytXsv9UN5t!-<(4O_MkNKUWD>;gx6D#91vSf~ z#7h+Drp3bJU5?ZytT&*v9|(CT{anA9B)4*Q-UE~jpkeQzhL3XkNk#T~RFVx+5{N*; z#>E&K6ag^|Mp6`h+jMJomG}Y@3c^y7B{DG!3qsB%P!*Ibj(kH%W0gG)<^47`*$$Dd_P??}q4xZ5zjl>?8GA?KOA! zu6w<`kEI1_dzpSinarRv>@dndxvfvjPqC#Ov4gAbXp)kQ?vQP|lM?`8UL%`|-b;5e z7@IFB6k7>;Ff0#)PgG*?@mn^Zzc<+N2!oPQDeW<)cAM3t22g-m)z^e)R z@pL^Chr{02m*4T$Kz^s>>bDgkbep&wa-t2NsmHv~eQzFEF?0lDilq$7dNMG_}sBe%CNtDF>|hllbzUQbc}(UKkxTn@jm zq^ZHDJSp-5@CO6CfVX`>=I;Iy(o|A4-^E+6fRn)+PG~1@AGjXp>PuSphTkuRDr`CQdQ@N_LUiXi%uZSZ7NbbDkqX9~Qgx z#x9;9u&>+58*2nfC3RDC+9V;mu&9I}sEfRmy68R6*%lJ*=Fi^ed4A9T|BO9(Wt(5J zEd=W9lVyZ37^=Iot1bPbZqZ)4wibf>v>kPmHljL2FKUn2w2#+AnQB6QomyW2kvZYI zSY-`~hfqI>K2)b<4fjdbupxQy{hri;x*@fomdh;&{a!-I^0!;>IJ6ct*@4B2auezU z`7k!=HbQD>!zOr@TClSUEY`4A)FIZ4nqqCJi_CKLlUbXXVmUjV*IC7f&<}eF2|#@f zZvLt`@bNa^q-{^lLA%P3c1CTiu$L2J9>7$3@a6{0sWKK{sFu$y)e0-RtnkAw>phj% zM=q?VH(lL#)9bn2vKVzsAtM~q{G*A{1f`>lDu&cZSyG>fc{=w90>m>@rG4>n_?(eZ zD{@s(yPT*LcyT;R-7Fdp#|#g>%)bk;Kig3vOhYQm>XZ6-Vv6&rS21W;SdVp^U|pLW zX&!^;uNy#G>30g#e5}xEdXPMwkXpG=7M;+waO5248_5W~%sAo3YW2}VC*>cGyljrjKSPfmGyMMJ z!zX)!gZa$GH6w@^D{T6olbvSDi{px6o*w4k_=~B0`BeY<0RA&n7OYcuaNtBJ5FF_D zNFM0QDR4d~A1GAurabn}OH1kPExD!s>DtGQ?E9J7w`Z@qFCCeA{Oq^wA^#_k!QNxN Fe*kMCK3o6* diff --git a/src/pharext/Cli/Args/Help.php b/src/pharext/Cli/Args/Help.php new file mode 100644 index 0000000..19e8cd4 --- /dev/null +++ b/src/pharext/Cli/Args/Help.php @@ -0,0 +1,108 @@ +prog = $prog; + $this->args = $args; + } + + function __toString() { + $usage = "Usage:\n\n \$ "; + $usage .= $this->prog; + + list($flags, $required, $optional) = $this->listSpec(); + if ($flags) { + $usage .= $this->dumpFlags($flags); + } + if ($required) { + $usage .= $this->dumpRequired($required); + } + if ($optional) { + $usage .= $this->dumpOptional($optional); + } + + $help = $this->dumpHelp(); + + return $usage . "\n\n" . $help . "\n"; + } + + function listSpec() { + $flags = []; + $required = []; + $optional = []; + foreach ($this->args->getSpec() as $spec) { + if ($spec[3] & Args::REQARG) { + if ($spec[3] & Args::REQUIRED) { + $required[] = $spec; + } else { + $optional[] = $spec; + } + } else { + $flags[] = $spec; + } + } + + return [$flags, $required, $optional] + compact("flags", "required", "optional"); + } + + 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) { + return sprintf(" [-%s ]", implode("|-", array_column($optional, 0))); + } + + 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 (isset($spec[0])) { + $dump .= sprintf("-%s|", $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 (isset($spec[4])) { + $dump .= sprintf(" [%s]", $spec[4]); + } + $dump .= "\n"; + } + return $dump; + } +} diff --git a/src/pharext/Cli/Command.php b/src/pharext/Cli/Command.php index 6ad2c80..b733885 100644 --- a/src/pharext/Cli/Command.php +++ b/src/pharext/Cli/Command.php @@ -124,60 +124,7 @@ trait Command * @param string $prog */ public function help($prog) { - printf("Usage:\n\n \$ %s", $prog); - - $flags = []; - $required = []; - $optional = []; - foreach ($this->args->getSpec() as $spec) { - if ($spec[3] & CliArgs::REQARG) { - if ($spec[3] & CliArgs::REQUIRED) { - $required[] = $spec; - } else { - $optional[] = $spec; - } - } else { - $flags[] = $spec; - } - } - - if ($flags) { - printf(" [-%s]", implode("", array_column($flags, 0))); - } - foreach ($required as $req) { - printf(" -%s ", $req[0]); - } - if ($optional) { - printf(" [-%s ]", implode("|-", array_column($optional, 0))); - } - printf("\n\n"); - $spc = $this->args->getSpec(); - $max = max(array_map("strlen", array_column($spc, 1))); - $max += $max % 8 + 2; - foreach ($spc as $spec) { - if (isset($spec[0])) { - printf(" -%s|", $spec[0]); - } else { - printf(" "); - } - printf("--%s ", $spec[1]); - if ($spec[3] & CliArgs::REQARG) { - printf(" "); - } elseif ($spec[3] & CliArgs::OPTARG) { - printf("[]"); - } else { - printf(" "); - } - printf("%s%s", str_repeat(" ", $max-strlen($spec[1])+3*!isset($spec[0])), $spec[2]); - if ($spec[3] & CliArgs::REQUIRED) { - printf(" (REQUIRED)"); - } - if (isset($spec[4])) { - printf(" [%s]", $spec[4]); - } - printf("\n"); - } - printf("\n"); + print new Args\Help($prog, $this->args); } /** -- 2.30.2 From c99dfed4c3056e0a8ed1351adb79dd4f16324965 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 18 May 2015 17:11:04 +0200 Subject: [PATCH 06/16] fix basic sourcedir --- bin/pharext | Bin 74552 -> 74562 bytes src/pharext/SourceDir/Basic.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pharext b/bin/pharext index 0858fa6cda382d7d846bfd179b2ebe0305f5f249..98236aba317295cec278e0aa70657557f48bd2d3 100755 GIT binary patch delta 906 zcmXX^ZAep57(UzXrfJP7o70?f@9sWy;xY;ml8}{@eLx>-Uj|AI44h3{gi}%cVJVn{ zHySmoABBm^oF2@SN{rH$pk?I`i$GHoEPqtsM+%*D*8Oo`&htL+^E~Ih_vr}ta)b*s z@(^JXq*Ekb`!PX@qZ7S(hFIE0qDUpY_6D1D%j*HPKWd?p(hCVkVwvF)&KGB99DK&Y!X zV>k2&W|dox5LKadCH3PhED9-%byk5;Fnqia1cMq{gjfcyMkDkseC-_sO`$Z;r3mfn z7o#A}7!LuXim|>#B9sfdIGEEXGa#R^u3M5k(5_FX(Wdoc!oE^_aoJU;)mh?9A_-{* zT7$WDHezXEb9n@)(T@FqI58x&M1+EizE8w1l+qzX=yzpbHq?uuKpkYH^?SxP7D#ST zQ9G?cgn46V!L6ikUvu3h9`RroL*UOagdXmnzYkbUW5yMP6~`yek`<|8%AjT79Pw&8 z_jQa(SN*?hI{`lrwq1f#1~c`lGh{Hbib&pAzETL)dY%E-$fx07<&Hw4UZg~u-pcSO zVuk#FlHiCwPFYs$u+xnck$VzOwvY(-%rTVSV`hKOjM;*9BQxosOjh)#@REZPuacK& z!08IZ<$D{5_DFoac_H<}C zobElrk-h>RfC|R_3fxiqUJ5>6JO%K$-zI}QJ`GsCTJZZ~@S~tie^;2P3)zZR2k#`FoZF?cZs@`cCIYr_j-*^Pg2YcKO>~M|BaYNQ& mX@9vO>6GZ^M*4!~motyo2U5h73mXT@a++(%9?=2YQQJRuu~10> delta 929 zcmXX^ZAep57(Vyz>fEOL&}vSn-n+Z)nvp4m1VOEps6Q;B1hYV;B1bcaS|NQfNh*~} zc*BuOL_zdTd8%bmriE!@MU-NNlzmeROh=zY=bU-}Je=o!pXYhcdv0I9aHC(i+$4h0 zX5~G7kZD^S>*-rp+$$jD{7{qx^^(j8s~(|l@6m@)s@Q3xUrB*mQaq~-m=XF@^7Jz3 zGm)CCfRn*pI`YL_Jd?bM4fsE8vXtbv@-4{X(e(HD* ztL&DPqRNUI_jZqW6P1M25edapE8ic7kln!~=SX(v$DBCmam;5#4IvW6lnGeiOoGJ@ z1I;gR$gst3V)eD8zQ;WD6*f5)T07*-VZ4zzAN*Fk0e(8>G2)#Hq2~4DLy$BxT`Exy z7Wm!7*<#J})UEJVZ`(|Vt0J9rVHBt8uenG=WMO9r@$%+r4^_Zn*~olf=@2RaYa+cQ zcpau$RN6_rH~*?@zs`}>kq??giB5Mx%%t#2%%)(F=2KWIr9z1uxz25}vV}p}05vu{ zvmcQVy3mzFUTx+_0Al@3_?`>-Qe5>#!QY~Tp2>Jt)oHvM%L zof!{3#5_)G8If?7zf-{9OY*tkE{QwOSx0YZya~P6l+ceO`x<)I6d!9;caUd5dG12@ Ee|u3@MF0Q* diff --git a/src/pharext/SourceDir/Basic.php b/src/pharext/SourceDir/Basic.php index fa180fe..f960236 100644 --- a/src/pharext/SourceDir/Basic.php +++ b/src/pharext/SourceDir/Basic.php @@ -62,7 +62,7 @@ class Basic implements IteratorAggregate, SourceDir $rii = new RecursiveIteratorIterator($rci); foreach ($rii as $path => $child) { if (!$child->isDir()) { - yield $path; + yield realpath($path); } } } -- 2.30.2 From 052ea3008a116f3eb9cc5607f76571b705cb10a7 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 19 May 2015 15:32:23 +0200 Subject: [PATCH 07/16] fix trailing newline in quiet mode --- src/pharext/Packager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pharext/Packager.php b/src/pharext/Packager.php index b54d284..bdb83bb 100644 --- a/src/pharext/Packager.php +++ b/src/pharext/Packager.php @@ -157,7 +157,7 @@ class Packager implements Command ); if ($bytes_pct == 1) { $done = true; - printf("\n"); + $this->info("\n"); } } }); -- 2.30.2 From 205d4dff84bebd606a0857a027c52b248243cebe Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 19 May 2015 15:32:44 +0200 Subject: [PATCH 08/16] flush bin --- bin/pharext | Bin 74562 -> 74567 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bin/pharext b/bin/pharext index 98236aba317295cec278e0aa70657557f48bd2d3..aa0f053aa4d03f39ebfb508c84a00fb9aa8088f9 100755 GIT binary patch delta 385 zcmX?fjOF+-mJP3^7%exyk=n<~TxuOXd98vjn7*rE0Hy^Lb-=W}q8^wofb!=<`4^!4 z|B4WO`by?tb(u<<0=E?z7=UJmg6Nm$zP*^dNJ$$kc|pktOtUH*gK2AJh~YWP5b=e| zhG6ll%9dbSPzAzwRe`9lhVs{|K-51`(c=MGw2Fm+Va{_i-pTrEQj;xI`N5jKR3Vxg zp!7CXGqCu3RTD6+rUo%2S`FgkJ~dOY_%St2F#Sml5(0|q5FZ9Y=|**kqc=hLn;)q^ zEap}z$;d3$wad&)%inx*c5J&$q+olJpT&vqc3BG!7xD0Yj+MEU!NkD8;O^w>1OSlp Be-Qux delta 380 zcmX?pjOEZVmJP3^7%euxk=n<~Z1XpA@>&I5Fnw3S089%g>VRo`MLjTG0Oikz@-IO7 z{}mzn^p(uP>N1ry1+FPFFaXUA1<`9ZnVC#pq@)d&yr5(RrdgGZ!L+q9#PA$ti1L zP&2?0fQhz|pybfY@N(VHOr&5zU{ w7PA!;W#*NnZ9X?Uwq54Qv8^Wy^DP3KHfSmbKl|gJ=h|D##K6Gd?&RwP0Oi1t#{d8T -- 2.30.2 From d017df1dcb270773804bbed4628397a9c7df30c4 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 May 2015 08:39:24 +0200 Subject: [PATCH 09/16] release v4.0.0 --- bin/pharext | Bin 74567 -> 74788 bytes src/pharext/Metadata.php | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pharext b/bin/pharext index aa0f053aa4d03f39ebfb508c84a00fb9aa8088f9..f3ff98a63bad652eaf537cbd8877e2c814d42573 100755 GIT binary patch delta 699 zcmX?pjAh9QmJOa#!ZUdp7*rV;7zBZs5r`QWWGBZ+Nobo|DVgXQ=ou(k7h9QGDP^Q4 zrlb~uI3|`>N(C8-MX41f3T0p=lh;VuF&P$0Jhw?8#`TrF)1*QTW0W>2NM9)n8Cp6hY38E=e31a9>B@?hA7nF>^G^?^P zn6_4isLN4?h%Zz&1dCr)wgl6HDiFS_3PgQ1l)qjDqW+1B9uLUkRV)k)bDo>=PS#hG znrxxU57z9Z3enU6rMIb?fyLjeLL8%}1~DXB4dUZIHB+$sF*Qvv{YecH0*dMoPXt2g zMsC0ZbtKiriIL>b-4a@&sr>V!#gp?THI|_Z1s~%_jXnVFeH7D6Q5mR zwrR|Y+D`C}T}l0*6v(u`T+``yHvFQ|lkZ_#5BT6Ul9 zgn?GQxC(!*cz#lMS=8AF76uiW4=x$()DsB$`YgigT9nmGo$L3kYiDhE%@q{BxBk4D z-vVwUvB>8%gnUrW|>JcTc2nAVpDyxN&iR4<-F6ESADhaEUC?H1V=Y>T{H)Yt|N-Jv&fq-BXg_7PPPa$cMMrmhheb3rd*+z@+K!(bU0g8tTvM?|_D@lo&{6IxyvcIArSTY$ZDZ|IWurp`MDX`>vsN`Wq9k8NLikbqm zfo=tv0-|LiAIVPER?-7Y#wbCo>rpZRTT{i#!0=uB%A?7Gsv?sgD2aj<{ZKLn(|XDf zP4UV`VEz2S{Kn&wh zg&1b5Y7AC92k6n%pCz* O=2iyK3k>c~zD@vMYosLr diff --git a/src/pharext/Metadata.php b/src/pharext/Metadata.php index db3ab81..ae5960f 100644 --- a/src/pharext/Metadata.php +++ b/src/pharext/Metadata.php @@ -5,7 +5,7 @@ namespace pharext; class Metadata { static function version() { - return "@dev-master"; + return "4.0.0"; } static function header() { -- 2.30.2 From fbca2e8b8beadbd42bede7186140daba34bfad04 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 20 May 2015 08:39:24 +0200 Subject: [PATCH 10/16] back to dev --- src/pharext/Metadata.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pharext/Metadata.php b/src/pharext/Metadata.php index ae5960f..db3ab81 100644 --- a/src/pharext/Metadata.php +++ b/src/pharext/Metadata.php @@ -5,7 +5,7 @@ namespace pharext; class Metadata { static function version() { - return "4.0.0"; + return "@dev-master"; } static function header() { -- 2.30.2 From 7fb5542ad4f48ae56a92a214b743367637b7c4d7 Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Thu, 6 Aug 2015 09:55:09 +0000 Subject: [PATCH 12/16] Added Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1931502..212a7e7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # pharext +[![Join the chat at https://gitter.im/m6w6/pharext](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/m6w6/pharext?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Distribute your PHP extension as self-installable phar executable ## About -- 2.30.2 From ce54d468fa97453d949185c0128b435add9aa68d Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 19 Aug 2015 21:39:04 +0200 Subject: [PATCH 13/16] remove hard dependency on ext/posix --- bin/pharext | Bin 74788 -> 74847 bytes src/pharext/Tempname.php | 12 +++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/pharext b/bin/pharext index f3ff98a63bad652eaf537cbd8877e2c814d42573..7640c6dff29c0b68c23dd6bfd4acd8e6fae23539 100755 GIT binary patch delta 825 zcmZ2-g5~}RmJOa#!pnFW7*rV;7zBZs5r`QWv?j+$Nmv*fS}8fCq?YOCCKi{Z7AaX5 zTbWrYWuzviKsctRR!RjKiAAXuB?@Io3MbE(vSG2%HMHD(UuqvK^XHpaCNEIX1=AN4 z48SzAq7DyGJXDZ{f#F$6O3dU3Dk78p6$QbP$xuldJ_d%JIa5x7CD%hG4=d_`6@60F z6qpTkEyxrQEfe`jcCxmT9#}F)31VH3k_p(FDpm%D@7h-$O%_xYnfyRW6s+ink};Up zQ-)}YS2hCkrzjhO=@ZJ9V46h*!naU?sLxX|1RMIAiGktdi`iF!hDuI8q9OoRd|d@% z7>6pvFk4k)u;MvDkEZ@CnKju_MRM{~RftDds+xf{JyJCR(~@csO@3;SP-;{&1&i-g z(*)B`)gXQsQHOZXMO{;%f*BG9Aev)$`Gv`~>Z)MHOCgFjUsach`TK_?&!T%%^B5 z733FZRw!vIsHrKWmF6XvfaFpuGK))!p>pv+QwqvUGgFi_A?9!vrIwTy9nBV!-HTaCh=`0ssmmKw|&^ delta 740 zcmcbAf@R4GmJOa#!ZUdp7*rV;7zBZs5r`QWWGBZ+Nobo|DVgXQ=ou(k7h9QGDP^Q4 zrlb~uI3|`>N(C8-MX41f3T0p=lh;Vuu$bx^8Ek$dwU3oqMki+SS_NG&eOJK%ObaOL zfN6V0JuqDW<0-XUgBNRl>O#CM_*+L1TDN_kz=u9OOupt+ejKDOj zvN4#pR)(m{QHF>wR5k>QUsbjQ(}F4xzN-pEeKnN7UIn85iHaT%$l_Hj3=DIgoAFN8 zSCg7-p~?@|?4=6P)BvToshWYs->X6#qoxKiBw7vP<32T0u>3JKO)&jQ4H5#1>JU!^ zs%r`)FhP6@qB(5*3MO}{tAZ78f+*VjNL?nD4H6BL>s!S)E4D_><}1iA&a8+}Pc6yG zPtVMo-l@RYzuiEIQJAUzo}=}`!q)8LGCv=FPt&PWYTQwqopbi5bcN?0KHf93S8wE1 zuFTD7e$cd#`Lqt#zwTL!Wo~#U##oEHt%|LFa_QdAssM(h4|3wO3(PhxIaT#BP>NH( z)$e+t)|@WI?uh-%Lo|O(V_R}ae?pouOMJhZSn~yyknb&eEJDlfvz;)|sux$`uNBWv z>Mn~q`@q7WBJ;r|gPnQ;L0_LmSY3;(*OVf diff --git a/src/pharext/Tempname.php b/src/pharext/Tempname.php index d46250f..3116023 100644 --- a/src/pharext/Tempname.php +++ b/src/pharext/Tempname.php @@ -19,13 +19,23 @@ class Tempname * @param string $suffix e.g. file extension */ public function __construct($prefix, $suffix = null) { - $temp = sys_get_temp_dir() . "/pharext-" . posix_getlogin(); + $temp = sys_get_temp_dir() . "/pharext-" . $this->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 */ -- 2.30.2 From 4af08c149c8b66e9fe8b9b0fb9f276e0745377d1 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 25 Aug 2015 17:13:22 +0200 Subject: [PATCH 14/16] support for running .ext.phars without ext/phar --- Makefile | 5 + bin/pharext | Bin 74847 -> 89746 bytes build/create-phar.php | 5 +- src/pharext/Archive.php | 257 ++++++++++++++++++++++++++++++ src/pharext/Cli/Command.php | 7 +- src/pharext/Installer.php | 10 +- src/pharext/Packager.php | 3 +- src/pharext/Task/Extract.php | 6 +- src/pharext/Task/PharBuild.php | 21 ++- src/pharext/Task/PharCompress.php | 8 +- src/pharext_installer.php | 29 +++- src/pharext_packager.php | 28 +++- 12 files changed, 355 insertions(+), 24 deletions(-) create mode 100644 src/pharext/Archive.php diff --git a/Makefile b/Makefile index 161d2de..887b82d 100644 --- a/Makefile +++ b/Makefile @@ -28,4 +28,9 @@ release: cp build/Metadata.php.in src/pharext/Metadata.php && \ git ci -am "back to dev" +archive-test: bin/pharext + ./bin/pharext -vpgs ../apfd.git + -../php-5.5/sapi/cli/php ./apfd-1.0.1.ext.phar + -./apfd-1.0.1.ext.phar + .PHONY: all clean test release diff --git a/bin/pharext b/bin/pharext index 7640c6dff29c0b68c23dd6bfd4acd8e6fae23539..321039ee1d5d6cace5c5162a40bef6c0a884a922 100755 GIT binary patch delta 19828 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 delta 7805 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 diff --git a/build/create-phar.php b/build/create-phar.php index d2804a8..26ac6e9 100644 --- a/build/create-phar.php +++ b/build/create-phar.php @@ -4,14 +4,13 @@ * Creates bin/pharext, invoked through the Makefile */ -set_include_path(dirname(__DIR__)."/src"); +set_include_path(dirname(__DIR__)."/src:".get_include_path()); spl_autoload_register(function($c) { return include strtr($c, "\\_", "//") . ".php"; }); -$file = (new pharext\Task\PharBuild(null, pharext\Metadata::all() + [ +$file = (new pharext\Task\PharBuild(null, __DIR__."/../src/pharext_packager.php", pharext\Metadata::all() + [ "name" => "pharext", - "stub" => "pharext_packager.php", "license" => file_get_contents(__DIR__."/../LICENSE") ], false))->run(); diff --git a/src/pharext/Archive.php b/src/pharext/Archive.php new file mode 100644 index 0000000..6a9b4a4 --- /dev/null +++ b/src/pharext/Archive.php @@ -0,0 +1,257 @@ + 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($this->file = $file, "r")) { + throw new Exception; + } + $this->stub = $this->readStub(); + $this->manifest = $this->readManifest(); + $this->signature = $this->readSignature(); + } + + 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"; + $dirn = dirname($path); + if (!is_dir($dirn) && !@mkdir($dirn, 0777, true)) { + throw new Exception; + } + if (!$fd = @fopen($path, "w")) { + throw new Exception; + } + switch ($entry["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; + } + if ($entry["osize"] != ($copied = stream_copy_to_stream($this->fd, $fd, $entry["csize"]))) { + throw new Exception("Copied '$copied' of '$file', expected '{$entry["osize"]}' from '{$entry["csize"]}"); + } + fclose($fd); + + $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 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 ('?>' === fread($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 = unpack("Vlen/Vnum/napi/Vflags", fread($this->fd, 14)); + if (($alias = current(unpack("V", fread($this->fd, 4))))) { + $alias = fread($this->fd, $alias); + } + if (($meta = current(unpack("V", fread($this->fd, 4))))) { + $meta = unserialize(fread($this->fd, $meta)); + } + $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"]; + } + if (($file = current(unpack("V", fread($this->fd, 4))))) { + $file = fread($this->fd, $file); + } + if ($file === 0 || !strlen($file)) { + throw new Exception("Empty file name encountered at offset '$offset'"); + } + $header = unpack("Vosize/Vstamp/Vcsize/Vcrc32/Vflags", fread($this->fd, 20)); + if (($meta = current(unpack("V", fread($this->fd, 4))))) { + $meta = unserialize(fread($this->fd, $meta)); + } else { + $meta = []; + } + $entries[$file] = $header + compact("meta", "offset"); + } + + private function readSignature() { + fseek($this->fd, -8, SEEK_END); + $sig = unpack("Vflags/Z4magic", fread($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 = current(unpack("V", fread($this->fd, 4))))) { + $offset = 4 + $hash; + fseek($this->fd, -$offset, SEEK_CUR); + $hash = fread($this->fd, $hash); + fseek($this->fd, 0, SEEK_SET); + $valid = openssl_verify(fread($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 = fread($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"); + } +} diff --git a/src/pharext/Cli/Command.php b/src/pharext/Cli/Command.php index b733885..bc0afbb 100644 --- a/src/pharext/Cli/Command.php +++ b/src/pharext/Cli/Command.php @@ -2,6 +2,7 @@ namespace pharext\Cli; +use pharext\Archive; use pharext\Cli\Args as CliArgs; use Phar; @@ -42,7 +43,11 @@ trait Command * @return mixed */ public function metadata($key = null) { - $running = new Phar(Phar::running(false)); + if (extension_loaded("Phar")) { + $running = new Phar(Phar::running(false)); + } else { + $running = new Archive(PHAREXT_PHAR); + } if ($key === "signature") { $sig = $running->getSignature(); diff --git a/src/pharext/Installer.php b/src/pharext/Installer.php index 29fe271..0171eae 100644 --- a/src/pharext/Installer.php +++ b/src/pharext/Installer.php @@ -68,7 +68,7 @@ class Installer implements Command } } - private function extract(Phar $phar) { + private function extract($phar) { $temp = (new Task\Extract($phar))->run($this->verbosity()); $this->cleanup[] = new Task\Cleanup($temp); return $temp; @@ -90,13 +90,17 @@ class Installer implements Command private function load() { $list = new SplObjectStorage(); - $phar = new Phar(Phar::running(false)); + $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 = new Phar("$temp/$dep_file"); + $dep_phar = extension_loaded("Phar") + ? new Phar("$temp/$dep_file") + : new Archive("$temp/$dep_file"); $list[$dep_phar] = $this->extract($dep_phar); } } diff --git a/src/pharext/Packager.php b/src/pharext/Packager.php index bdb83bb..10542e4 100644 --- a/src/pharext/Packager.php +++ b/src/pharext/Packager.php @@ -247,10 +247,9 @@ class Packager implements Command "name" => $this->args->name, "release" => $this->args->release, "license" => $this->source->getLicense(), - "stub" => "pharext_installer.php", "type" => $this->args->zend ? "zend_extension" : "extension", ]); - $file = (new Task\PharBuild($this->source, $meta))->run($this->verbosity()); + $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); diff --git a/src/pharext/Task/Extract.php b/src/pharext/Task/Extract.php index d68b426..3aa3f85 100644 --- a/src/pharext/Task/Extract.php +++ b/src/pharext/Task/Extract.php @@ -2,6 +2,7 @@ namespace pharext\Task; +use pharext\Archive; use pharext\Task; use pharext\Tempdir; @@ -22,7 +23,7 @@ class Extract implements Task * @param mixed $source archive location */ public function __construct($source) { - if ($source instanceof Phar || $source instanceof PharData) { + if ($source instanceof Phar || $source instanceof PharData || $source instanceof Archive) { $this->source = $source; } else { $this->source = new PharData($source); @@ -37,6 +38,9 @@ class Extract implements Task 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; diff --git a/src/pharext/Task/PharBuild.php b/src/pharext/Task/PharBuild.php index 03ac42c..25dd7a4 100644 --- a/src/pharext/Task/PharBuild.php +++ b/src/pharext/Task/PharBuild.php @@ -19,6 +19,11 @@ class PharBuild implements Task */ private $source; + /** + * @var string + */ + private $stub; + /** * @var array */ @@ -31,11 +36,13 @@ class PharBuild implements Task /** * @param SourceDir $source extension source directory + * @param string $stub path to phar stub * @param array $meta phar meta data * @param bool $readonly whether the stub has -dphar.readonly=1 set */ - public function __construct(SourceDir $source = null, array $meta = null, $readonly = true) { + public function __construct(SourceDir $source = null, $stub, array $meta = null, $readonly = true) { $this->source = $source; + $this->stub = $stub; $this->meta = $meta; $this->readonly = $readonly; } @@ -57,12 +64,12 @@ class PharBuild implements Task if ($this->meta) { $phar->setMetadata($this->meta); - if (isset($this->meta["stub"])) { - $phar->setDefaultStub($this->meta["stub"]); - $phar->setStub("#!/usr/bin/php -dphar.readonly=" . - intval($this->readonly) ."\n". - $phar->getStub()); - } + } + if (is_file($this->stub)) { + $stub = preg_replace_callback('/^#include <([^>]+)>/m', function($includes) { + return file_get_contents($includes[1], true, null, 5); + }, file_get_contents($this->stub)); + $phar->setStub($stub); } $phar->buildFromIterator((new Task\BundleGenerator)->run()); diff --git a/src/pharext/Task/PharCompress.php b/src/pharext/Task/PharCompress.php index ea0607f..78a9349 100644 --- a/src/pharext/Task/PharCompress.php +++ b/src/pharext/Task/PharCompress.php @@ -58,12 +58,10 @@ class PharCompress implements Task if ($verbose) { printf("Compressing %s ...\n", basename($this->package->getPath())); } + /* stop shebang */ + $stub = $this->package->getStub(); $phar = $this->package->compress($this->encoding); - $meta = $phar->getMetadata(); - if (isset($meta["stub"])) { - /* drop shebang */ - $phar->setDefaultStub($meta["stub"]); - } + $phar->setStub(substr($stub, strpos($stub, "\n")+1)); return $this->file . $this->extension; } } diff --git a/src/pharext_installer.php b/src/pharext_installer.php index 89e44a3..19386f2 100644 --- a/src/pharext_installer.php +++ b/src/pharext_installer.php @@ -1,11 +1,38 @@ +#!/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(); diff --git a/src/pharext_packager.php b/src/pharext_packager.php index f85c2f1..bdce719 100644 --- a/src/pharext_packager.php +++ b/src/pharext_packager.php @@ -1,10 +1,36 @@ +#!/usr/bin/env php -dphar.readonly=0 run($argc, $argv); + +__HALT_COMPILER(); -- 2.30.2 From 99085a3ad122f986811769448959bc1ed5257bbc Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 1 Sep 2015 19:28:02 +0200 Subject: [PATCH 15/16] more failure checks --- bin/pharext | Bin 89746 -> 84497 bytes src/pharext/Archive.php | 139 +++++++++++++++++++++++++--------------- 2 files changed, 88 insertions(+), 51 deletions(-) diff --git a/bin/pharext b/bin/pharext index 321039ee1d5d6cace5c5162a40bef6c0a884a922..b464635584534dc679a2dcced3f27219c49fe2b5 100755 GIT binary patch delta 1745 zcmbtVUuaWj6u)Th#(_WtWKwGN;K%u}E+cnYccuif;HU(Kml6B)$TF zBxa%e#s;|mIQlZ(CqX$g245sM)b}Q@yX)~ScSTs&e_m{b+bFP;V3eQ4L@($#ABz<7 zaV1j5hN{d+t*v@NiCLBs(v+%6=)YJbk4&U!O2Nu=!~+Tiqp@(-z(*=LXX3o_`dedR zb&ys$Mt=mGHDV|%dw$L`%e@rS)Q~yy7sP4ggpCZ>@DmVowcA?PuZ5fjxf5 zBfbLoYGC7W+iOXZ%CO6ePytZ&U-GV4M?*y(K84wBJIYTq=6b5)$_#oCM8_7ze)xHP zU;W;;YhpT5pl|GRvsy11Y}KZkO!ckSJ>r-u-TNYKf;lwT>ln#C+VEtdjEdFdzRVOV z>N)Go8l%OPt&rIMNOdGNIm+ee3=BuJ&GvOV_)atTgJ?n=t|v!aVzZ}RT@O!e-tqnB n9pdg_=jYmMiN~KjJo8KF?|s`RPD$zP*$-c$pQ@dsdq)2O`%84b delta 4114 zcmeHKYiv_h9BVT-n%Ev zqLN_zU?Ru3peCZ(7co)ef{Pk3>IaBlBz_SCWD*mCF`_1DoC(DLIp^N4rNba<{9=>l z-*e9Y{rH{J7hcRbekSAHC(<%L&NZ28a5(Md^w!#@t&6tw$&A=WlgShbicx7=tA8Ns z3(AvHeXpp<0ZG;BBEd+58P1Ph-bbi2>)gQmK*?t_eD9RoD~Wz7THgoii0BU-6Qwlm zwQ@tWG(j|G*krOq?2B|JMrdE>mX#=%_Gr5K| zV8lB(fzlvXN9hTDeO_O$=xg3uOV1y-Zl?x5f$%D?^_3C>_#JB=-Tc~VG97hX`35`f z4!mqFrV=aGCQ9pankmz7`6ko1*((?DIOo87ax4zw)|quIctV?(D(n!<2E3G$Mt<2-A3g~>@Ac&W@mgy?JOrt z_N{dPN4tm8vOJcfNAg$>W_5ZhkJ-7TudVrvuPxt`?bU0H&9_TqoG&D*Dl!_AJH%Nc zQF&6-B;*cBN_)amnHWo4iV-<+83>7^YT||%lEtKrF-a2>86-uEX37%b!AFXU_leP{ zID_0{`iywcA+Mi%EaqHf0*ZaAv+<91HZ37Iwo(<>={6){ng9$eF!NPep2%H8mu5*}q-@F^eT~fD>ww^entg0st-=8NF)q~MlR_uHDtyW|PS@Vt4p_lK1rxh2 zeh2byRURF3QBPgN&;dbF4YKZg$!adkN&-}IMAf3APeTk@_fiZXz~Kuks)hz1?t_MK z_3iOaH#Eby#RXl=j=Bb$$Whl|aCNU|kZgIU8w1|y))C-ug);)mVNLRBk{`JP0Me@) znPkV`K0m(GT!2qrv<(x80Up+rao7Q+gpJH5!_9y~w+P^q5+#ikPi}%yEeIS9pe!5+ zsFFq(^UK@J8wyFQ8!S74huXpywm5NxP+H&p=!0yQ3>KI=sgIndud5N~;EjJZJU5cZhv68JV1loa3UeCQC8Iz=oXRzeGBiPtPC?tX1z zgu>C<$8ofe5j|`3thNyFa28b)HQ9&aRszr`VZb~$nG;1ElUA|A3H5;-cQSm6Gr%lG zYerlK>TAJhcxryG)Lc|W64Qd59SGVFl<}+BpodR7p~W*FDK(eHc-QXmM97bnFuk~t z$R4PO-B`w?vAezV(*kBs-x;zDKCI$V6-cJN*=xYZZny}cPI zfHKw&0BdykFv3^(F{1`Uo~r-)^{`G8@y`PVx%w+*XqZ9={>=0IUwt+F{x=6;@uZMu vrfvGn>Dr~!wdT%^8_#ZiyYai*<6qXfd = @fopen($this->file = $file, "r")) { + 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")); } @@ -80,30 +89,11 @@ class Archive implements ArrayAccess } foreach ($this->manifest["entries"] as $file => $entry) { fseek($this->fd, $this->manifest["offset"]+$entry["offset"]); - $path = $dir."/$file"; - $dirn = dirname($path); - if (!is_dir($dirn) && !@mkdir($dirn, 0777, true)) { - throw new Exception; - } - if (!$fd = @fopen($path, "w")) { - throw new Exception; - } - switch ($entry["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; + $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"]}"); } - if ($entry["osize"] != ($copied = stream_copy_to_stream($this->fd, $fd, $entry["csize"]))) { - throw new Exception("Copied '$copied' of '$file', expected '{$entry["osize"]}' from '{$entry["csize"]}"); - } - fclose($fd); $crc = hexdec(hash_file("crc32b", $path)); if ($crc !== $entry["crc32"]) { @@ -122,7 +112,7 @@ class Archive implements ArrayAccess function offsetGet($o) { $this->extract(); - return new \SplFileInfo($this->extracted."/$o"); + return new SplFileInfo($this->extracted."/$o"); } function offsetSet($o, $v) { @@ -143,7 +133,7 @@ class Archive implements ArrayAccess function getPath() { /* compatible with Phar::getPath() */ - return new \SplFileInfo($this->file); + return new SplFileInfo($this->file); } function getMetadata($key = null) { @@ -153,6 +143,63 @@ class Archive implements ArrayAccess 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)) { @@ -160,7 +207,7 @@ class Archive implements ArrayAccess $stub .= $line; if (false !== stripos($line, self::HALT_COMPILER)) { /* check for '?>' on a separate line */ - if ('?>' === fread($this->fd, 2)) { + if ('?>' === $this->readVerified($this->fd, 2)) { $stub .= '?>' . fgets($this->fd); } else { fseek($this->fd, -2, SEEK_CUR); @@ -173,13 +220,9 @@ class Archive implements ArrayAccess private function readManifest() { $current = ftell($this->fd); - $header = unpack("Vlen/Vnum/napi/Vflags", fread($this->fd, 14)); - if (($alias = current(unpack("V", fread($this->fd, 4))))) { - $alias = fread($this->fd, $alias); - } - if (($meta = current(unpack("V", fread($this->fd, 4))))) { - $meta = unserialize(fread($this->fd, $meta)); - } + $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); @@ -198,24 +241,18 @@ class Archive implements ArrayAccess $last = end($entries); $offset = $last["offset"] + $last["csize"]; } - if (($file = current(unpack("V", fread($this->fd, 4))))) { - $file = fread($this->fd, $file); - } - if ($file === 0 || !strlen($file)) { + $file = $this->readStringBinary($this->fd); + if (!strlen($file)) { throw new Exception("Empty file name encountered at offset '$offset'"); } - $header = unpack("Vosize/Vstamp/Vcsize/Vcrc32/Vflags", fread($this->fd, 20)); - if (($meta = current(unpack("V", fread($this->fd, 4))))) { - $meta = unserialize(fread($this->fd, $meta)); - } else { - $meta = []; - } + $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 = unpack("Vflags/Z4magic", fread($this->fd, 8)); + $sig = $this->readFormat("Vflags/Z4magic", $this->fd, 8); $end = ftell($this->fd); if ($sig["magic"] !== "GBMB") { @@ -225,13 +262,13 @@ class Archive implements ArrayAccess switch ($sig["flags"]) { case self::SIG_OPENSSL: fseek($this->fd, -12, SEEK_END); - if (($hash = current(unpack("V", fread($this->fd, 4))))) { + if (($hash = $this->readSingleFormat("V", $this->fd, 4))) { $offset = 4 + $hash; fseek($this->fd, -$offset, SEEK_CUR); - $hash = fread($this->fd, $hash); + $hash = $this->readVerified($this->fd, $hash); fseek($this->fd, 0, SEEK_SET); - $valid = openssl_verify(fread($this->fd, $end - $offset - 8), - $hash, file_get_contents($this->file.".pubkey")) === 1; + $valid = openssl_verify($this->readVerified($this->fd, $end - $offset - 8), + $hash, @file_get_contents($this->file.".pubkey")) === 1; } break; @@ -241,7 +278,7 @@ class Archive implements ArrayAccess case self::SIG_SHA512: $offset = 8 + self::$siglen[$sig["flags"]]; fseek($this->fd, -$offset, SEEK_END); - $hash = fread($this->fd, self::$siglen[$sig["flags"]]); + $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); -- 2.30.2 From 975b503f8cb6e5f4621057712edc3ff6273366c6 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 2 Sep 2015 11:56:38 +0200 Subject: [PATCH 16/16] fix shebang --- src/pharext_packager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pharext_packager.php b/src/pharext_packager.php index bdce719..5dabb9d 100644 --- a/src/pharext_packager.php +++ b/src/pharext_packager.php @@ -1,4 +1,4 @@ -#!/usr/bin/env php -dphar.readonly=0 +#!/usr/bin/php -dphar.readonly=0