phar.c 103 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679
  1. /*
  2. +----------------------------------------------------------------------+
  3. | phar php single-file executable PHP extension |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2005-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Gregory Beaver <cellog@php.net> |
  16. | Marcus Boerger <helly@php.net> |
  17. +----------------------------------------------------------------------+
  18. */
  19. /* $Id$ */
  20. #define PHAR_MAIN 1
  21. #include "phar_internal.h"
  22. #include "SAPI.h"
  23. #include "func_interceptors.h"
  24. static void destroy_phar_data(void *pDest);
  25. ZEND_DECLARE_MODULE_GLOBALS(phar)
  26. char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
  27. /**
  28. * set's phar->is_writeable based on the current INI value
  29. */
  30. static int phar_set_writeable_bit(void *pDest, void *argument TSRMLS_DC) /* {{{ */
  31. {
  32. zend_bool keep = *(zend_bool *)argument;
  33. phar_archive_data *phar = *(phar_archive_data **)pDest;
  34. if (!phar->is_data) {
  35. phar->is_writeable = !keep;
  36. }
  37. return ZEND_HASH_APPLY_KEEP;
  38. }
  39. /* }}} */
  40. /* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
  41. ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
  42. {
  43. zend_bool old, ini;
  44. if (entry->name_length == 14) {
  45. old = PHAR_G(readonly_orig);
  46. } else {
  47. old = PHAR_G(require_hash_orig);
  48. }
  49. if (new_value_length == 2 && !strcasecmp("on", new_value)) {
  50. ini = (zend_bool) 1;
  51. }
  52. else if (new_value_length == 3 && !strcasecmp("yes", new_value)) {
  53. ini = (zend_bool) 1;
  54. }
  55. else if (new_value_length == 4 && !strcasecmp("true", new_value)) {
  56. ini = (zend_bool) 1;
  57. }
  58. else {
  59. ini = (zend_bool) atoi(new_value);
  60. }
  61. /* do not allow unsetting in runtime */
  62. if (stage == ZEND_INI_STAGE_STARTUP) {
  63. if (entry->name_length == 14) {
  64. PHAR_G(readonly_orig) = ini;
  65. } else {
  66. PHAR_G(require_hash_orig) = ini;
  67. }
  68. } else if (old && !ini) {
  69. return FAILURE;
  70. }
  71. if (entry->name_length == 14) {
  72. PHAR_G(readonly) = ini;
  73. if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets) {
  74. zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_fname_map), phar_set_writeable_bit, (void *)&ini TSRMLS_CC);
  75. }
  76. } else {
  77. PHAR_G(require_hash) = ini;
  78. }
  79. return SUCCESS;
  80. }
  81. /* }}}*/
  82. /* this global stores the global cached pre-parsed manifests */
  83. HashTable cached_phars;
  84. HashTable cached_alias;
  85. static void phar_split_cache_list(TSRMLS_D) /* {{{ */
  86. {
  87. char *tmp;
  88. char *key, *lasts, *end;
  89. char ds[2];
  90. phar_archive_data *phar;
  91. uint i = 0;
  92. if (!PHAR_GLOBALS->cache_list || !(PHAR_GLOBALS->cache_list[0])) {
  93. return;
  94. }
  95. ds[0] = DEFAULT_DIR_SEPARATOR;
  96. ds[1] = '\0';
  97. tmp = estrdup(PHAR_GLOBALS->cache_list);
  98. /* fake request startup */
  99. PHAR_GLOBALS->request_init = 1;
  100. if (zend_hash_init(&EG(regular_list), 0, NULL, NULL, 0) == SUCCESS) {
  101. EG(regular_list).nNextFreeElement=1; /* we don't want resource id 0 */
  102. }
  103. PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
  104. PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
  105. /* these two are dummies and will be destroyed later */
  106. zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
  107. zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
  108. /* these two are real and will be copied over cached_phars/cached_alias later */
  109. zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
  110. zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
  111. PHAR_GLOBALS->manifest_cached = 1;
  112. PHAR_GLOBALS->persist = 1;
  113. for (key = php_strtok_r(tmp, ds, &lasts);
  114. key;
  115. key = php_strtok_r(NULL, ds, &lasts)) {
  116. end = strchr(key, DEFAULT_DIR_SEPARATOR);
  117. if (end) {
  118. if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
  119. finish_up:
  120. phar->phar_pos = i++;
  121. php_stream_close(phar->fp);
  122. phar->fp = NULL;
  123. } else {
  124. finish_error:
  125. PHAR_GLOBALS->persist = 0;
  126. PHAR_GLOBALS->manifest_cached = 0;
  127. efree(tmp);
  128. zend_hash_destroy(&(PHAR_G(phar_fname_map)));
  129. PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
  130. zend_hash_destroy(&(PHAR_G(phar_alias_map)));
  131. PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
  132. zend_hash_destroy(&cached_phars);
  133. zend_hash_destroy(&cached_alias);
  134. zend_hash_graceful_reverse_destroy(&EG(regular_list));
  135. memset(&EG(regular_list), 0, sizeof(HashTable));
  136. /* free cached manifests */
  137. PHAR_GLOBALS->request_init = 0;
  138. return;
  139. }
  140. } else {
  141. if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
  142. goto finish_up;
  143. } else {
  144. goto finish_error;
  145. }
  146. }
  147. }
  148. PHAR_GLOBALS->persist = 0;
  149. PHAR_GLOBALS->request_init = 0;
  150. /* destroy dummy values from before */
  151. zend_hash_destroy(&cached_phars);
  152. zend_hash_destroy(&cached_alias);
  153. cached_phars = PHAR_GLOBALS->phar_fname_map;
  154. cached_alias = PHAR_GLOBALS->phar_alias_map;
  155. PHAR_GLOBALS->phar_fname_map.arBuckets = 0;
  156. PHAR_GLOBALS->phar_alias_map.arBuckets = 0;
  157. zend_hash_graceful_reverse_destroy(&EG(regular_list));
  158. memset(&EG(regular_list), 0, sizeof(HashTable));
  159. efree(tmp);
  160. }
  161. /* }}} */
  162. ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
  163. {
  164. PHAR_G(cache_list) = new_value;
  165. if (stage == ZEND_INI_STAGE_STARTUP) {
  166. phar_split_cache_list(TSRMLS_C);
  167. }
  168. return SUCCESS;
  169. }
  170. /* }}} */
  171. PHP_INI_BEGIN()
  172. STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
  173. STD_PHP_INI_BOOLEAN("phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
  174. STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
  175. PHP_INI_END()
  176. /**
  177. * When all uses of a phar have been concluded, this frees the manifest
  178. * and the phar slot
  179. */
  180. void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
  181. {
  182. if (phar->alias && phar->alias != phar->fname) {
  183. pefree(phar->alias, phar->is_persistent);
  184. phar->alias = NULL;
  185. }
  186. if (phar->fname) {
  187. pefree(phar->fname, phar->is_persistent);
  188. phar->fname = NULL;
  189. }
  190. if (phar->signature) {
  191. pefree(phar->signature, phar->is_persistent);
  192. phar->signature = NULL;
  193. }
  194. if (phar->manifest.arBuckets) {
  195. zend_hash_destroy(&phar->manifest);
  196. phar->manifest.arBuckets = NULL;
  197. }
  198. if (phar->mounted_dirs.arBuckets) {
  199. zend_hash_destroy(&phar->mounted_dirs);
  200. phar->mounted_dirs.arBuckets = NULL;
  201. }
  202. if (phar->virtual_dirs.arBuckets) {
  203. zend_hash_destroy(&phar->virtual_dirs);
  204. phar->virtual_dirs.arBuckets = NULL;
  205. }
  206. if (phar->metadata) {
  207. if (phar->is_persistent) {
  208. if (phar->metadata_len) {
  209. /* for zip comments that are strings */
  210. free(phar->metadata);
  211. } else {
  212. zval_internal_ptr_dtor(&phar->metadata);
  213. }
  214. } else {
  215. zval_ptr_dtor(&phar->metadata);
  216. }
  217. phar->metadata_len = 0;
  218. phar->metadata = 0;
  219. }
  220. if (phar->fp) {
  221. php_stream_close(phar->fp);
  222. phar->fp = 0;
  223. }
  224. if (phar->ufp) {
  225. php_stream_close(phar->ufp);
  226. phar->ufp = 0;
  227. }
  228. pefree(phar, phar->is_persistent);
  229. }
  230. /* }}}*/
  231. /**
  232. * Delete refcount and destruct if needed. On destruct return 1 else 0.
  233. */
  234. int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
  235. {
  236. if (phar->is_persistent) {
  237. return 0;
  238. }
  239. if (--phar->refcount < 0) {
  240. if (PHAR_GLOBALS->request_done
  241. || zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
  242. phar_destroy_phar_data(phar TSRMLS_CC);
  243. }
  244. return 1;
  245. } else if (!phar->refcount) {
  246. /* invalidate phar cache */
  247. PHAR_G(last_phar) = NULL;
  248. PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
  249. if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
  250. /* close open file handle - allows removal or rename of
  251. the file on windows, which has greedy locking
  252. only close if the archive was not already compressed. If it
  253. was compressed, then the fp does not refer to the original file */
  254. php_stream_close(phar->fp);
  255. phar->fp = NULL;
  256. }
  257. if (!zend_hash_num_elements(&phar->manifest)) {
  258. /* this is a new phar that has perhaps had an alias/metadata set, but has never
  259. been flushed */
  260. if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
  261. phar_destroy_phar_data(phar TSRMLS_CC);
  262. }
  263. return 1;
  264. }
  265. }
  266. return 0;
  267. }
  268. /* }}}*/
  269. /**
  270. * Destroy phar's in shutdown, here we don't care about aliases
  271. */
  272. static void destroy_phar_data_only(void *pDest) /* {{{ */
  273. {
  274. phar_archive_data *phar_data = *(phar_archive_data **) pDest;
  275. TSRMLS_FETCH();
  276. if (EG(exception) || --phar_data->refcount < 0) {
  277. phar_destroy_phar_data(phar_data TSRMLS_CC);
  278. }
  279. }
  280. /* }}}*/
  281. /**
  282. * Delete aliases to phar's that got kicked out of the global table
  283. */
  284. static int phar_unalias_apply(void *pDest, void *argument TSRMLS_DC) /* {{{ */
  285. {
  286. return *(void**)pDest == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
  287. }
  288. /* }}} */
  289. /**
  290. * Delete aliases to phar's that got kicked out of the global table
  291. */
  292. static int phar_tmpclose_apply(void *pDest TSRMLS_DC) /* {{{ */
  293. {
  294. phar_entry_info *entry = (phar_entry_info *) pDest;
  295. if (entry->fp_type != PHAR_TMP) {
  296. return ZEND_HASH_APPLY_KEEP;
  297. }
  298. if (entry->fp && !entry->fp_refcount) {
  299. php_stream_close(entry->fp);
  300. entry->fp = NULL;
  301. }
  302. return ZEND_HASH_APPLY_KEEP;
  303. }
  304. /* }}} */
  305. /**
  306. * Filename map destructor
  307. */
  308. static void destroy_phar_data(void *pDest) /* {{{ */
  309. {
  310. phar_archive_data *phar_data = *(phar_archive_data **) pDest;
  311. TSRMLS_FETCH();
  312. if (PHAR_GLOBALS->request_ends) {
  313. /* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
  314. this prevents unnecessary unfreed stream resources */
  315. zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply TSRMLS_CC);
  316. destroy_phar_data_only(pDest);
  317. return;
  318. }
  319. zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC);
  320. if (--phar_data->refcount < 0) {
  321. phar_destroy_phar_data(phar_data TSRMLS_CC);
  322. }
  323. }
  324. /* }}}*/
  325. /**
  326. * destructor for the manifest hash, frees each file's entry
  327. */
  328. void destroy_phar_manifest_entry(void *pDest) /* {{{ */
  329. {
  330. phar_entry_info *entry = (phar_entry_info *)pDest;
  331. TSRMLS_FETCH();
  332. if (entry->cfp) {
  333. php_stream_close(entry->cfp);
  334. entry->cfp = 0;
  335. }
  336. if (entry->fp) {
  337. php_stream_close(entry->fp);
  338. entry->fp = 0;
  339. }
  340. if (entry->metadata) {
  341. if (entry->is_persistent) {
  342. if (entry->metadata_len) {
  343. /* for zip comments that are strings */
  344. free(entry->metadata);
  345. } else {
  346. zval_internal_ptr_dtor(&entry->metadata);
  347. }
  348. } else {
  349. zval_ptr_dtor(&entry->metadata);
  350. }
  351. entry->metadata_len = 0;
  352. entry->metadata = 0;
  353. }
  354. if (entry->metadata_str.c) {
  355. smart_str_free(&entry->metadata_str);
  356. entry->metadata_str.c = 0;
  357. }
  358. pefree(entry->filename, entry->is_persistent);
  359. if (entry->link) {
  360. pefree(entry->link, entry->is_persistent);
  361. entry->link = 0;
  362. }
  363. if (entry->tmp) {
  364. pefree(entry->tmp, entry->is_persistent);
  365. entry->tmp = 0;
  366. }
  367. }
  368. /* }}} */
  369. int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */
  370. {
  371. int ret = 0;
  372. if (idata->internal_file && !idata->internal_file->is_persistent) {
  373. if (--idata->internal_file->fp_refcount < 0) {
  374. idata->internal_file->fp_refcount = 0;
  375. }
  376. if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
  377. php_stream_close(idata->fp);
  378. }
  379. /* if phar_get_or_create_entry_data returns a sub-directory, we have to free it */
  380. if (idata->internal_file->is_temp_dir) {
  381. destroy_phar_manifest_entry((void *)idata->internal_file);
  382. efree(idata->internal_file);
  383. }
  384. }
  385. phar_archive_delref(idata->phar TSRMLS_CC);
  386. efree(idata);
  387. return ret;
  388. }
  389. /* }}} */
  390. /**
  391. * Removes an entry, either by actually removing it or by marking it.
  392. */
  393. void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */
  394. {
  395. phar_archive_data *phar;
  396. phar = idata->phar;
  397. if (idata->internal_file->fp_refcount < 2) {
  398. if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
  399. php_stream_close(idata->fp);
  400. }
  401. zend_hash_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
  402. idata->phar->refcount--;
  403. efree(idata);
  404. } else {
  405. idata->internal_file->is_deleted = 1;
  406. phar_entry_delref(idata TSRMLS_CC);
  407. }
  408. if (!phar->donotflush) {
  409. phar_flush(phar, 0, 0, 0, error TSRMLS_CC);
  410. }
  411. }
  412. /* }}} */
  413. #define MAPPHAR_ALLOC_FAIL(msg) \
  414. if (fp) {\
  415. php_stream_close(fp);\
  416. }\
  417. if (error) {\
  418. spprintf(error, 0, msg, fname);\
  419. }\
  420. return FAILURE;
  421. #define MAPPHAR_FAIL(msg) \
  422. efree(savebuf);\
  423. if (mydata) {\
  424. phar_destroy_phar_data(mydata TSRMLS_CC);\
  425. }\
  426. if (signature) {\
  427. pefree(signature, PHAR_G(persist));\
  428. }\
  429. MAPPHAR_ALLOC_FAIL(msg)
  430. #ifdef WORDS_BIGENDIAN
  431. # define PHAR_GET_32(buffer, var) \
  432. var = ((((unsigned char*)(buffer))[3]) << 24) \
  433. | ((((unsigned char*)(buffer))[2]) << 16) \
  434. | ((((unsigned char*)(buffer))[1]) << 8) \
  435. | (((unsigned char*)(buffer))[0]); \
  436. (buffer) += 4
  437. # define PHAR_GET_16(buffer, var) \
  438. var = ((((unsigned char*)(buffer))[1]) << 8) \
  439. | (((unsigned char*)(buffer))[0]); \
  440. (buffer) += 2
  441. #else
  442. # define PHAR_GET_32(buffer, var) \
  443. memcpy(&var, buffer, sizeof(var)); \
  444. buffer += 4
  445. # define PHAR_GET_16(buffer, var) \
  446. var = *(php_uint16*)(buffer); \
  447. buffer += 2
  448. #endif
  449. #define PHAR_ZIP_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
  450. (((php_uint16)var[1]) & 0xff) << 8))
  451. #define PHAR_ZIP_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
  452. (((php_uint32)var[1]) & 0xff) << 8 | \
  453. (((php_uint32)var[2]) & 0xff) << 16 | \
  454. (((php_uint32)var[3]) & 0xff) << 24))
  455. /**
  456. * Open an already loaded phar
  457. */
  458. int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
  459. {
  460. phar_archive_data *phar;
  461. #ifdef PHP_WIN32
  462. char *unixfname;
  463. #endif
  464. if (error) {
  465. *error = NULL;
  466. }
  467. #ifdef PHP_WIN32
  468. unixfname = estrndup(fname, fname_len);
  469. phar_unixify_path_separators(unixfname, fname_len);
  470. if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC)
  471. && ((alias && fname_len == phar->fname_len
  472. && !strncmp(unixfname, phar->fname, fname_len)) || !alias)
  473. ) {
  474. phar_entry_info *stub;
  475. efree(unixfname);
  476. #else
  477. if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC)
  478. && ((alias && fname_len == phar->fname_len
  479. && !strncmp(fname, phar->fname, fname_len)) || !alias)
  480. ) {
  481. phar_entry_info *stub;
  482. #endif
  483. /* logic above is as follows:
  484. If an explicit alias was requested, ensure the filename passed in
  485. matches the phar's filename.
  486. If no alias was passed in, then it can match either and be valid
  487. */
  488. if (!is_data) {
  489. /* prevent any ".phar" without a stub getting through */
  490. if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
  491. if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
  492. if (error) {
  493. spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
  494. }
  495. return FAILURE;
  496. }
  497. }
  498. }
  499. if (pphar) {
  500. *pphar = phar;
  501. }
  502. return SUCCESS;
  503. } else {
  504. #ifdef PHP_WIN32
  505. efree(unixfname);
  506. #endif
  507. if (pphar) {
  508. *pphar = NULL;
  509. }
  510. if (phar && error && !(options & REPORT_ERRORS)) {
  511. efree(error);
  512. }
  513. return FAILURE;
  514. }
  515. }
  516. /* }}}*/
  517. /**
  518. * Parse out metadata from the manifest for a single file
  519. *
  520. * Meta-data is in this format:
  521. * [len32][data...]
  522. *
  523. * data is the serialized zval
  524. */
  525. int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_len TSRMLS_DC) /* {{{ */
  526. {
  527. php_unserialize_data_t var_hash;
  528. if (zip_metadata_len) {
  529. const unsigned char *p;
  530. unsigned char *p_buff = (unsigned char *)estrndup(*buffer, zip_metadata_len);
  531. p = p_buff;
  532. ALLOC_ZVAL(*metadata);
  533. INIT_ZVAL(**metadata);
  534. PHP_VAR_UNSERIALIZE_INIT(var_hash);
  535. if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash TSRMLS_CC)) {
  536. efree(p_buff);
  537. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  538. zval_ptr_dtor(metadata);
  539. *metadata = NULL;
  540. return FAILURE;
  541. }
  542. efree(p_buff);
  543. PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
  544. if (PHAR_G(persist)) {
  545. /* lazy init metadata */
  546. zval_ptr_dtor(metadata);
  547. *metadata = (zval *) pemalloc(zip_metadata_len, 1);
  548. memcpy(*metadata, *buffer, zip_metadata_len);
  549. return SUCCESS;
  550. }
  551. } else {
  552. *metadata = NULL;
  553. }
  554. return SUCCESS;
  555. }
  556. /* }}}*/
  557. /**
  558. * Size of fixed fields in the manifest.
  559. * See: http://php.net/manual/en/phar.fileformat.phar.php
  560. */
  561. #define MANIFEST_FIXED_LEN 18
  562. #define SAFE_PHAR_GET_32(buffer, endbuffer, var) \
  563. if (UNEXPECTED(buffer + 4 > endbuffer)) { \
  564. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)"); \
  565. } \
  566. PHAR_GET_32(buffer, var);
  567. /**
  568. * Does not check for a previously opened phar in the cache.
  569. *
  570. * Parse a new one and add it to the cache, returning either SUCCESS or
  571. * FAILURE, and setting pphar to the pointer to the manifest entry
  572. *
  573. * This is used by phar_open_from_filename to process the manifest, but can be called
  574. * directly.
  575. */
  576. static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
  577. {
  578. char b32[4], *buffer, *endbuffer, *savebuf;
  579. phar_archive_data *mydata = NULL;
  580. phar_entry_info entry;
  581. php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
  582. php_uint16 manifest_ver;
  583. php_uint32 len;
  584. long offset;
  585. int sig_len, register_alias = 0, temp_alias = 0;
  586. char *signature = NULL;
  587. if (pphar) {
  588. *pphar = NULL;
  589. }
  590. if (error) {
  591. *error = NULL;
  592. }
  593. /* check for ?>\n and increment accordingly */
  594. if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
  595. MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
  596. }
  597. buffer = b32;
  598. if (3 != php_stream_read(fp, buffer, 3)) {
  599. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
  600. }
  601. if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
  602. int nextchar;
  603. halt_offset += 3;
  604. if (EOF == (nextchar = php_stream_getc(fp))) {
  605. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
  606. }
  607. if ((char) nextchar == '\r') {
  608. /* if we have an \r we require an \n as well */
  609. if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
  610. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
  611. }
  612. ++halt_offset;
  613. }
  614. if ((char) nextchar == '\n') {
  615. ++halt_offset;
  616. }
  617. }
  618. /* make sure we are at the right location to read the manifest */
  619. if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
  620. MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
  621. }
  622. /* read in manifest */
  623. buffer = b32;
  624. if (4 != php_stream_read(fp, buffer, 4)) {
  625. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
  626. }
  627. PHAR_GET_32(buffer, manifest_len);
  628. if (manifest_len > 1048576 * 100) {
  629. /* prevent serious memory issues by limiting manifest to at most 100 MB in length */
  630. MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
  631. }
  632. buffer = (char *)emalloc(manifest_len);
  633. savebuf = buffer;
  634. endbuffer = buffer + manifest_len;
  635. if (manifest_len < MANIFEST_FIXED_LEN || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
  636. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
  637. }
  638. /* extract the number of entries */
  639. SAFE_PHAR_GET_32(buffer, endbuffer, manifest_count);
  640. if (manifest_count == 0) {
  641. MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry");
  642. }
  643. /* extract API version, lowest nibble currently unused */
  644. manifest_ver = (((unsigned char)buffer[0]) << 8)
  645. + ((unsigned char)buffer[1]);
  646. buffer += 2;
  647. if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
  648. efree(savebuf);
  649. php_stream_close(fp);
  650. if (error) {
  651. spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F);
  652. }
  653. return FAILURE;
  654. }
  655. SAFE_PHAR_GET_32(buffer, endbuffer, manifest_flags);
  656. manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
  657. manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
  658. /* remember whether this entire phar was compressed with gz/bzip2 */
  659. manifest_flags |= compression;
  660. /* The lowest nibble contains the phar wide flags. The compression flags can */
  661. /* be ignored on reading because it is being generated anyways. */
  662. if (manifest_flags & PHAR_HDR_SIGNATURE) {
  663. char sig_buf[8], *sig_ptr = sig_buf;
  664. off_t read_len;
  665. size_t end_of_phar;
  666. if (-1 == php_stream_seek(fp, -8, SEEK_END)
  667. || (read_len = php_stream_tell(fp)) < 20
  668. || 8 != php_stream_read(fp, sig_buf, 8)
  669. || memcmp(sig_buf+4, "GBMB", 4)) {
  670. efree(savebuf);
  671. php_stream_close(fp);
  672. if (error) {
  673. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  674. }
  675. return FAILURE;
  676. }
  677. PHAR_GET_32(sig_ptr, sig_flags);
  678. switch(sig_flags) {
  679. case PHAR_SIG_OPENSSL: {
  680. php_uint32 signature_len;
  681. char *sig;
  682. off_t whence;
  683. /* we store the signature followed by the signature length */
  684. if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
  685. || 4 != php_stream_read(fp, sig_buf, 4)) {
  686. efree(savebuf);
  687. php_stream_close(fp);
  688. if (error) {
  689. spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
  690. }
  691. return FAILURE;
  692. }
  693. sig_ptr = sig_buf;
  694. PHAR_GET_32(sig_ptr, signature_len);
  695. sig = (char *) emalloc(signature_len);
  696. whence = signature_len + 4;
  697. whence = -whence;
  698. if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
  699. || !(end_of_phar = php_stream_tell(fp))
  700. || signature_len != php_stream_read(fp, sig, signature_len)) {
  701. efree(savebuf);
  702. efree(sig);
  703. php_stream_close(fp);
  704. if (error) {
  705. spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
  706. }
  707. return FAILURE;
  708. }
  709. if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error TSRMLS_CC)) {
  710. efree(savebuf);
  711. efree(sig);
  712. php_stream_close(fp);
  713. if (error) {
  714. char *save = *error;
  715. spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
  716. efree(save);
  717. }
  718. return FAILURE;
  719. }
  720. efree(sig);
  721. }
  722. break;
  723. #if PHAR_HASH_OK
  724. case PHAR_SIG_SHA512: {
  725. unsigned char digest[64];
  726. php_stream_seek(fp, -(8 + 64), SEEK_END);
  727. read_len = php_stream_tell(fp);
  728. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  729. efree(savebuf);
  730. php_stream_close(fp);
  731. if (error) {
  732. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  733. }
  734. return FAILURE;
  735. }
  736. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error TSRMLS_CC)) {
  737. efree(savebuf);
  738. php_stream_close(fp);
  739. if (error) {
  740. char *save = *error;
  741. spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
  742. efree(save);
  743. }
  744. return FAILURE;
  745. }
  746. break;
  747. }
  748. case PHAR_SIG_SHA256: {
  749. unsigned char digest[32];
  750. php_stream_seek(fp, -(8 + 32), SEEK_END);
  751. read_len = php_stream_tell(fp);
  752. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  753. efree(savebuf);
  754. php_stream_close(fp);
  755. if (error) {
  756. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  757. }
  758. return FAILURE;
  759. }
  760. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error TSRMLS_CC)) {
  761. efree(savebuf);
  762. php_stream_close(fp);
  763. if (error) {
  764. char *save = *error;
  765. spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
  766. efree(save);
  767. }
  768. return FAILURE;
  769. }
  770. break;
  771. }
  772. #else
  773. case PHAR_SIG_SHA512:
  774. case PHAR_SIG_SHA256:
  775. efree(savebuf);
  776. php_stream_close(fp);
  777. if (error) {
  778. spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
  779. }
  780. return FAILURE;
  781. #endif
  782. case PHAR_SIG_SHA1: {
  783. unsigned char digest[20];
  784. php_stream_seek(fp, -(8 + 20), SEEK_END);
  785. read_len = php_stream_tell(fp);
  786. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  787. efree(savebuf);
  788. php_stream_close(fp);
  789. if (error) {
  790. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  791. }
  792. return FAILURE;
  793. }
  794. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error TSRMLS_CC)) {
  795. efree(savebuf);
  796. php_stream_close(fp);
  797. if (error) {
  798. char *save = *error;
  799. spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
  800. efree(save);
  801. }
  802. return FAILURE;
  803. }
  804. break;
  805. }
  806. case PHAR_SIG_MD5: {
  807. unsigned char digest[16];
  808. php_stream_seek(fp, -(8 + 16), SEEK_END);
  809. read_len = php_stream_tell(fp);
  810. if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
  811. efree(savebuf);
  812. php_stream_close(fp);
  813. if (error) {
  814. spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
  815. }
  816. return FAILURE;
  817. }
  818. if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error TSRMLS_CC)) {
  819. efree(savebuf);
  820. php_stream_close(fp);
  821. if (error) {
  822. char *save = *error;
  823. spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
  824. efree(save);
  825. }
  826. return FAILURE;
  827. }
  828. break;
  829. }
  830. default:
  831. efree(savebuf);
  832. php_stream_close(fp);
  833. if (error) {
  834. spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
  835. }
  836. return FAILURE;
  837. }
  838. } else if (PHAR_G(require_hash)) {
  839. efree(savebuf);
  840. php_stream_close(fp);
  841. if (error) {
  842. spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
  843. }
  844. return FAILURE;
  845. } else {
  846. sig_flags = 0;
  847. sig_len = 0;
  848. }
  849. /* extract alias */
  850. SAFE_PHAR_GET_32(buffer, endbuffer, tmp_len);
  851. if (buffer + tmp_len > endbuffer) {
  852. MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
  853. }
  854. if (manifest_len < MANIFEST_FIXED_LEN + tmp_len) {
  855. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
  856. }
  857. /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
  858. if (tmp_len) {
  859. /* if the alias is stored we enforce it (implicit overrides explicit) */
  860. if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
  861. {
  862. php_stream_close(fp);
  863. if (signature) {
  864. efree(signature);
  865. }
  866. if (error) {
  867. spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%.*s\" under different alias \"%s\"", fname, tmp_len, buffer, alias);
  868. }
  869. efree(savebuf);
  870. return FAILURE;
  871. }
  872. alias_len = tmp_len;
  873. alias = buffer;
  874. buffer += tmp_len;
  875. register_alias = 1;
  876. } else if (!alias_len || !alias) {
  877. /* if we neither have an explicit nor an implicit alias, we use the filename */
  878. alias = NULL;
  879. alias_len = 0;
  880. register_alias = 0;
  881. } else if (alias_len) {
  882. register_alias = 1;
  883. temp_alias = 1;
  884. }
  885. /* we have 5 32-bit items plus 1 byte at least */
  886. if (manifest_count > ((manifest_len - MANIFEST_FIXED_LEN - tmp_len) / (5 * 4 + 1))) {
  887. /* prevent serious memory issues */
  888. MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
  889. }
  890. mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
  891. mydata->is_persistent = PHAR_G(persist);
  892. /* check whether we have meta data, zero check works regardless of byte order */
  893. SAFE_PHAR_GET_32(buffer, endbuffer, len);
  894. if (mydata->is_persistent) {
  895. mydata->metadata_len = len;
  896. if (!len) {
  897. /* FIXME: not sure why this is needed but removing it breaks tests */
  898. SAFE_PHAR_GET_32(buffer, endbuffer, len);
  899. }
  900. }
  901. if(len > endbuffer - buffer) {
  902. MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
  903. }
  904. if (phar_parse_metadata(&buffer, &mydata->metadata, len TSRMLS_CC) == FAILURE) {
  905. MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
  906. }
  907. buffer += len;
  908. /* set up our manifest */
  909. zend_hash_init(&mydata->manifest, manifest_count,
  910. zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
  911. zend_hash_init(&mydata->mounted_dirs, 5,
  912. zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
  913. zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
  914. zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
  915. mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
  916. #ifdef PHP_WIN32
  917. phar_unixify_path_separators(mydata->fname, fname_len);
  918. #endif
  919. mydata->fname_len = fname_len;
  920. offset = halt_offset + manifest_len + 4;
  921. memset(&entry, 0, sizeof(phar_entry_info));
  922. entry.phar = mydata;
  923. entry.fp_type = PHAR_FP;
  924. entry.is_persistent = mydata->is_persistent;
  925. for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
  926. if (buffer + 28 > endbuffer) {
  927. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
  928. }
  929. PHAR_GET_32(buffer, entry.filename_len);
  930. if (entry.filename_len == 0) {
  931. MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
  932. }
  933. if (entry.is_persistent) {
  934. entry.manifest_pos = manifest_index;
  935. }
  936. if (entry.filename_len > endbuffer - buffer - 24) {
  937. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
  938. }
  939. if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
  940. entry.is_dir = 1;
  941. } else {
  942. entry.is_dir = 0;
  943. }
  944. phar_add_virtual_dirs(mydata, buffer, entry.filename_len TSRMLS_CC);
  945. entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
  946. buffer += entry.filename_len;
  947. PHAR_GET_32(buffer, entry.uncompressed_filesize);
  948. PHAR_GET_32(buffer, entry.timestamp);
  949. if (offset == halt_offset + (int)manifest_len + 4) {
  950. mydata->min_timestamp = entry.timestamp;
  951. mydata->max_timestamp = entry.timestamp;
  952. } else {
  953. if (mydata->min_timestamp > entry.timestamp) {
  954. mydata->min_timestamp = entry.timestamp;
  955. } else if (mydata->max_timestamp < entry.timestamp) {
  956. mydata->max_timestamp = entry.timestamp;
  957. }
  958. }
  959. PHAR_GET_32(buffer, entry.compressed_filesize);
  960. PHAR_GET_32(buffer, entry.crc32);
  961. PHAR_GET_32(buffer, entry.flags);
  962. if (entry.is_dir) {
  963. entry.filename_len--;
  964. entry.flags |= PHAR_ENT_PERM_DEF_DIR;
  965. }
  966. PHAR_GET_32(buffer, len);
  967. if (entry.is_persistent) {
  968. entry.metadata_len = len;
  969. } else {
  970. entry.metadata_len = 0;
  971. }
  972. if (len > endbuffer - buffer) {
  973. pefree(entry.filename, entry.is_persistent);
  974. MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
  975. }
  976. if (phar_parse_metadata(&buffer, &entry.metadata, len TSRMLS_CC) == FAILURE) {
  977. pefree(entry.filename, entry.is_persistent);
  978. MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
  979. }
  980. buffer += len;
  981. entry.offset = entry.offset_abs = offset;
  982. offset += entry.compressed_filesize;
  983. switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
  984. case PHAR_ENT_COMPRESSED_GZ:
  985. if (!PHAR_G(has_zlib)) {
  986. if (entry.metadata) {
  987. if (entry.is_persistent) {
  988. free(entry.metadata);
  989. } else {
  990. zval_ptr_dtor(&entry.metadata);
  991. }
  992. }
  993. pefree(entry.filename, entry.is_persistent);
  994. MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
  995. }
  996. break;
  997. case PHAR_ENT_COMPRESSED_BZ2:
  998. if (!PHAR_G(has_bz2)) {
  999. if (entry.metadata) {
  1000. if (entry.is_persistent) {
  1001. free(entry.metadata);
  1002. } else {
  1003. zval_ptr_dtor(&entry.metadata);
  1004. }
  1005. }
  1006. pefree(entry.filename, entry.is_persistent);
  1007. MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
  1008. }
  1009. break;
  1010. default:
  1011. if (entry.uncompressed_filesize != entry.compressed_filesize) {
  1012. if (entry.metadata) {
  1013. if (entry.is_persistent) {
  1014. free(entry.metadata);
  1015. } else {
  1016. zval_ptr_dtor(&entry.metadata);
  1017. }
  1018. }
  1019. pefree(entry.filename, entry.is_persistent);
  1020. MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
  1021. }
  1022. break;
  1023. }
  1024. manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
  1025. /* if signature matched, no need to check CRC32 for each file */
  1026. entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
  1027. phar_set_inode(&entry TSRMLS_CC);
  1028. zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL);
  1029. }
  1030. snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
  1031. mydata->internal_file_start = halt_offset + manifest_len + 4;
  1032. mydata->halt_offset = halt_offset;
  1033. mydata->flags = manifest_flags;
  1034. endbuffer = strrchr(mydata->fname, '/');
  1035. if (endbuffer) {
  1036. mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
  1037. if (mydata->ext == endbuffer) {
  1038. mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
  1039. }
  1040. if (mydata->ext) {
  1041. mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
  1042. }
  1043. }
  1044. mydata->alias = alias ?
  1045. pestrndup(alias, alias_len, mydata->is_persistent) :
  1046. pestrndup(mydata->fname, fname_len, mydata->is_persistent);
  1047. mydata->alias_len = alias ? alias_len : fname_len;
  1048. mydata->sig_flags = sig_flags;
  1049. mydata->fp = fp;
  1050. mydata->sig_len = sig_len;
  1051. mydata->signature = signature;
  1052. phar_request_initialize(TSRMLS_C);
  1053. if (register_alias) {
  1054. phar_archive_data **fd_ptr;
  1055. mydata->is_temporary_alias = temp_alias;
  1056. if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
  1057. signature = NULL;
  1058. fp = NULL;
  1059. MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
  1060. }
  1061. if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
  1062. if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
  1063. signature = NULL;
  1064. fp = NULL;
  1065. MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
  1066. }
  1067. }
  1068. zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
  1069. } else {
  1070. mydata->is_temporary_alias = 1;
  1071. }
  1072. zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
  1073. efree(savebuf);
  1074. if (pphar) {
  1075. *pphar = mydata;
  1076. }
  1077. return SUCCESS;
  1078. }
  1079. /* }}} */
  1080. /**
  1081. * Create or open a phar for writing
  1082. */
  1083. int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
  1084. {
  1085. const char *ext_str, *z;
  1086. char *my_error;
  1087. int ext_len;
  1088. phar_archive_data **test, *unused = NULL;
  1089. test = &unused;
  1090. if (error) {
  1091. *error = NULL;
  1092. }
  1093. /* first try to open an existing file */
  1094. if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
  1095. goto check_file;
  1096. }
  1097. /* next try to create a new file */
  1098. if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
  1099. if (error) {
  1100. if (ext_len == -2) {
  1101. spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
  1102. } else {
  1103. spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
  1104. }
  1105. }
  1106. return FAILURE;
  1107. }
  1108. check_file:
  1109. if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
  1110. if (pphar) {
  1111. *pphar = *test;
  1112. }
  1113. if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
  1114. if (error) {
  1115. spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
  1116. }
  1117. return FAILURE;
  1118. }
  1119. if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
  1120. phar_entry_info *stub;
  1121. if (FAILURE == zend_hash_find(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) {
  1122. spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
  1123. return FAILURE;
  1124. }
  1125. }
  1126. if (!PHAR_G(readonly) || (*test)->is_data) {
  1127. (*test)->is_writeable = 1;
  1128. }
  1129. return SUCCESS;
  1130. } else if (my_error) {
  1131. if (error) {
  1132. *error = my_error;
  1133. } else {
  1134. efree(my_error);
  1135. }
  1136. return FAILURE;
  1137. }
  1138. if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
  1139. /* assume zip-based phar */
  1140. return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
  1141. }
  1142. if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
  1143. /* assume tar-based phar */
  1144. return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
  1145. }
  1146. return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
  1147. }
  1148. /* }}} */
  1149. int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
  1150. {
  1151. phar_archive_data *mydata;
  1152. php_stream *fp;
  1153. char *actual = NULL, *p;
  1154. if (!pphar) {
  1155. pphar = &mydata;
  1156. }
  1157. #if PHP_API_VERSION < 20100412
  1158. if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
  1159. return FAILURE;
  1160. }
  1161. #endif
  1162. if (php_check_open_basedir(fname TSRMLS_CC)) {
  1163. return FAILURE;
  1164. }
  1165. /* first open readonly so it won't be created if not present */
  1166. fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
  1167. if (actual) {
  1168. fname = actual;
  1169. fname_len = strlen(actual);
  1170. }
  1171. if (fp) {
  1172. if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC) == SUCCESS) {
  1173. if ((*pphar)->is_data || !PHAR_G(readonly)) {
  1174. (*pphar)->is_writeable = 1;
  1175. }
  1176. if (actual) {
  1177. efree(actual);
  1178. }
  1179. return SUCCESS;
  1180. } else {
  1181. /* file exists, but is either corrupt or not a phar archive */
  1182. if (actual) {
  1183. efree(actual);
  1184. }
  1185. return FAILURE;
  1186. }
  1187. }
  1188. if (actual) {
  1189. efree(actual);
  1190. }
  1191. if (PHAR_G(readonly) && !is_data) {
  1192. if (options & REPORT_ERRORS) {
  1193. if (error) {
  1194. spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
  1195. }
  1196. }
  1197. return FAILURE;
  1198. }
  1199. /* set up our manifest */
  1200. mydata = ecalloc(1, sizeof(phar_archive_data));
  1201. mydata->fname = expand_filepath(fname, NULL TSRMLS_CC);
  1202. fname_len = strlen(mydata->fname);
  1203. #ifdef PHP_WIN32
  1204. phar_unixify_path_separators(mydata->fname, fname_len);
  1205. #endif
  1206. p = strrchr(mydata->fname, '/');
  1207. if (p) {
  1208. mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
  1209. if (mydata->ext == p) {
  1210. mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
  1211. }
  1212. if (mydata->ext) {
  1213. mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
  1214. }
  1215. }
  1216. if (pphar) {
  1217. *pphar = mydata;
  1218. }
  1219. zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
  1220. zend_get_hash_value, destroy_phar_manifest_entry, 0);
  1221. zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
  1222. zend_get_hash_value, NULL, 0);
  1223. zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
  1224. zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
  1225. mydata->fname_len = fname_len;
  1226. snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
  1227. mydata->is_temporary_alias = alias ? 0 : 1;
  1228. mydata->internal_file_start = -1;
  1229. mydata->fp = NULL;
  1230. mydata->is_writeable = 1;
  1231. mydata->is_brandnew = 1;
  1232. phar_request_initialize(TSRMLS_C);
  1233. zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
  1234. if (is_data) {
  1235. alias = NULL;
  1236. alias_len = 0;
  1237. mydata->is_data = 1;
  1238. /* assume tar format, PharData can specify other */
  1239. mydata->is_tar = 1;
  1240. } else {
  1241. phar_archive_data **fd_ptr;
  1242. if (alias && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
  1243. if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
  1244. if (error) {
  1245. spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
  1246. }
  1247. zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
  1248. if (pphar) {
  1249. *pphar = NULL;
  1250. }
  1251. return FAILURE;
  1252. }
  1253. }
  1254. mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
  1255. mydata->alias_len = alias ? alias_len : fname_len;
  1256. }
  1257. if (alias_len && alias) {
  1258. if (FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL)) {
  1259. if (options & REPORT_ERRORS) {
  1260. if (error) {
  1261. spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
  1262. }
  1263. }
  1264. zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
  1265. if (pphar) {
  1266. *pphar = NULL;
  1267. }
  1268. return FAILURE;
  1269. }
  1270. }
  1271. return SUCCESS;
  1272. }
  1273. /* }}}*/
  1274. /**
  1275. * Return an already opened filename.
  1276. *
  1277. * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify
  1278. * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS
  1279. * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
  1280. */
  1281. int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
  1282. {
  1283. php_stream *fp;
  1284. char *actual;
  1285. int ret, is_data = 0;
  1286. if (error) {
  1287. *error = NULL;
  1288. }
  1289. if (!strstr(fname, ".phar")) {
  1290. is_data = 1;
  1291. }
  1292. if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC) == SUCCESS) {
  1293. return SUCCESS;
  1294. } else if (error && *error) {
  1295. return FAILURE;
  1296. }
  1297. #if PHP_API_VERSION < 20100412
  1298. if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
  1299. return FAILURE;
  1300. }
  1301. #endif
  1302. if (php_check_open_basedir(fname TSRMLS_CC)) {
  1303. return FAILURE;
  1304. }
  1305. fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
  1306. if (!fp) {
  1307. if (options & REPORT_ERRORS) {
  1308. if (error) {
  1309. spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
  1310. }
  1311. }
  1312. if (actual) {
  1313. efree(actual);
  1314. }
  1315. return FAILURE;
  1316. }
  1317. if (actual) {
  1318. fname = actual;
  1319. fname_len = strlen(actual);
  1320. }
  1321. ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC);
  1322. if (actual) {
  1323. efree(actual);
  1324. }
  1325. return ret;
  1326. }
  1327. /* }}}*/
  1328. static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
  1329. {
  1330. const char *c;
  1331. int so_far = 0;
  1332. if (buf_len < search_len) {
  1333. return NULL;
  1334. }
  1335. c = buf - 1;
  1336. do {
  1337. if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
  1338. return (char *) NULL;
  1339. }
  1340. so_far = c - buf;
  1341. if (so_far >= (buf_len - search_len)) {
  1342. return (char *) NULL;
  1343. }
  1344. if (!memcmp(c, search, search_len)) {
  1345. return (char *) c;
  1346. }
  1347. } while (1);
  1348. }
  1349. /* }}} */
  1350. /**
  1351. * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
  1352. * that the manifest is proper, then pass it to phar_parse_pharfile(). SUCCESS
  1353. * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
  1354. */
  1355. static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, int is_data, char **error TSRMLS_DC) /* {{{ */
  1356. {
  1357. const char token[] = "__HALT_COMPILER();";
  1358. const char zip_magic[] = "PK\x03\x04";
  1359. const char gz_magic[] = "\x1f\x8b\x08";
  1360. const char bz_magic[] = "BZh";
  1361. char *pos, test = '\0';
  1362. const int window_size = 1024;
  1363. char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */
  1364. const long readsize = sizeof(buffer) - sizeof(token);
  1365. const long tokenlen = sizeof(token) - 1;
  1366. long halt_offset;
  1367. size_t got;
  1368. php_uint32 compression = PHAR_FILE_COMPRESSED_NONE;
  1369. if (error) {
  1370. *error = NULL;
  1371. }
  1372. if (-1 == php_stream_rewind(fp)) {
  1373. MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
  1374. }
  1375. buffer[sizeof(buffer)-1] = '\0';
  1376. memset(buffer, 32, sizeof(token));
  1377. halt_offset = 0;
  1378. /* Maybe it's better to compile the file instead of just searching, */
  1379. /* but we only want the offset. So we want a .re scanner to find it. */
  1380. while(!php_stream_eof(fp)) {
  1381. if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
  1382. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
  1383. }
  1384. if (!test) {
  1385. test = '\1';
  1386. pos = buffer+tokenlen;
  1387. if (!memcmp(pos, gz_magic, 3)) {
  1388. char err = 0;
  1389. php_stream_filter *filter;
  1390. php_stream *temp;
  1391. /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
  1392. zval filterparams;
  1393. if (!PHAR_G(has_zlib)) {
  1394. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
  1395. }
  1396. array_init(&filterparams);
  1397. /* this is defined in zlib's zconf.h */
  1398. #ifndef MAX_WBITS
  1399. #define MAX_WBITS 15
  1400. #endif
  1401. add_assoc_long(&filterparams, "window", MAX_WBITS + 32);
  1402. /* entire file is gzip-compressed, uncompress to temporary file */
  1403. if (!(temp = php_stream_fopen_tmpfile())) {
  1404. MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
  1405. }
  1406. php_stream_rewind(fp);
  1407. filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
  1408. if (!filter) {
  1409. err = 1;
  1410. add_assoc_long(&filterparams, "window", MAX_WBITS);
  1411. filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
  1412. zval_dtor(&filterparams);
  1413. if (!filter) {
  1414. php_stream_close(temp);
  1415. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
  1416. }
  1417. } else {
  1418. zval_dtor(&filterparams);
  1419. }
  1420. php_stream_filter_append(&temp->writefilters, filter);
  1421. if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
  1422. if (err) {
  1423. php_stream_close(temp);
  1424. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
  1425. }
  1426. php_stream_close(temp);
  1427. MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
  1428. }
  1429. php_stream_filter_flush(filter, 1);
  1430. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  1431. php_stream_close(fp);
  1432. fp = temp;
  1433. php_stream_rewind(fp);
  1434. compression = PHAR_FILE_COMPRESSED_GZ;
  1435. /* now, start over */
  1436. test = '\0';
  1437. continue;
  1438. } else if (!memcmp(pos, bz_magic, 3)) {
  1439. php_stream_filter *filter;
  1440. php_stream *temp;
  1441. if (!PHAR_G(has_bz2)) {
  1442. MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
  1443. }
  1444. /* entire file is bzip-compressed, uncompress to temporary file */
  1445. if (!(temp = php_stream_fopen_tmpfile())) {
  1446. MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
  1447. }
  1448. php_stream_rewind(fp);
  1449. filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
  1450. if (!filter) {
  1451. php_stream_close(temp);
  1452. MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
  1453. }
  1454. php_stream_filter_append(&temp->writefilters, filter);
  1455. if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
  1456. php_stream_close(temp);
  1457. MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
  1458. }
  1459. php_stream_filter_flush(filter, 1);
  1460. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  1461. php_stream_close(fp);
  1462. fp = temp;
  1463. php_stream_rewind(fp);
  1464. compression = PHAR_FILE_COMPRESSED_BZ2;
  1465. /* now, start over */
  1466. test = '\0';
  1467. continue;
  1468. }
  1469. if (!memcmp(pos, zip_magic, 4)) {
  1470. php_stream_seek(fp, 0, SEEK_END);
  1471. return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
  1472. }
  1473. if (got > 512) {
  1474. if (phar_is_tar(pos, fname)) {
  1475. php_stream_rewind(fp);
  1476. return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, is_data, compression, error TSRMLS_CC);
  1477. }
  1478. }
  1479. }
  1480. if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
  1481. halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
  1482. return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
  1483. }
  1484. halt_offset += got;
  1485. memmove(buffer, buffer + window_size, tokenlen); /* move the memory buffer by the size of the window */
  1486. }
  1487. MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
  1488. }
  1489. /* }}} */
  1490. /*
  1491. * given the location of the file extension and the start of the file path,
  1492. * determine the end of the portion of the path (i.e. /path/to/file.ext/blah
  1493. * grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
  1494. * stat it to determine if it exists.
  1495. * if so, check to see if it is a directory and fail if so
  1496. * if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
  1497. * succeed if we are creating the file, otherwise fail.
  1498. */
  1499. static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC) /* {{{ */
  1500. {
  1501. php_stream_statbuf ssb;
  1502. char *realpath;
  1503. char *filename = estrndup(fname, (ext - fname) + ext_len);
  1504. if ((realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
  1505. #ifdef PHP_WIN32
  1506. phar_unixify_path_separators(realpath, strlen(realpath));
  1507. #endif
  1508. if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
  1509. efree(realpath);
  1510. efree(filename);
  1511. return SUCCESS;
  1512. }
  1513. if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) {
  1514. efree(realpath);
  1515. efree(filename);
  1516. return SUCCESS;
  1517. }
  1518. efree(realpath);
  1519. }
  1520. if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) {
  1521. efree(filename);
  1522. if (ssb.sb.st_mode & S_IFDIR) {
  1523. return FAILURE;
  1524. }
  1525. if (for_create == 1) {
  1526. return FAILURE;
  1527. }
  1528. return SUCCESS;
  1529. } else {
  1530. char *slash;
  1531. if (!for_create) {
  1532. efree(filename);
  1533. return FAILURE;
  1534. }
  1535. slash = (char *) strrchr(filename, '/');
  1536. if (slash) {
  1537. *slash = '\0';
  1538. }
  1539. if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) {
  1540. if (!slash) {
  1541. if (!(realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
  1542. efree(filename);
  1543. return FAILURE;
  1544. }
  1545. #ifdef PHP_WIN32
  1546. phar_unixify_path_separators(realpath, strlen(realpath));
  1547. #endif
  1548. slash = strstr(realpath, filename);
  1549. if (slash) {
  1550. slash += ((ext - fname) + ext_len);
  1551. *slash = '\0';
  1552. }
  1553. slash = strrchr(realpath, '/');
  1554. if (slash) {
  1555. *slash = '\0';
  1556. } else {
  1557. efree(realpath);
  1558. efree(filename);
  1559. return FAILURE;
  1560. }
  1561. if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
  1562. efree(realpath);
  1563. efree(filename);
  1564. return FAILURE;
  1565. }
  1566. efree(realpath);
  1567. if (ssb.sb.st_mode & S_IFDIR) {
  1568. efree(filename);
  1569. return SUCCESS;
  1570. }
  1571. }
  1572. efree(filename);
  1573. return FAILURE;
  1574. }
  1575. efree(filename);
  1576. if (ssb.sb.st_mode & S_IFDIR) {
  1577. return SUCCESS;
  1578. }
  1579. return FAILURE;
  1580. }
  1581. }
  1582. /* }}} */
  1583. /* check for ".phar" in extension */
  1584. static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC) /* {{{ */
  1585. {
  1586. char test[51];
  1587. const char *pos;
  1588. if (ext_len >= 50) {
  1589. return FAILURE;
  1590. }
  1591. if (executable == 1) {
  1592. /* copy "." as well */
  1593. memcpy(test, ext_str - 1, ext_len + 1);
  1594. test[ext_len + 1] = '\0';
  1595. /* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
  1596. /* (phar://hi/there/.phar/oops is also invalid) */
  1597. pos = strstr(test, ".phar");
  1598. if (pos && (*(pos - 1) != '/')
  1599. && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
  1600. return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
  1601. } else {
  1602. return FAILURE;
  1603. }
  1604. }
  1605. /* data phars need only contain a single non-"." to be valid */
  1606. if (!executable) {
  1607. pos = strstr(ext_str, ".phar");
  1608. if (!(pos && (*(pos - 1) != '/')
  1609. && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
  1610. return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
  1611. }
  1612. } else {
  1613. if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
  1614. return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
  1615. }
  1616. }
  1617. return FAILURE;
  1618. }
  1619. /* }}} */
  1620. /*
  1621. * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
  1622. * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
  1623. * the first extension as the filename extension
  1624. *
  1625. * if an extension is found, it sets ext_str to the location of the file extension in filename,
  1626. * and ext_len to the length of the extension.
  1627. * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
  1628. * the calling function to use "alias" as the phar alias
  1629. *
  1630. * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
  1631. * extension rules, not to iterate.
  1632. */
  1633. int phar_detect_phar_fname_ext(const char *filename, int filename_len, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC) /* {{{ */
  1634. {
  1635. const char *pos, *slash;
  1636. *ext_str = NULL;
  1637. *ext_len = 0;
  1638. if (!filename_len || filename_len == 1) {
  1639. return FAILURE;
  1640. }
  1641. phar_request_initialize(TSRMLS_C);
  1642. /* first check for alias in first segment */
  1643. pos = memchr(filename, '/', filename_len);
  1644. if (pos && pos != filename) {
  1645. /* check for url like http:// or phar:// */
  1646. if (*(pos - 1) == ':' && (pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
  1647. *ext_len = -2;
  1648. *ext_str = NULL;
  1649. return FAILURE;
  1650. }
  1651. if (zend_hash_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
  1652. *ext_str = pos;
  1653. *ext_len = -1;
  1654. return FAILURE;
  1655. }
  1656. if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_alias, (char *) filename, pos - filename)) {
  1657. *ext_str = pos;
  1658. *ext_len = -1;
  1659. return FAILURE;
  1660. }
  1661. }
  1662. if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
  1663. phar_archive_data **pphar;
  1664. if (is_complete) {
  1665. if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len, (void **)&pphar)) {
  1666. *ext_str = filename + (filename_len - (*pphar)->ext_len);
  1667. woohoo:
  1668. *ext_len = (*pphar)->ext_len;
  1669. if (executable == 2) {
  1670. return SUCCESS;
  1671. }
  1672. if (executable == 1 && !(*pphar)->is_data) {
  1673. return SUCCESS;
  1674. }
  1675. if (!executable && (*pphar)->is_data) {
  1676. return SUCCESS;
  1677. }
  1678. return FAILURE;
  1679. }
  1680. if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, (char *) filename, filename_len, (void **)&pphar)) {
  1681. *ext_str = filename + (filename_len - (*pphar)->ext_len);
  1682. goto woohoo;
  1683. }
  1684. } else {
  1685. char *str_key;
  1686. uint keylen;
  1687. ulong unused;
  1688. for (zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
  1689. HASH_KEY_NON_EXISTENT != zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &str_key, &keylen, &unused, 0, NULL);
  1690. zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map))
  1691. ) {
  1692. if (keylen > (uint) filename_len) {
  1693. continue;
  1694. }
  1695. if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
  1696. || filename[keylen] == '/' || filename[keylen] == '\0')) {
  1697. if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) {
  1698. break;
  1699. }
  1700. *ext_str = filename + (keylen - (*pphar)->ext_len);
  1701. goto woohoo;
  1702. }
  1703. }
  1704. if (PHAR_G(manifest_cached)) {
  1705. for (zend_hash_internal_pointer_reset(&cached_phars);
  1706. HASH_KEY_NON_EXISTENT != zend_hash_get_current_key_ex(&cached_phars, &str_key, &keylen, &unused, 0, NULL);
  1707. zend_hash_move_forward(&cached_phars)
  1708. ) {
  1709. if (keylen > (uint) filename_len) {
  1710. continue;
  1711. }
  1712. if (!memcmp(filename, str_key, keylen) && ((uint)filename_len == keylen
  1713. || filename[keylen] == '/' || filename[keylen] == '\0')) {
  1714. if (FAILURE == zend_hash_get_current_data(&cached_phars, (void **) &pphar)) {
  1715. break;
  1716. }
  1717. *ext_str = filename + (keylen - (*pphar)->ext_len);
  1718. goto woohoo;
  1719. }
  1720. }
  1721. }
  1722. }
  1723. }
  1724. pos = memchr(filename + 1, '.', filename_len);
  1725. next_extension:
  1726. if (!pos) {
  1727. return FAILURE;
  1728. }
  1729. while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
  1730. pos = memchr(pos + 1, '.', filename_len - (pos - filename) - 1);
  1731. if (!pos) {
  1732. return FAILURE;
  1733. }
  1734. }
  1735. slash = memchr(pos, '/', filename_len - (pos - filename));
  1736. if (!slash) {
  1737. /* this is a url like "phar://blah.phar" with no directory */
  1738. *ext_str = pos;
  1739. *ext_len = strlen(pos);
  1740. /* file extension must contain "phar" */
  1741. switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
  1742. case SUCCESS:
  1743. return SUCCESS;
  1744. case FAILURE:
  1745. /* we are at the end of the string, so we fail */
  1746. return FAILURE;
  1747. }
  1748. }
  1749. /* we've found an extension that ends at a directory separator */
  1750. *ext_str = pos;
  1751. *ext_len = slash - pos;
  1752. switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
  1753. case SUCCESS:
  1754. return SUCCESS;
  1755. case FAILURE:
  1756. /* look for more extensions */
  1757. pos = strchr(pos + 1, '.');
  1758. if (pos) {
  1759. *ext_str = NULL;
  1760. *ext_len = 0;
  1761. }
  1762. goto next_extension;
  1763. }
  1764. return FAILURE;
  1765. }
  1766. /* }}} */
  1767. static int php_check_dots(const char *element, int n) /* {{{ */
  1768. {
  1769. for(n--; n >= 0; --n) {
  1770. if (element[n] != '.') {
  1771. return 1;
  1772. }
  1773. }
  1774. return 0;
  1775. }
  1776. /* }}} */
  1777. #define IS_DIRECTORY_UP(element, len) \
  1778. (len >= 2 && !php_check_dots(element, len))
  1779. #define IS_DIRECTORY_CURRENT(element, len) \
  1780. (len == 1 && element[0] == '.')
  1781. #define IS_BACKSLASH(c) ((c) == '/')
  1782. #ifdef COMPILE_DL_PHAR
  1783. /* stupid-ass non-extern declaration in tsrm_strtok.h breaks dumbass MS compiler */
  1784. static inline int in_character_class(char ch, const char *delim) /* {{{ */
  1785. {
  1786. while (*delim) {
  1787. if (*delim == ch) {
  1788. return 1;
  1789. }
  1790. ++delim;
  1791. }
  1792. return 0;
  1793. }
  1794. /* }}} */
  1795. char *tsrm_strtok_r(char *s, const char *delim, char **last) /* {{{ */
  1796. {
  1797. char *token;
  1798. if (s == NULL) {
  1799. s = *last;
  1800. }
  1801. while (*s && in_character_class(*s, delim)) {
  1802. ++s;
  1803. }
  1804. if (!*s) {
  1805. return NULL;
  1806. }
  1807. token = s;
  1808. while (*s && !in_character_class(*s, delim)) {
  1809. ++s;
  1810. }
  1811. if (!*s) {
  1812. *last = s;
  1813. } else {
  1814. *s = '\0';
  1815. *last = s + 1;
  1816. }
  1817. return token;
  1818. }
  1819. /* }}} */
  1820. #endif
  1821. /**
  1822. * Remove .. and . references within a phar filename
  1823. */
  1824. char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
  1825. {
  1826. char *newpath;
  1827. int newpath_len;
  1828. char *ptr;
  1829. char *tok;
  1830. int ptr_length, path_length = *new_len;
  1831. if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
  1832. newpath_len = PHAR_G(cwd_len);
  1833. newpath = emalloc(strlen(path) + newpath_len + 1);
  1834. memcpy(newpath, PHAR_G(cwd), newpath_len);
  1835. } else {
  1836. newpath = emalloc(strlen(path) + 2);
  1837. newpath[0] = '/';
  1838. newpath_len = 1;
  1839. }
  1840. ptr = path;
  1841. if (*ptr == '/') {
  1842. ++ptr;
  1843. }
  1844. tok = ptr;
  1845. do {
  1846. ptr = memchr(ptr, '/', path_length - (ptr - path));
  1847. } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
  1848. if (!ptr && (path_length - (tok - path))) {
  1849. switch (path_length - (tok - path)) {
  1850. case 1:
  1851. if (*tok == '.') {
  1852. efree(path);
  1853. *new_len = 1;
  1854. efree(newpath);
  1855. return estrndup("/", 1);
  1856. }
  1857. break;
  1858. case 2:
  1859. if (tok[0] == '.' && tok[1] == '.') {
  1860. efree(path);
  1861. *new_len = 1;
  1862. efree(newpath);
  1863. return estrndup("/", 1);
  1864. }
  1865. }
  1866. efree(newpath);
  1867. return path;
  1868. }
  1869. while (ptr) {
  1870. ptr_length = ptr - tok;
  1871. last_time:
  1872. if (IS_DIRECTORY_UP(tok, ptr_length)) {
  1873. #define PREVIOUS newpath[newpath_len - 1]
  1874. while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
  1875. newpath_len--;
  1876. }
  1877. if (newpath[0] != '/') {
  1878. newpath[newpath_len] = '\0';
  1879. } else if (newpath_len > 1) {
  1880. --newpath_len;
  1881. }
  1882. } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
  1883. if (newpath_len > 1) {
  1884. newpath[newpath_len++] = '/';
  1885. memcpy(newpath + newpath_len, tok, ptr_length+1);
  1886. } else {
  1887. memcpy(newpath + newpath_len, tok, ptr_length+1);
  1888. }
  1889. newpath_len += ptr_length;
  1890. }
  1891. if (ptr == path + path_length) {
  1892. break;
  1893. }
  1894. tok = ++ptr;
  1895. do {
  1896. ptr = memchr(ptr, '/', path_length - (ptr - path));
  1897. } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
  1898. if (!ptr && (path_length - (tok - path))) {
  1899. ptr_length = path_length - (tok - path);
  1900. ptr = path + path_length;
  1901. goto last_time;
  1902. }
  1903. }
  1904. efree(path);
  1905. *new_len = newpath_len;
  1906. newpath[newpath_len] = '\0';
  1907. return erealloc(newpath, newpath_len + 1);
  1908. }
  1909. /* }}} */
  1910. /**
  1911. * Process a phar stream name, ensuring we can handle any of:
  1912. *
  1913. * - whatever.phar
  1914. * - whatever.phar.gz
  1915. * - whatever.phar.bz2
  1916. * - whatever.phar.php
  1917. *
  1918. * Optionally the name might start with 'phar://'
  1919. *
  1920. * This is used by phar_parse_url()
  1921. */
  1922. int phar_split_fname(const char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC) /* {{{ */
  1923. {
  1924. const char *ext_str;
  1925. #ifdef PHP_WIN32
  1926. char *save;
  1927. #endif
  1928. int ext_len;
  1929. if (CHECK_NULL_PATH(filename, filename_len)) {
  1930. return FAILURE;
  1931. }
  1932. if (!strncasecmp(filename, "phar://", 7)) {
  1933. filename += 7;
  1934. filename_len -= 7;
  1935. }
  1936. ext_len = 0;
  1937. #ifdef PHP_WIN32
  1938. save = filename;
  1939. filename = estrndup(filename, filename_len);
  1940. phar_unixify_path_separators(filename, filename_len);
  1941. #endif
  1942. if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
  1943. if (ext_len != -1) {
  1944. if (!ext_str) {
  1945. /* no / detected, restore arch for error message */
  1946. #ifdef PHP_WIN32
  1947. *arch = save;
  1948. #else
  1949. *arch = filename;
  1950. #endif
  1951. }
  1952. #ifdef PHP_WIN32
  1953. efree(filename);
  1954. #endif
  1955. return FAILURE;
  1956. }
  1957. ext_len = 0;
  1958. /* no extension detected - instead we are dealing with an alias */
  1959. }
  1960. *arch_len = ext_str - filename + ext_len;
  1961. *arch = estrndup(filename, *arch_len);
  1962. if (ext_str[ext_len]) {
  1963. *entry_len = filename_len - *arch_len;
  1964. *entry = estrndup(ext_str+ext_len, *entry_len);
  1965. #ifdef PHP_WIN32
  1966. phar_unixify_path_separators(*entry, *entry_len);
  1967. #endif
  1968. *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC);
  1969. } else {
  1970. *entry_len = 1;
  1971. *entry = estrndup("/", 1);
  1972. }
  1973. #ifdef PHP_WIN32
  1974. efree(filename);
  1975. #endif
  1976. return SUCCESS;
  1977. }
  1978. /* }}} */
  1979. /**
  1980. * Invoked when a user calls Phar::mapPhar() from within an executing .phar
  1981. * to set up its manifest directly
  1982. */
  1983. int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
  1984. {
  1985. char *fname;
  1986. zval *halt_constant;
  1987. php_stream *fp;
  1988. int fname_len;
  1989. char *actual = NULL;
  1990. int ret;
  1991. if (error) {
  1992. *error = NULL;
  1993. }
  1994. fname = (char*)zend_get_executed_filename(TSRMLS_C);
  1995. fname_len = strlen(fname);
  1996. if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
  1997. return SUCCESS;
  1998. }
  1999. if (!strcmp(fname, "[no active file]")) {
  2000. if (error) {
  2001. spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
  2002. }
  2003. return FAILURE;
  2004. }
  2005. MAKE_STD_ZVAL(halt_constant);
  2006. if (0 == zend_get_constant("__COMPILER_HALT_OFFSET__", 24, halt_constant TSRMLS_CC)) {
  2007. FREE_ZVAL(halt_constant);
  2008. if (error) {
  2009. spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
  2010. }
  2011. return FAILURE;
  2012. }
  2013. FREE_ZVAL(halt_constant);
  2014. #if PHP_API_VERSION < 20100412
  2015. if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
  2016. return FAILURE;
  2017. }
  2018. #endif
  2019. if (php_check_open_basedir(fname TSRMLS_CC)) {
  2020. return FAILURE;
  2021. }
  2022. fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
  2023. if (!fp) {
  2024. if (error) {
  2025. spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
  2026. }
  2027. if (actual) {
  2028. efree(actual);
  2029. }
  2030. return FAILURE;
  2031. }
  2032. if (actual) {
  2033. fname = actual;
  2034. fname_len = strlen(actual);
  2035. }
  2036. ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error TSRMLS_CC);
  2037. if (actual) {
  2038. efree(actual);
  2039. }
  2040. return ret;
  2041. }
  2042. /* }}} */
  2043. /**
  2044. * Validate the CRC32 of a file opened from within the phar
  2045. */
  2046. int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC) /* {{{ */
  2047. {
  2048. php_uint32 crc = ~0;
  2049. int len = idata->internal_file->uncompressed_filesize;
  2050. php_stream *fp = idata->fp;
  2051. phar_entry_info *entry = idata->internal_file;
  2052. if (error) {
  2053. *error = NULL;
  2054. }
  2055. if (entry->is_zip && process_zip > 0) {
  2056. /* verify local file header */
  2057. phar_zip_file_header local;
  2058. phar_zip_data_desc desc;
  2059. if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) {
  2060. spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
  2061. return FAILURE;
  2062. }
  2063. php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
  2064. if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
  2065. spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
  2066. return FAILURE;
  2067. }
  2068. /* check for data descriptor */
  2069. if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
  2070. php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
  2071. entry->header_offset + sizeof(local) +
  2072. PHAR_ZIP_16(local.filename_len) +
  2073. PHAR_ZIP_16(local.extra_len) +
  2074. entry->compressed_filesize, SEEK_SET);
  2075. if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
  2076. (char *) &desc, sizeof(desc))) {
  2077. spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, entry->filename);
  2078. return FAILURE;
  2079. }
  2080. if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
  2081. memcpy(&(local.crc32), &(desc.crc32), 12);
  2082. } else {
  2083. /* old data descriptors have no signature */
  2084. memcpy(&(local.crc32), &desc, 12);
  2085. }
  2086. }
  2087. /* verify local header */
  2088. if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) {
  2089. spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
  2090. return FAILURE;
  2091. }
  2092. /* construct actual offset to file start - local extra_len can be different from central extra_len */
  2093. entry->offset = entry->offset_abs =
  2094. sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
  2095. if (idata->zero && idata->zero != entry->offset_abs) {
  2096. idata->zero = entry->offset_abs;
  2097. }
  2098. }
  2099. if (process_zip == 1) {
  2100. return SUCCESS;
  2101. }
  2102. php_stream_seek(fp, idata->zero, SEEK_SET);
  2103. while (len--) {
  2104. CRC32(crc, php_stream_getc(fp));
  2105. }
  2106. php_stream_seek(fp, idata->zero, SEEK_SET);
  2107. if (~crc == crc32) {
  2108. entry->is_crc_checked = 1;
  2109. return SUCCESS;
  2110. } else {
  2111. spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
  2112. return FAILURE;
  2113. }
  2114. }
  2115. /* }}} */
  2116. static inline void phar_set_32(char *buffer, int var) /* {{{ */
  2117. {
  2118. #ifdef WORDS_BIGENDIAN
  2119. *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
  2120. *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
  2121. *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
  2122. *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
  2123. #else
  2124. memcpy(buffer, &var, sizeof(var));
  2125. #endif
  2126. } /* }}} */
  2127. static int phar_flush_clean_deleted_apply(void *data TSRMLS_DC) /* {{{ */
  2128. {
  2129. phar_entry_info *entry = (phar_entry_info *)data;
  2130. if (entry->fp_refcount <= 0 && entry->is_deleted) {
  2131. return ZEND_HASH_APPLY_REMOVE;
  2132. } else {
  2133. return ZEND_HASH_APPLY_KEEP;
  2134. }
  2135. }
  2136. /* }}} */
  2137. #include "stub.h"
  2138. char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) /* {{{ */
  2139. {
  2140. char *stub = NULL;
  2141. int index_len, web_len;
  2142. size_t dummy;
  2143. if (!len) {
  2144. len = &dummy;
  2145. }
  2146. if (error) {
  2147. *error = NULL;
  2148. }
  2149. if (!index_php) {
  2150. index_php = "index.php";
  2151. }
  2152. if (!web_index) {
  2153. web_index = "index.php";
  2154. }
  2155. index_len = strlen(index_php);
  2156. web_len = strlen(web_index);
  2157. if (index_len > 400) {
  2158. /* ridiculous size not allowed for index.php startup filename */
  2159. if (error) {
  2160. spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
  2161. return NULL;
  2162. }
  2163. }
  2164. if (web_len > 400) {
  2165. /* ridiculous size not allowed for index.php startup filename */
  2166. if (error) {
  2167. spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
  2168. return NULL;
  2169. }
  2170. }
  2171. phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
  2172. return stub;
  2173. }
  2174. /* }}} */
  2175. /**
  2176. * Save phar contents to disk
  2177. *
  2178. * user_stub contains either a string, or a resource pointer, if len is a negative length.
  2179. * user_stub and len should be both 0 if the default or existing stub should be used
  2180. */
  2181. int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert, char **error TSRMLS_DC) /* {{{ */
  2182. {
  2183. char halt_stub[] = "__HALT_COMPILER();";
  2184. char *newstub, *tmp;
  2185. phar_entry_info *entry, *newentry;
  2186. int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
  2187. char *pos, has_dirs = 0;
  2188. char manifest[18], entry_buffer[24];
  2189. off_t manifest_ftell;
  2190. long offset;
  2191. size_t wrote;
  2192. php_uint32 manifest_len, mytime, loc, new_manifest_count;
  2193. php_uint32 newcrc32;
  2194. php_stream *file, *oldfile, *newfile, *stubfile;
  2195. php_stream_filter *filter;
  2196. php_serialize_data_t metadata_hash;
  2197. smart_str main_metadata_str = {0};
  2198. int free_user_stub, free_fp = 1, free_ufp = 1;
  2199. int manifest_hack = 0;
  2200. if (phar->is_persistent) {
  2201. if (error) {
  2202. spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
  2203. }
  2204. return EOF;
  2205. }
  2206. if (error) {
  2207. *error = NULL;
  2208. }
  2209. if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
  2210. return EOF;
  2211. }
  2212. zend_hash_clean(&phar->virtual_dirs);
  2213. if (phar->is_zip) {
  2214. return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
  2215. }
  2216. if (phar->is_tar) {
  2217. return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
  2218. }
  2219. if (PHAR_G(readonly)) {
  2220. return EOF;
  2221. }
  2222. if (phar->fp && !phar->is_brandnew) {
  2223. oldfile = phar->fp;
  2224. closeoldfile = 0;
  2225. php_stream_rewind(oldfile);
  2226. } else {
  2227. oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
  2228. closeoldfile = oldfile != NULL;
  2229. }
  2230. newfile = php_stream_fopen_tmpfile();
  2231. if (!newfile) {
  2232. if (error) {
  2233. spprintf(error, 0, "unable to create temporary file");
  2234. }
  2235. if (closeoldfile) {
  2236. php_stream_close(oldfile);
  2237. }
  2238. return EOF;
  2239. }
  2240. if (user_stub) {
  2241. if (len < 0) {
  2242. /* resource passed in */
  2243. if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) {
  2244. if (closeoldfile) {
  2245. php_stream_close(oldfile);
  2246. }
  2247. php_stream_close(newfile);
  2248. if (error) {
  2249. spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
  2250. }
  2251. return EOF;
  2252. }
  2253. if (len == -1) {
  2254. len = PHP_STREAM_COPY_ALL;
  2255. } else {
  2256. len = -len;
  2257. }
  2258. user_stub = 0;
  2259. if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
  2260. if (closeoldfile) {
  2261. php_stream_close(oldfile);
  2262. }
  2263. php_stream_close(newfile);
  2264. if (error) {
  2265. spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
  2266. }
  2267. return EOF;
  2268. }
  2269. free_user_stub = 1;
  2270. } else {
  2271. free_user_stub = 0;
  2272. }
  2273. tmp = estrndup(user_stub, len);
  2274. if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
  2275. efree(tmp);
  2276. if (closeoldfile) {
  2277. php_stream_close(oldfile);
  2278. }
  2279. php_stream_close(newfile);
  2280. if (error) {
  2281. spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
  2282. }
  2283. if (free_user_stub) {
  2284. efree(user_stub);
  2285. }
  2286. return EOF;
  2287. }
  2288. pos = user_stub + (pos - tmp);
  2289. efree(tmp);
  2290. len = pos - user_stub + 18;
  2291. if ((size_t)len != php_stream_write(newfile, user_stub, len)
  2292. || 5 != php_stream_write(newfile, " ?>\r\n", 5)) {
  2293. if (closeoldfile) {
  2294. php_stream_close(oldfile);
  2295. }
  2296. php_stream_close(newfile);
  2297. if (error) {
  2298. spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
  2299. }
  2300. if (free_user_stub) {
  2301. efree(user_stub);
  2302. }
  2303. return EOF;
  2304. }
  2305. phar->halt_offset = len + 5;
  2306. if (free_user_stub) {
  2307. efree(user_stub);
  2308. }
  2309. } else {
  2310. size_t written;
  2311. if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
  2312. php_stream_copy_to_stream_ex(oldfile, newfile, phar->halt_offset, &written);
  2313. newstub = NULL;
  2314. } else {
  2315. /* this is either a brand new phar or a default stub overwrite */
  2316. newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC);
  2317. written = php_stream_write(newfile, newstub, phar->halt_offset);
  2318. }
  2319. if (phar->halt_offset != written) {
  2320. if (closeoldfile) {
  2321. php_stream_close(oldfile);
  2322. }
  2323. php_stream_close(newfile);
  2324. if (error) {
  2325. if (newstub) {
  2326. spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
  2327. } else {
  2328. spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
  2329. }
  2330. }
  2331. if (newstub) {
  2332. efree(newstub);
  2333. }
  2334. return EOF;
  2335. }
  2336. if (newstub) {
  2337. efree(newstub);
  2338. }
  2339. }
  2340. manifest_ftell = php_stream_tell(newfile);
  2341. halt_offset = manifest_ftell;
  2342. /* Check whether we can get rid of some of the deleted entries which are
  2343. * unused. However some might still be in use so even after this clean-up
  2344. * we need to skip entries marked is_deleted. */
  2345. zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
  2346. /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
  2347. main_metadata_str.c = 0;
  2348. if (phar->metadata) {
  2349. PHP_VAR_SERIALIZE_INIT(metadata_hash);
  2350. php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
  2351. PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
  2352. } else {
  2353. main_metadata_str.len = 0;
  2354. }
  2355. new_manifest_count = 0;
  2356. offset = 0;
  2357. for (zend_hash_internal_pointer_reset(&phar->manifest);
  2358. zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
  2359. zend_hash_move_forward(&phar->manifest)) {
  2360. if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
  2361. continue;
  2362. }
  2363. if (entry->cfp) {
  2364. /* did we forget to get rid of cfp last time? */
  2365. php_stream_close(entry->cfp);
  2366. entry->cfp = 0;
  2367. }
  2368. if (entry->is_deleted || entry->is_mounted) {
  2369. /* remove this from the new phar */
  2370. continue;
  2371. }
  2372. if (!entry->is_modified && entry->fp_refcount) {
  2373. /* open file pointers refer to this fp, do not free the stream */
  2374. switch (entry->fp_type) {
  2375. case PHAR_FP:
  2376. free_fp = 0;
  2377. break;
  2378. case PHAR_UFP:
  2379. free_ufp = 0;
  2380. default:
  2381. break;
  2382. }
  2383. }
  2384. /* after excluding deleted files, calculate manifest size in bytes and number of entries */
  2385. ++new_manifest_count;
  2386. phar_add_virtual_dirs(phar, entry->filename, entry->filename_len TSRMLS_CC);
  2387. if (entry->is_dir) {
  2388. /* we use this to calculate API version, 1.1.1 is used for phars with directories */
  2389. has_dirs = 1;
  2390. }
  2391. if (entry->metadata) {
  2392. if (entry->metadata_str.c) {
  2393. smart_str_free(&entry->metadata_str);
  2394. }
  2395. entry->metadata_str.c = 0;
  2396. entry->metadata_str.len = 0;
  2397. PHP_VAR_SERIALIZE_INIT(metadata_hash);
  2398. php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
  2399. PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
  2400. } else {
  2401. if (entry->metadata_str.c) {
  2402. smart_str_free(&entry->metadata_str);
  2403. }
  2404. entry->metadata_str.c = 0;
  2405. entry->metadata_str.len = 0;
  2406. }
  2407. /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
  2408. offset += 4 + entry->filename_len + sizeof(entry_buffer) + entry->metadata_str.len + (entry->is_dir ? 1 : 0);
  2409. /* compress and rehash as necessary */
  2410. if ((oldfile && !entry->is_modified) || entry->is_dir) {
  2411. if (entry->fp_type == PHAR_UFP) {
  2412. /* reset so we can copy the compressed data over */
  2413. entry->fp_type = PHAR_FP;
  2414. }
  2415. continue;
  2416. }
  2417. if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
  2418. /* re-open internal file pointer just-in-time */
  2419. newentry = phar_open_jit(phar, entry, error TSRMLS_CC);
  2420. if (!newentry) {
  2421. /* major problem re-opening, so we ignore this file and the error */
  2422. efree(*error);
  2423. *error = NULL;
  2424. continue;
  2425. }
  2426. entry = newentry;
  2427. }
  2428. file = phar_get_efp(entry, 0 TSRMLS_CC);
  2429. if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
  2430. if (closeoldfile) {
  2431. php_stream_close(oldfile);
  2432. }
  2433. php_stream_close(newfile);
  2434. if (error) {
  2435. spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
  2436. }
  2437. return EOF;
  2438. }
  2439. newcrc32 = ~0;
  2440. mytime = entry->uncompressed_filesize;
  2441. for (loc = 0;loc < mytime; ++loc) {
  2442. CRC32(newcrc32, php_stream_getc(file));
  2443. }
  2444. entry->crc32 = ~newcrc32;
  2445. entry->is_crc_checked = 1;
  2446. if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
  2447. /* not compressed */
  2448. entry->compressed_filesize = entry->uncompressed_filesize;
  2449. continue;
  2450. }
  2451. filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
  2452. if (!filter) {
  2453. if (closeoldfile) {
  2454. php_stream_close(oldfile);
  2455. }
  2456. php_stream_close(newfile);
  2457. if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
  2458. if (error) {
  2459. spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
  2460. }
  2461. } else {
  2462. if (error) {
  2463. spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
  2464. }
  2465. }
  2466. return EOF;
  2467. }
  2468. /* create new file that holds the compressed version */
  2469. /* work around inability to specify freedom in write and strictness
  2470. in read count */
  2471. entry->cfp = php_stream_fopen_tmpfile();
  2472. if (!entry->cfp) {
  2473. if (error) {
  2474. spprintf(error, 0, "unable to create temporary file");
  2475. }
  2476. if (closeoldfile) {
  2477. php_stream_close(oldfile);
  2478. }
  2479. php_stream_close(newfile);
  2480. return EOF;
  2481. }
  2482. php_stream_flush(file);
  2483. if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
  2484. if (closeoldfile) {
  2485. php_stream_close(oldfile);
  2486. }
  2487. php_stream_close(newfile);
  2488. if (error) {
  2489. spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
  2490. }
  2491. return EOF;
  2492. }
  2493. php_stream_filter_append((&entry->cfp->writefilters), filter);
  2494. if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
  2495. if (closeoldfile) {
  2496. php_stream_close(oldfile);
  2497. }
  2498. php_stream_close(newfile);
  2499. if (error) {
  2500. spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
  2501. }
  2502. return EOF;
  2503. }
  2504. php_stream_filter_flush(filter, 1);
  2505. php_stream_flush(entry->cfp);
  2506. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  2507. php_stream_seek(entry->cfp, 0, SEEK_END);
  2508. entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
  2509. /* generate crc on compressed file */
  2510. php_stream_rewind(entry->cfp);
  2511. entry->old_flags = entry->flags;
  2512. entry->is_modified = 1;
  2513. global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
  2514. }
  2515. global_flags |= PHAR_HDR_SIGNATURE;
  2516. /* write out manifest pre-header */
  2517. /* 4: manifest length
  2518. * 4: manifest entry count
  2519. * 2: phar version
  2520. * 4: phar global flags
  2521. * 4: alias length
  2522. * ?: the alias itself
  2523. * 4: phar metadata length
  2524. * ?: phar metadata
  2525. */
  2526. restore_alias_len = phar->alias_len;
  2527. if (phar->is_temporary_alias) {
  2528. phar->alias_len = 0;
  2529. }
  2530. manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
  2531. phar_set_32(manifest, manifest_len);
  2532. /* Hack - see bug #65028, add padding byte to the end of the manifest */
  2533. if(manifest[0] == '\r' || manifest[0] == '\n') {
  2534. manifest_len++;
  2535. phar_set_32(manifest, manifest_len);
  2536. manifest_hack = 1;
  2537. }
  2538. phar_set_32(manifest+4, new_manifest_count);
  2539. if (has_dirs) {
  2540. *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
  2541. *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
  2542. } else {
  2543. *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
  2544. *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
  2545. }
  2546. phar_set_32(manifest+10, global_flags);
  2547. phar_set_32(manifest+14, phar->alias_len);
  2548. /* write the manifest header */
  2549. if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
  2550. || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
  2551. if (closeoldfile) {
  2552. php_stream_close(oldfile);
  2553. }
  2554. php_stream_close(newfile);
  2555. phar->alias_len = restore_alias_len;
  2556. if (error) {
  2557. spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
  2558. }
  2559. return EOF;
  2560. }
  2561. phar->alias_len = restore_alias_len;
  2562. phar_set_32(manifest, main_metadata_str.len);
  2563. if (4 != php_stream_write(newfile, manifest, 4) || (main_metadata_str.len
  2564. && main_metadata_str.len != php_stream_write(newfile, main_metadata_str.c, main_metadata_str.len))) {
  2565. smart_str_free(&main_metadata_str);
  2566. if (closeoldfile) {
  2567. php_stream_close(oldfile);
  2568. }
  2569. php_stream_close(newfile);
  2570. phar->alias_len = restore_alias_len;
  2571. if (error) {
  2572. spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
  2573. }
  2574. return EOF;
  2575. }
  2576. smart_str_free(&main_metadata_str);
  2577. /* re-calculate the manifest location to simplify later code */
  2578. manifest_ftell = php_stream_tell(newfile);
  2579. /* now write the manifest */
  2580. for (zend_hash_internal_pointer_reset(&phar->manifest);
  2581. zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
  2582. zend_hash_move_forward(&phar->manifest)) {
  2583. if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
  2584. continue;
  2585. }
  2586. if (entry->is_deleted || entry->is_mounted) {
  2587. /* remove this from the new phar if deleted, ignore if mounted */
  2588. continue;
  2589. }
  2590. if (entry->is_dir) {
  2591. /* add 1 for trailing slash */
  2592. phar_set_32(entry_buffer, entry->filename_len + 1);
  2593. } else {
  2594. phar_set_32(entry_buffer, entry->filename_len);
  2595. }
  2596. if (4 != php_stream_write(newfile, entry_buffer, 4)
  2597. || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
  2598. || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
  2599. if (closeoldfile) {
  2600. php_stream_close(oldfile);
  2601. }
  2602. php_stream_close(newfile);
  2603. if (error) {
  2604. if (entry->is_dir) {
  2605. spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
  2606. } else {
  2607. spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
  2608. }
  2609. }
  2610. return EOF;
  2611. }
  2612. /* set the manifest meta-data:
  2613. 4: uncompressed filesize
  2614. 4: creation timestamp
  2615. 4: compressed filesize
  2616. 4: crc32
  2617. 4: flags
  2618. 4: metadata-len
  2619. +: metadata
  2620. */
  2621. mytime = time(NULL);
  2622. phar_set_32(entry_buffer, entry->uncompressed_filesize);
  2623. phar_set_32(entry_buffer+4, mytime);
  2624. phar_set_32(entry_buffer+8, entry->compressed_filesize);
  2625. phar_set_32(entry_buffer+12, entry->crc32);
  2626. phar_set_32(entry_buffer+16, entry->flags);
  2627. phar_set_32(entry_buffer+20, entry->metadata_str.len);
  2628. if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
  2629. || entry->metadata_str.len != php_stream_write(newfile, entry->metadata_str.c, entry->metadata_str.len)) {
  2630. if (closeoldfile) {
  2631. php_stream_close(oldfile);
  2632. }
  2633. php_stream_close(newfile);
  2634. if (error) {
  2635. spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
  2636. }
  2637. return EOF;
  2638. }
  2639. }
  2640. /* Hack - see bug #65028, add padding byte to the end of the manifest */
  2641. if(manifest_hack) {
  2642. if(1 != php_stream_write(newfile, manifest, 1)) {
  2643. if (closeoldfile) {
  2644. php_stream_close(oldfile);
  2645. }
  2646. php_stream_close(newfile);
  2647. if (error) {
  2648. spprintf(error, 0, "unable to write manifest padding byte");
  2649. }
  2650. return EOF;
  2651. }
  2652. }
  2653. /* now copy the actual file data to the new phar */
  2654. offset = php_stream_tell(newfile);
  2655. for (zend_hash_internal_pointer_reset(&phar->manifest);
  2656. zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
  2657. zend_hash_move_forward(&phar->manifest)) {
  2658. if (zend_hash_get_current_data(&phar->manifest, (void **)&entry) == FAILURE) {
  2659. continue;
  2660. }
  2661. if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
  2662. continue;
  2663. }
  2664. if (entry->cfp) {
  2665. file = entry->cfp;
  2666. php_stream_rewind(file);
  2667. } else {
  2668. file = phar_get_efp(entry, 0 TSRMLS_CC);
  2669. if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
  2670. if (closeoldfile) {
  2671. php_stream_close(oldfile);
  2672. }
  2673. php_stream_close(newfile);
  2674. if (error) {
  2675. spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
  2676. }
  2677. return EOF;
  2678. }
  2679. }
  2680. if (!file) {
  2681. if (closeoldfile) {
  2682. php_stream_close(oldfile);
  2683. }
  2684. php_stream_close(newfile);
  2685. if (error) {
  2686. spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
  2687. }
  2688. return EOF;
  2689. }
  2690. /* this will have changed for all files that have either changed compression or been modified */
  2691. entry->offset = entry->offset_abs = offset;
  2692. offset += entry->compressed_filesize;
  2693. if (php_stream_copy_to_stream_ex(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
  2694. if (closeoldfile) {
  2695. php_stream_close(oldfile);
  2696. }
  2697. php_stream_close(newfile);
  2698. if (error) {
  2699. spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
  2700. }
  2701. return EOF;
  2702. }
  2703. entry->is_modified = 0;
  2704. if (entry->cfp) {
  2705. php_stream_close(entry->cfp);
  2706. entry->cfp = NULL;
  2707. }
  2708. if (entry->fp_type == PHAR_MOD) {
  2709. /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed when the phar_entry_data is phar_entry_delref'ed */
  2710. if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
  2711. php_stream_close(entry->fp);
  2712. }
  2713. entry->fp = NULL;
  2714. entry->fp_type = PHAR_FP;
  2715. } else if (entry->fp_type == PHAR_UFP) {
  2716. entry->fp_type = PHAR_FP;
  2717. }
  2718. }
  2719. /* append signature */
  2720. if (global_flags & PHAR_HDR_SIGNATURE) {
  2721. char sig_buf[4];
  2722. php_stream_rewind(newfile);
  2723. if (phar->signature) {
  2724. efree(phar->signature);
  2725. phar->signature = NULL;
  2726. }
  2727. switch(phar->sig_flags) {
  2728. #ifndef PHAR_HASH_OK
  2729. case PHAR_SIG_SHA512:
  2730. case PHAR_SIG_SHA256:
  2731. if (closeoldfile) {
  2732. php_stream_close(oldfile);
  2733. }
  2734. php_stream_close(newfile);
  2735. if (error) {
  2736. spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
  2737. }
  2738. return EOF;
  2739. #endif
  2740. default: {
  2741. char *digest = NULL;
  2742. int digest_len;
  2743. if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
  2744. if (error) {
  2745. char *save = *error;
  2746. spprintf(error, 0, "phar error: unable to write signature: %s", save);
  2747. efree(save);
  2748. }
  2749. if (digest) {
  2750. efree(digest);
  2751. }
  2752. if (closeoldfile) {
  2753. php_stream_close(oldfile);
  2754. }
  2755. php_stream_close(newfile);
  2756. return EOF;
  2757. }
  2758. php_stream_write(newfile, digest, digest_len);
  2759. efree(digest);
  2760. if (phar->sig_flags == PHAR_SIG_OPENSSL) {
  2761. phar_set_32(sig_buf, digest_len);
  2762. php_stream_write(newfile, sig_buf, 4);
  2763. }
  2764. break;
  2765. }
  2766. }
  2767. phar_set_32(sig_buf, phar->sig_flags);
  2768. php_stream_write(newfile, sig_buf, 4);
  2769. php_stream_write(newfile, "GBMB", 4);
  2770. }
  2771. /* finally, close the temp file, rename the original phar,
  2772. move the temp to the old phar, unlink the old phar, and reload it into memory
  2773. */
  2774. if (phar->fp && free_fp) {
  2775. php_stream_close(phar->fp);
  2776. }
  2777. if (phar->ufp) {
  2778. if (free_ufp) {
  2779. php_stream_close(phar->ufp);
  2780. }
  2781. phar->ufp = NULL;
  2782. }
  2783. if (closeoldfile) {
  2784. php_stream_close(oldfile);
  2785. }
  2786. phar->internal_file_start = halt_offset + manifest_len + 4;
  2787. phar->halt_offset = halt_offset;
  2788. phar->is_brandnew = 0;
  2789. php_stream_rewind(newfile);
  2790. if (phar->donotflush) {
  2791. /* deferred flush */
  2792. phar->fp = newfile;
  2793. } else {
  2794. phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
  2795. if (!phar->fp) {
  2796. phar->fp = newfile;
  2797. if (error) {
  2798. spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
  2799. }
  2800. return EOF;
  2801. }
  2802. if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
  2803. /* to properly compress, we have to tell zlib to add a zlib header */
  2804. zval filterparams;
  2805. array_init(&filterparams);
  2806. add_assoc_long(&filterparams, "window", MAX_WBITS+16);
  2807. filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
  2808. zval_dtor(&filterparams);
  2809. if (!filter) {
  2810. if (error) {
  2811. spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
  2812. }
  2813. return EOF;
  2814. }
  2815. php_stream_filter_append(&phar->fp->writefilters, filter);
  2816. php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
  2817. php_stream_filter_flush(filter, 1);
  2818. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  2819. php_stream_close(phar->fp);
  2820. /* use the temp stream as our base */
  2821. phar->fp = newfile;
  2822. } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
  2823. filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
  2824. php_stream_filter_append(&phar->fp->writefilters, filter);
  2825. php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
  2826. php_stream_filter_flush(filter, 1);
  2827. php_stream_filter_remove(filter, 1 TSRMLS_CC);
  2828. php_stream_close(phar->fp);
  2829. /* use the temp stream as our base */
  2830. phar->fp = newfile;
  2831. } else {
  2832. php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
  2833. /* we could also reopen the file in "rb" mode but there is no need for that */
  2834. php_stream_close(newfile);
  2835. }
  2836. }
  2837. if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
  2838. if (error) {
  2839. spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
  2840. }
  2841. return EOF;
  2842. }
  2843. return EOF;
  2844. }
  2845. /* }}} */
  2846. #ifdef COMPILE_DL_PHAR
  2847. ZEND_GET_MODULE(phar)
  2848. #endif
  2849. /* {{{ phar_functions[]
  2850. *
  2851. * Every user visible function must have an entry in phar_functions[].
  2852. */
  2853. zend_function_entry phar_functions[] = {
  2854. PHP_FE_END
  2855. };
  2856. /* }}}*/
  2857. static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
  2858. {
  2859. return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
  2860. }
  2861. /* }}} */
  2862. static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
  2863. {
  2864. return ((phar_archive_data*)handle)->halt_offset + 32;
  2865. } /* }}} */
  2866. zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
  2867. #define phar_orig_zend_open zend_stream_open_function
  2868. static char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC)
  2869. {
  2870. return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC);
  2871. }
  2872. static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
  2873. {
  2874. zend_op_array *res;
  2875. char *name = NULL;
  2876. int failed;
  2877. phar_archive_data *phar;
  2878. if (!file_handle || !file_handle->filename) {
  2879. return phar_orig_compile_file(file_handle, type TSRMLS_CC);
  2880. }
  2881. if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
  2882. if (SUCCESS == phar_open_from_filename((char*)file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
  2883. if (phar->is_zip || phar->is_tar) {
  2884. zend_file_handle f = *file_handle;
  2885. /* zip or tar-based phar */
  2886. spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
  2887. if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) {
  2888. efree(name);
  2889. name = NULL;
  2890. file_handle->filename = f.filename;
  2891. if (file_handle->opened_path) {
  2892. efree(file_handle->opened_path);
  2893. }
  2894. file_handle->opened_path = f.opened_path;
  2895. file_handle->free_filename = f.free_filename;
  2896. } else {
  2897. *file_handle = f;
  2898. }
  2899. } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
  2900. /* compressed phar */
  2901. file_handle->type = ZEND_HANDLE_STREAM;
  2902. /* we do our own reading directly from the phar, don't change the next line */
  2903. file_handle->handle.stream.handle = phar;
  2904. file_handle->handle.stream.reader = phar_zend_stream_reader;
  2905. file_handle->handle.stream.closer = NULL;
  2906. file_handle->handle.stream.fsizer = phar_zend_stream_fsizer;
  2907. file_handle->handle.stream.isatty = 0;
  2908. phar->is_persistent ?
  2909. php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
  2910. php_stream_rewind(phar->fp);
  2911. memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
  2912. }
  2913. }
  2914. }
  2915. zend_try {
  2916. failed = 0;
  2917. CG(zend_lineno) = 0;
  2918. res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
  2919. } zend_catch {
  2920. failed = 1;
  2921. res = NULL;
  2922. } zend_end_try();
  2923. if (name) {
  2924. efree(name);
  2925. }
  2926. if (failed) {
  2927. zend_bailout();
  2928. }
  2929. return res;
  2930. }
  2931. /* }}} */
  2932. typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
  2933. typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
  2934. PHP_GINIT_FUNCTION(phar) /* {{{ */
  2935. {
  2936. phar_mime_type mime;
  2937. memset(phar_globals, 0, sizeof(zend_phar_globals));
  2938. phar_globals->readonly = 1;
  2939. zend_hash_init(&phar_globals->mime_types, 0, NULL, NULL, 1);
  2940. #define PHAR_SET_MIME(mimetype, ret, fileext) \
  2941. mime.mime = mimetype; \
  2942. mime.len = sizeof((mimetype))+1; \
  2943. mime.type = ret; \
  2944. zend_hash_add(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type), NULL); \
  2945. PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
  2946. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
  2947. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
  2948. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
  2949. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
  2950. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
  2951. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
  2952. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
  2953. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
  2954. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
  2955. PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
  2956. PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
  2957. PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
  2958. PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
  2959. PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
  2960. PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
  2961. PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
  2962. PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
  2963. PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
  2964. PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
  2965. PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
  2966. PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
  2967. PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
  2968. PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
  2969. PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
  2970. PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
  2971. PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
  2972. PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
  2973. PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
  2974. PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
  2975. PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
  2976. PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
  2977. PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
  2978. PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
  2979. PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
  2980. PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
  2981. PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
  2982. PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
  2983. PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
  2984. PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
  2985. phar_restore_orig_functions(TSRMLS_C);
  2986. }
  2987. /* }}} */
  2988. PHP_GSHUTDOWN_FUNCTION(phar) /* {{{ */
  2989. {
  2990. zend_hash_destroy(&phar_globals->mime_types);
  2991. }
  2992. /* }}} */
  2993. PHP_MINIT_FUNCTION(phar) /* {{{ */
  2994. {
  2995. REGISTER_INI_ENTRIES();
  2996. phar_orig_compile_file = zend_compile_file;
  2997. zend_compile_file = phar_compile_file;
  2998. phar_save_resolve_path = zend_resolve_path;
  2999. zend_resolve_path = phar_resolve_path;
  3000. phar_object_init(TSRMLS_C);
  3001. phar_intercept_functions_init(TSRMLS_C);
  3002. phar_save_orig_functions(TSRMLS_C);
  3003. return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
  3004. }
  3005. /* }}} */
  3006. PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
  3007. {
  3008. php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
  3009. phar_intercept_functions_shutdown(TSRMLS_C);
  3010. if (zend_compile_file == phar_compile_file) {
  3011. zend_compile_file = phar_orig_compile_file;
  3012. }
  3013. if (PHAR_G(manifest_cached)) {
  3014. zend_hash_destroy(&(cached_phars));
  3015. zend_hash_destroy(&(cached_alias));
  3016. }
  3017. return SUCCESS;
  3018. }
  3019. /* }}} */
  3020. void phar_request_initialize(TSRMLS_D) /* {{{ */
  3021. {
  3022. if (!PHAR_GLOBALS->request_init)
  3023. {
  3024. PHAR_G(last_phar) = NULL;
  3025. PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
  3026. PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
  3027. PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
  3028. PHAR_GLOBALS->request_init = 1;
  3029. PHAR_GLOBALS->request_ends = 0;
  3030. PHAR_GLOBALS->request_done = 0;
  3031. zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data, 0);
  3032. zend_hash_init(&(PHAR_GLOBALS->phar_persist_map), 5, zend_get_hash_value, NULL, 0);
  3033. zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
  3034. if (PHAR_G(manifest_cached)) {
  3035. phar_archive_data **pphar;
  3036. phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
  3037. for (zend_hash_internal_pointer_reset(&cached_phars);
  3038. zend_hash_get_current_data(&cached_phars, (void **)&pphar) == SUCCESS;
  3039. zend_hash_move_forward(&cached_phars)) {
  3040. stuff[pphar[0]->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar[0]->manifest)), sizeof(phar_entry_fp_info));
  3041. }
  3042. PHAR_GLOBALS->cached_fp = stuff;
  3043. }
  3044. PHAR_GLOBALS->phar_SERVER_mung_list = 0;
  3045. PHAR_G(cwd) = NULL;
  3046. PHAR_G(cwd_len) = 0;
  3047. PHAR_G(cwd_init) = 0;
  3048. }
  3049. }
  3050. /* }}} */
  3051. PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
  3052. {
  3053. int i;
  3054. PHAR_GLOBALS->request_ends = 1;
  3055. if (PHAR_GLOBALS->request_init)
  3056. {
  3057. phar_release_functions(TSRMLS_C);
  3058. zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
  3059. PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
  3060. zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
  3061. PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
  3062. zend_hash_destroy(&(PHAR_GLOBALS->phar_persist_map));
  3063. PHAR_GLOBALS->phar_persist_map.arBuckets = NULL;
  3064. PHAR_GLOBALS->phar_SERVER_mung_list = 0;
  3065. if (PHAR_GLOBALS->cached_fp) {
  3066. for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
  3067. if (PHAR_GLOBALS->cached_fp[i].fp) {
  3068. php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
  3069. }
  3070. if (PHAR_GLOBALS->cached_fp[i].ufp) {
  3071. php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
  3072. }
  3073. efree(PHAR_GLOBALS->cached_fp[i].manifest);
  3074. }
  3075. efree(PHAR_GLOBALS->cached_fp);
  3076. PHAR_GLOBALS->cached_fp = 0;
  3077. }
  3078. PHAR_GLOBALS->request_init = 0;
  3079. if (PHAR_G(cwd)) {
  3080. efree(PHAR_G(cwd));
  3081. }
  3082. PHAR_G(cwd) = NULL;
  3083. PHAR_G(cwd_len) = 0;
  3084. PHAR_G(cwd_init) = 0;
  3085. }
  3086. PHAR_GLOBALS->request_done = 1;
  3087. return SUCCESS;
  3088. }
  3089. /* }}} */
  3090. PHP_MINFO_FUNCTION(phar) /* {{{ */
  3091. {
  3092. phar_request_initialize(TSRMLS_C);
  3093. php_info_print_table_start();
  3094. php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
  3095. php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
  3096. php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
  3097. php_info_print_table_row(2, "SVN revision", "$Id$");
  3098. php_info_print_table_row(2, "Phar-based phar archives", "enabled");
  3099. php_info_print_table_row(2, "Tar-based phar archives", "enabled");
  3100. php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
  3101. if (PHAR_G(has_zlib)) {
  3102. php_info_print_table_row(2, "gzip compression", "enabled");
  3103. } else {
  3104. php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
  3105. }
  3106. if (PHAR_G(has_bz2)) {
  3107. php_info_print_table_row(2, "bzip2 compression", "enabled");
  3108. } else {
  3109. php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
  3110. }
  3111. #ifdef PHAR_HAVE_OPENSSL
  3112. php_info_print_table_row(2, "Native OpenSSL support", "enabled");
  3113. #else
  3114. if (zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
  3115. php_info_print_table_row(2, "OpenSSL support", "enabled");
  3116. } else {
  3117. php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
  3118. }
  3119. #endif
  3120. php_info_print_table_end();
  3121. php_info_print_box_start(0);
  3122. PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
  3123. PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
  3124. PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
  3125. PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
  3126. PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
  3127. php_info_print_box_end();
  3128. DISPLAY_INI_ENTRIES();
  3129. }
  3130. /* }}} */
  3131. /* {{{ phar_module_entry
  3132. */
  3133. static const zend_module_dep phar_deps[] = {
  3134. ZEND_MOD_OPTIONAL("apc")
  3135. ZEND_MOD_OPTIONAL("bz2")
  3136. ZEND_MOD_OPTIONAL("openssl")
  3137. ZEND_MOD_OPTIONAL("zlib")
  3138. ZEND_MOD_OPTIONAL("standard")
  3139. #if defined(HAVE_HASH) && !defined(COMPILE_DL_HASH)
  3140. ZEND_MOD_REQUIRED("hash")
  3141. #endif
  3142. #if HAVE_SPL
  3143. ZEND_MOD_REQUIRED("spl")
  3144. #endif
  3145. ZEND_MOD_END
  3146. };
  3147. zend_module_entry phar_module_entry = {
  3148. STANDARD_MODULE_HEADER_EX, NULL,
  3149. phar_deps,
  3150. "Phar",
  3151. phar_functions,
  3152. PHP_MINIT(phar),
  3153. PHP_MSHUTDOWN(phar),
  3154. NULL,
  3155. PHP_RSHUTDOWN(phar),
  3156. PHP_MINFO(phar),
  3157. PHP_PHAR_VERSION,
  3158. PHP_MODULE_GLOBALS(phar), /* globals descriptor */
  3159. PHP_GINIT(phar), /* globals ctor */
  3160. PHP_GSHUTDOWN(phar), /* globals dtor */
  3161. NULL, /* post deactivate */
  3162. STANDARD_MODULE_PROPERTIES_EX
  3163. };
  3164. /* }}} */
  3165. /*
  3166. * Local variables:
  3167. * tab-width: 4
  3168. * c-basic-offset: 4
  3169. * End:
  3170. * vim600: noet sw=4 ts=4 fdm=marker
  3171. * vim<600: noet sw=4 ts=4
  3172. */