go-pear.phar 3.4 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501335023350333504335053350633507335083350933510335113351233513335143351533516335173351833519335203352133522335233352433525335263352733528335293353033531335323353333534335353353633537335383353933540335413354233543335443354533546335473354833549335503355133552335533355433555335563355733558335593356033561335623356333564335653356633567335683356933570335713357233573335743357533576335773357833579335803358133582335833358433585335863358733588335893359033591335923359333594335953359633597335983359933600336013360233603336043360533606336073360833609336103361133612336133361433615336163361733618336193362033621336223362333624336253362633627336283362933630336313363233633336343363533636336373363833639336403364133642336433364433645336463364733648336493365033651336523365333654336553365633657336583365933660336613366233663336643366533666336673366833669336703367133672336733367433675336763367733678336793368033681336823368333684336853368633687336883368933690336913369233693336943369533696336973369833699337003370133702337033370433705337063370733708337093371033711337123371333714337153371633717337183371933720337213372233723337243372533726337273372833729337303373133732337333373433735337363373733738337393374033741337423374333744337453374633747337483374933750337513375233753337543375533756337573375833759337603376133762337633376433765337663376733768337693377033771337723377333774337753377633777337783377933780337813378233783337843378533786337873378833789337903379133792337933379433795337963379733798337993380033801338023380333804338053380633807338083380933810338113381233813338143381533816338173381833819338203382133822338233382433825338263382733828338293383033831338323383333834338353383633837338383383933840338413384233843338443384533846338473384833849338503385133852338533385433855338563385733858338593386033861338623386333864338653386633867338683386933870338713387233873338743387533876338773387833879338803388133882338833388433885338863388733888338893389033891338923389333894338953389633897338983389933900339013390233903339043390533906339073390833909339103391133912339133391433915339163391733918339193392033921339223392333924339253392633927339283392933930339313393233933339343393533936339373393833939339403394133942339433394433945339463394733948339493395033951339523395333954339553395633957339583395933960339613396233963339643396533966339673396833969339703397133972339733397433975339763397733978339793398033981339823398333984339853398633987339883398933990339913399233993339943399533996339973399833999340003400134002340033400434005340063400734008340093401034011340123401334014340153401634017340183401934020340213402234023340243402534026340273402834029340303403134032340333403434035340363403734038340393404034041340423404334044340453404634047340483404934050340513405234053340543405534056340573405834059340603406134062340633406434065340663406734068340693407034071340723407334074340753407634077340783407934080340813408234083340843408534086340873408834089340903409134092340933409434095340963409734098340993410034101341023410334104341053410634107341083410934110341113411234113341143411534116341173411834119341203412134122341233412434125341263412734128341293413034131341323413334134341353413634137341383413934140341413414234143341443414534146341473414834149341503415134152341533415434155341563415734158341593416034161341623416334164341653416634167341683416934170341713417234173341743417534176341773417834179341803418134182341833418434185341863418734188341893419034191341923419334194341953419634197341983419934200342013420234203342043420534206342073420834209342103421134212342133421434215342163421734218342193422034221342223422334224342253422634227342283422934230342313423234233342343423534236342373423834239342403424134242342433424434245342463424734248342493425034251342523425334254342553425634257342583425934260342613426234263342643426534266342673426834269342703427134272342733427434275342763427734278342793428034281342823428334284342853428634287342883428934290342913429234293342943429534296342973429834299343003430134302343033430434305343063430734308343093431034311343123431334314343153431634317343183431934320343213432234323343243432534326343273432834329343303433134332343333433434335343363433734338343393434034341343423434334344343453434634347343483434934350343513435234353343543435534356343573435834359343603436134362343633436434365343663436734368343693437034371343723437334374343753437634377343783437934380343813438234383343843438534386343873438834389343903439134392343933439434395343963439734398343993440034401344023440334404344053440634407344083440934410344113441234413344143441534416344173441834419344203442134422344233442434425344263442734428344293443034431344323443334434344353443634437344383443934440344413444234443344443444534446344473444834449344503445134452344533445434455344563445734458344593446034461344623446334464344653446634467344683446934470344713447234473344743447534476344773447834479344803448134482344833448434485344863448734488344893449034491344923449334494344953449634497344983449934500345013450234503345043450534506345073450834509345103451134512345133451434515345163451734518345193452034521345223452334524345253452634527345283452934530345313453234533345343453534536345373453834539345403454134542345433454434545345463454734548345493455034551345523455334554345553455634557345583455934560345613456234563345643456534566345673456834569345703457134572345733457434575345763457734578345793458034581345823458334584345853458634587345883458934590345913459234593345943459534596345973459834599346003460134602346033460434605346063460734608346093461034611346123461334614346153461634617346183461934620346213462234623346243462534626346273462834629346303463134632346333463434635346363463734638346393464034641346423464334644346453464634647346483464934650346513465234653346543465534656346573465834659346603466134662346633466434665346663466734668346693467034671346723467334674346753467634677346783467934680346813468234683346843468534686346873468834689346903469134692346933469434695346963469734698346993470034701347023470334704347053470634707347083470934710347113471234713347143471534716347173471834719347203472134722347233472434725347263472734728347293473034731347323473334734347353473634737347383473934740347413474234743347443474534746347473474834749347503475134752347533475434755347563475734758347593476034761347623476334764347653476634767347683476934770347713477234773347743477534776347773477834779347803478134782347833478434785347863478734788347893479034791347923479334794347953479634797347983479934800348013480234803348043480534806348073480834809348103481134812348133481434815348163481734818348193482034821348223482334824348253482634827348283482934830348313483234833348343483534836348373483834839348403484134842348433484434845348463484734848348493485034851348523485334854348553485634857348583485934860348613486234863348643486534866348673486834869348703487134872348733487434875348763487734878348793488034881348823488334884348853488634887348883488934890348913489234893348943489534896348973489834899349003490134902349033490434905349063490734908349093491034911349123491334914349153491634917349183491934920349213492234923349243492534926349273492834929349303493134932349333493434935349363493734938349393494034941349423494334944349453494634947349483494934950349513495234953349543495534956349573495834959349603496134962349633496434965349663496734968349693497034971349723497334974349753497634977349783497934980349813498234983349843498534986349873498834989349903499134992349933499434995349963499734998349993500035001350023500335004350053500635007350083500935010350113501235013350143501535016350173501835019350203502135022350233502435025350263502735028350293503035031350323503335034350353503635037350383503935040350413504235043350443504535046350473504835049350503505135052350533505435055350563505735058350593506035061350623506335064350653506635067350683506935070350713507235073350743507535076350773507835079350803508135082350833508435085350863508735088350893509035091350923509335094350953509635097350983509935100351013510235103351043510535106351073510835109351103511135112351133511435115351163511735118351193512035121351223512335124351253512635127351283512935130351313513235133351343513535136351373513835139351403514135142351433514435145351463514735148351493515035151351523515335154351553515635157351583515935160351613516235163351643516535166351673516835169351703517135172351733517435175351763517735178351793518035181351823518335184351853518635187351883518935190351913519235193351943519535196351973519835199352003520135202352033520435205352063520735208352093521035211352123521335214352153521635217352183521935220352213522235223352243522535226352273522835229352303523135232352333523435235352363523735238352393524035241352423524335244352453524635247352483524935250352513525235253352543525535256352573525835259352603526135262352633526435265352663526735268352693527035271352723527335274352753527635277352783527935280352813528235283352843528535286352873528835289352903529135292352933529435295352963529735298352993530035301353023530335304353053530635307353083530935310353113531235313353143531535316353173531835319353203532135322353233532435325353263532735328353293533035331353323533335334353353533635337353383533935340353413534235343353443534535346353473534835349353503535135352353533535435355353563535735358353593536035361353623536335364353653536635367353683536935370353713537235373353743537535376353773537835379353803538135382353833538435385353863538735388353893539035391353923539335394353953539635397353983539935400354013540235403354043540535406354073540835409354103541135412354133541435415354163541735418354193542035421354223542335424354253542635427354283542935430354313543235433354343543535436354373543835439354403544135442354433544435445354463544735448354493545035451354523545335454354553545635457354583545935460354613546235463354643546535466354673546835469354703547135472354733547435475354763547735478354793548035481354823548335484354853548635487354883548935490354913549235493354943549535496354973549835499355003550135502355033550435505355063550735508355093551035511355123551335514355153551635517355183551935520355213552235523355243552535526355273552835529355303553135532355333553435535355363553735538355393554035541355423554335544355453554635547355483554935550355513555235553355543555535556355573555835559355603556135562355633556435565355663556735568355693557035571355723557335574355753557635577355783557935580355813558235583355843558535586355873558835589355903559135592355933559435595355963559735598355993560035601356023560335604356053560635607356083560935610356113561235613356143561535616356173561835619356203562135622356233562435625356263562735628356293563035631356323563335634356353563635637356383563935640356413564235643356443564535646356473564835649356503565135652356533565435655356563565735658356593566035661356623566335664356653566635667356683566935670356713567235673356743567535676356773567835679356803568135682356833568435685356863568735688356893569035691356923569335694356953569635697356983569935700357013570235703357043570535706357073570835709357103571135712357133571435715357163571735718357193572035721357223572335724357253572635727357283572935730357313573235733357343573535736357373573835739357403574135742357433574435745357463574735748357493575035751357523575335754357553575635757357583575935760357613576235763357643576535766357673576835769357703577135772357733577435775357763577735778357793578035781357823578335784357853578635787357883578935790357913579235793357943579535796357973579835799358003580135802358033580435805358063580735808358093581035811358123581335814358153581635817358183581935820358213582235823358243582535826358273582835829358303583135832358333583435835358363583735838358393584035841358423584335844358453584635847358483584935850358513585235853358543585535856358573585835859358603586135862358633586435865358663586735868358693587035871358723587335874358753587635877358783587935880358813588235883358843588535886358873588835889358903589135892358933589435895358963589735898358993590035901359023590335904359053590635907359083590935910359113591235913359143591535916359173591835919359203592135922359233592435925359263592735928359293593035931359323593335934359353593635937359383593935940359413594235943359443594535946359473594835949359503595135952359533595435955359563595735958359593596035961359623596335964359653596635967359683596935970359713597235973359743597535976359773597835979359803598135982359833598435985359863598735988359893599035991359923599335994359953599635997359983599936000360013600236003360043600536006360073600836009360103601136012360133601436015360163601736018360193602036021360223602336024360253602636027360283602936030360313603236033360343603536036360373603836039360403604136042360433604436045360463604736048360493605036051360523605336054360553605636057360583605936060360613606236063360643606536066360673606836069360703607136072360733607436075360763607736078360793608036081360823608336084360853608636087360883608936090360913609236093360943609536096360973609836099361003610136102361033610436105361063610736108361093611036111361123611336114361153611636117361183611936120361213612236123361243612536126361273612836129361303613136132361333613436135361363613736138361393614036141361423614336144361453614636147361483614936150361513615236153361543615536156361573615836159361603616136162361633616436165361663616736168361693617036171361723617336174361753617636177361783617936180361813618236183361843618536186361873618836189361903619136192361933619436195361963619736198361993620036201362023620336204362053620636207362083620936210362113621236213362143621536216362173621836219362203622136222362233622436225362263622736228362293623036231362323623336234362353623636237362383623936240362413624236243362443624536246362473624836249362503625136252362533625436255362563625736258362593626036261362623626336264362653626636267362683626936270362713627236273362743627536276362773627836279362803628136282362833628436285362863628736288362893629036291362923629336294362953629636297362983629936300363013630236303363043630536306363073630836309363103631136312363133631436315363163631736318363193632036321363223632336324363253632636327363283632936330363313633236333363343633536336363373633836339363403634136342363433634436345363463634736348363493635036351363523635336354363553635636357363583635936360363613636236363363643636536366363673636836369363703637136372363733637436375363763637736378363793638036381363823638336384363853638636387363883638936390363913639236393363943639536396363973639836399364003640136402364033640436405364063640736408364093641036411364123641336414364153641636417364183641936420364213642236423364243642536426364273642836429364303643136432364333643436435364363643736438364393644036441364423644336444364453644636447364483644936450364513645236453364543645536456364573645836459364603646136462364633646436465364663646736468364693647036471364723647336474364753647636477364783647936480364813648236483364843648536486364873648836489364903649136492364933649436495364963649736498364993650036501365023650336504365053650636507365083650936510365113651236513365143651536516365173651836519365203652136522365233652436525365263652736528365293653036531365323653336534365353653636537365383653936540365413654236543365443654536546365473654836549365503655136552365533655436555365563655736558365593656036561365623656336564365653656636567365683656936570365713657236573365743657536576365773657836579365803658136582365833658436585365863658736588365893659036591365923659336594365953659636597365983659936600366013660236603366043660536606366073660836609366103661136612366133661436615366163661736618366193662036621366223662336624366253662636627366283662936630366313663236633366343663536636366373663836639366403664136642366433664436645366463664736648366493665036651366523665336654366553665636657366583665936660366613666236663366643666536666366673666836669366703667136672366733667436675366763667736678366793668036681366823668336684366853668636687366883668936690366913669236693366943669536696366973669836699367003670136702367033670436705367063670736708367093671036711367123671336714367153671636717367183671936720367213672236723367243672536726367273672836729367303673136732367333673436735367363673736738367393674036741367423674336744367453674636747367483674936750367513675236753367543675536756367573675836759367603676136762367633676436765367663676736768367693677036771367723677336774367753677636777367783677936780367813678236783367843678536786367873678836789367903679136792367933679436795367963679736798367993680036801368023680336804368053680636807368083680936810368113681236813368143681536816368173681836819368203682136822368233682436825368263682736828368293683036831368323683336834368353683636837368383683936840368413684236843368443684536846368473684836849368503685136852368533685436855368563685736858368593686036861368623686336864368653686636867368683686936870368713687236873368743687536876368773687836879368803688136882368833688436885368863688736888368893689036891368923689336894368953689636897368983689936900369013690236903369043690536906369073690836909369103691136912369133691436915369163691736918369193692036921369223692336924369253692636927369283692936930369313693236933369343693536936369373693836939369403694136942369433694436945369463694736948369493695036951369523695336954369553695636957369583695936960369613696236963369643696536966369673696836969369703697136972369733697436975369763697736978369793698036981369823698336984369853698636987369883698936990369913699236993369943699536996369973699836999370003700137002370033700437005370063700737008370093701037011370123701337014370153701637017370183701937020370213702237023370243702537026370273702837029370303703137032370333703437035370363703737038370393704037041370423704337044370453704637047370483704937050370513705237053370543705537056370573705837059370603706137062370633706437065370663706737068370693707037071370723707337074370753707637077370783707937080370813708237083370843708537086370873708837089370903709137092370933709437095370963709737098370993710037101371023710337104371053710637107371083710937110371113711237113371143711537116371173711837119371203712137122371233712437125371263712737128371293713037131371323713337134371353713637137371383713937140371413714237143371443714537146371473714837149371503715137152371533715437155371563715737158371593716037161371623716337164371653716637167371683716937170371713717237173371743717537176371773717837179371803718137182371833718437185371863718737188371893719037191371923719337194371953719637197371983719937200372013720237203372043720537206372073720837209372103721137212372133721437215372163721737218372193722037221372223722337224372253722637227372283722937230372313723237233372343723537236372373723837239372403724137242372433724437245372463724737248372493725037251372523725337254372553725637257372583725937260372613726237263372643726537266372673726837269372703727137272372733727437275372763727737278372793728037281372823728337284372853728637287372883728937290372913729237293372943729537296372973729837299373003730137302373033730437305373063730737308373093731037311373123731337314373153731637317373183731937320373213732237323373243732537326373273732837329373303733137332373333733437335373363733737338373393734037341373423734337344373453734637347373483734937350373513735237353373543735537356373573735837359373603736137362373633736437365373663736737368373693737037371373723737337374373753737637377373783737937380373813738237383373843738537386373873738837389373903739137392373933739437395373963739737398373993740037401374023740337404374053740637407374083740937410374113741237413374143741537416374173741837419374203742137422374233742437425374263742737428374293743037431374323743337434374353743637437374383743937440374413744237443374443744537446374473744837449374503745137452374533745437455374563745737458374593746037461374623746337464374653746637467374683746937470374713747237473374743747537476374773747837479374803748137482374833748437485374863748737488374893749037491374923749337494374953749637497374983749937500375013750237503375043750537506375073750837509375103751137512375133751437515375163751737518375193752037521375223752337524375253752637527375283752937530375313753237533375343753537536375373753837539375403754137542375433754437545375463754737548375493755037551375523755337554375553755637557375583755937560375613756237563375643756537566375673756837569375703757137572375733757437575375763757737578375793758037581375823758337584375853758637587375883758937590375913759237593375943759537596375973759837599376003760137602376033760437605376063760737608376093761037611376123761337614376153761637617376183761937620376213762237623376243762537626376273762837629376303763137632376333763437635376363763737638376393764037641376423764337644376453764637647376483764937650376513765237653376543765537656376573765837659376603766137662376633766437665376663766737668376693767037671376723767337674376753767637677376783767937680376813768237683376843768537686376873768837689376903769137692376933769437695376963769737698376993770037701377023770337704377053770637707377083770937710377113771237713377143771537716377173771837719377203772137722377233772437725377263772737728377293773037731377323773337734377353773637737377383773937740377413774237743377443774537746377473774837749377503775137752377533775437755377563775737758377593776037761377623776337764377653776637767377683776937770377713777237773377743777537776377773777837779377803778137782377833778437785377863778737788377893779037791377923779337794377953779637797377983779937800378013780237803378043780537806378073780837809378103781137812378133781437815378163781737818378193782037821378223782337824378253782637827378283782937830378313783237833378343783537836378373783837839378403784137842378433784437845378463784737848378493785037851378523785337854378553785637857378583785937860378613786237863378643786537866378673786837869378703787137872378733787437875378763787737878378793788037881378823788337884378853788637887378883788937890378913789237893378943789537896378973789837899379003790137902379033790437905379063790737908379093791037911379123791337914379153791637917379183791937920379213792237923379243792537926379273792837929379303793137932379333793437935379363793737938379393794037941379423794337944379453794637947379483794937950379513795237953379543795537956379573795837959379603796137962379633796437965379663796737968379693797037971379723797337974379753797637977379783797937980379813798237983379843798537986379873798837989379903799137992379933799437995379963799737998379993800038001380023800338004380053800638007380083800938010380113801238013380143801538016380173801838019380203802138022380233802438025380263802738028380293803038031380323803338034380353803638037380383803938040380413804238043380443804538046380473804838049380503805138052380533805438055380563805738058380593806038061380623806338064380653806638067380683806938070380713807238073380743807538076380773807838079380803808138082380833808438085380863808738088380893809038091380923809338094380953809638097380983809938100381013810238103381043810538106381073810838109381103811138112381133811438115381163811738118381193812038121381223812338124381253812638127381283812938130381313813238133381343813538136381373813838139381403814138142381433814438145381463814738148381493815038151381523815338154381553815638157381583815938160381613816238163381643816538166381673816838169381703817138172381733817438175381763817738178381793818038181381823818338184381853818638187381883818938190381913819238193381943819538196381973819838199382003820138202382033820438205382063820738208382093821038211382123821338214382153821638217382183821938220382213822238223382243822538226382273822838229382303823138232382333823438235382363823738238382393824038241382423824338244382453824638247382483824938250382513825238253382543825538256382573825838259382603826138262382633826438265382663826738268382693827038271382723827338274382753827638277382783827938280382813828238283382843828538286382873828838289382903829138292382933829438295382963829738298382993830038301383023830338304383053830638307383083830938310383113831238313383143831538316383173831838319383203832138322383233832438325383263832738328383293833038331383323833338334383353833638337383383833938340383413834238343383443834538346383473834838349383503835138352383533835438355383563835738358383593836038361383623836338364383653836638367383683836938370383713837238373383743837538376383773837838379383803838138382383833838438385383863838738388383893839038391383923839338394383953839638397383983839938400384013840238403384043840538406384073840838409384103841138412384133841438415384163841738418384193842038421384223842338424384253842638427384283842938430384313843238433384343843538436384373843838439384403844138442384433844438445384463844738448384493845038451384523845338454384553845638457384583845938460384613846238463384643846538466384673846838469384703847138472384733847438475384763847738478384793848038481384823848338484384853848638487384883848938490384913849238493384943849538496384973849838499385003850138502385033850438505385063850738508385093851038511385123851338514385153851638517385183851938520385213852238523385243852538526385273852838529385303853138532385333853438535385363853738538385393854038541385423854338544385453854638547385483854938550385513855238553385543855538556385573855838559385603856138562385633856438565385663856738568385693857038571385723857338574385753857638577385783857938580385813858238583385843858538586385873858838589385903859138592385933859438595385963859738598385993860038601386023860338604386053860638607386083860938610386113861238613386143861538616386173861838619386203862138622386233862438625386263862738628386293863038631386323863338634386353863638637386383863938640386413864238643386443864538646386473864838649386503865138652386533865438655386563865738658386593866038661386623866338664386653866638667386683866938670386713867238673386743867538676386773867838679386803868138682386833868438685386863868738688386893869038691386923869338694386953869638697386983869938700387013870238703387043870538706387073870838709387103871138712387133871438715387163871738718387193872038721387223872338724387253872638727387283872938730387313873238733387343873538736387373873838739387403874138742387433874438745387463874738748387493875038751387523875338754387553875638757387583875938760387613876238763387643876538766387673876838769387703877138772387733877438775387763877738778387793878038781387823878338784387853878638787387883878938790387913879238793387943879538796387973879838799388003880138802388033880438805388063880738808388093881038811388123881338814388153881638817388183881938820388213882238823388243882538826388273882838829388303883138832388333883438835388363883738838388393884038841388423884338844388453884638847388483884938850388513885238853388543885538856388573885838859388603886138862388633886438865388663886738868388693887038871388723887338874388753887638877388783887938880388813888238883388843888538886388873888838889388903889138892388933889438895388963889738898388993890038901389023890338904389053890638907389083890938910389113891238913389143891538916389173891838919389203892138922389233892438925389263892738928389293893038931389323893338934389353893638937389383893938940389413894238943389443894538946389473894838949389503895138952389533895438955389563895738958389593896038961389623896338964389653896638967389683896938970389713897238973389743897538976389773897838979389803898138982389833898438985389863898738988389893899038991389923899338994389953899638997389983899939000390013900239003390043900539006390073900839009390103901139012390133901439015390163901739018390193902039021390223902339024390253902639027390283902939030390313903239033390343903539036390373903839039390403904139042390433904439045390463904739048390493905039051390523905339054390553905639057390583905939060390613906239063390643906539066390673906839069390703907139072390733907439075390763907739078390793908039081390823908339084390853908639087390883908939090390913909239093390943909539096390973909839099391003910139102391033910439105391063910739108391093911039111391123911339114391153911639117391183911939120391213912239123391243912539126391273912839129391303913139132391333913439135391363913739138391393914039141391423914339144391453914639147391483914939150391513915239153391543915539156391573915839159391603916139162391633916439165391663916739168391693917039171391723917339174391753917639177391783917939180391813918239183391843918539186391873918839189391903919139192391933919439195391963919739198391993920039201392023920339204392053920639207392083920939210392113921239213392143921539216392173921839219392203922139222392233922439225392263922739228392293923039231392323923339234392353923639237392383923939240392413924239243392443924539246392473924839249392503925139252392533925439255392563925739258392593926039261392623926339264392653926639267392683926939270392713927239273392743927539276392773927839279392803928139282392833928439285392863928739288392893929039291392923929339294392953929639297392983929939300393013930239303393043930539306393073930839309393103931139312393133931439315393163931739318393193932039321393223932339324393253932639327393283932939330393313933239333393343933539336393373933839339393403934139342393433934439345393463934739348393493935039351393523935339354393553935639357393583935939360393613936239363393643936539366393673936839369393703937139372393733937439375393763937739378393793938039381393823938339384393853938639387393883938939390393913939239393393943939539396393973939839399394003940139402394033940439405394063940739408394093941039411394123941339414394153941639417394183941939420394213942239423394243942539426394273942839429394303943139432394333943439435394363943739438394393944039441394423944339444394453944639447394483944939450394513945239453394543945539456394573945839459394603946139462394633946439465394663946739468394693947039471394723947339474394753947639477394783947939480394813948239483394843948539486394873948839489394903949139492394933949439495394963949739498394993950039501395023950339504395053950639507395083950939510395113951239513395143951539516395173951839519395203952139522395233952439525395263952739528395293953039531395323953339534395353953639537395383953939540395413954239543395443954539546395473954839549395503955139552395533955439555395563955739558395593956039561395623956339564395653956639567395683956939570395713957239573395743957539576395773957839579395803958139582395833958439585395863958739588395893959039591395923959339594395953959639597395983959939600396013960239603396043960539606396073960839609396103961139612396133961439615396163961739618396193962039621396223962339624396253962639627396283962939630396313963239633396343963539636396373963839639396403964139642396433964439645396463964739648396493965039651396523965339654396553965639657396583965939660396613966239663396643966539666396673966839669396703967139672396733967439675396763967739678396793968039681396823968339684396853968639687396883968939690396913969239693396943969539696396973969839699397003970139702397033970439705397063970739708397093971039711397123971339714397153971639717397183971939720397213972239723397243972539726397273972839729397303973139732397333973439735397363973739738397393974039741397423974339744397453974639747397483974939750397513975239753397543975539756397573975839759397603976139762397633976439765397663976739768397693977039771397723977339774397753977639777397783977939780397813978239783397843978539786397873978839789397903979139792397933979439795397963979739798397993980039801398023980339804398053980639807398083980939810398113981239813398143981539816398173981839819398203982139822398233982439825398263982739828398293983039831398323983339834398353983639837398383983939840398413984239843398443984539846398473984839849398503985139852398533985439855398563985739858398593986039861398623986339864398653986639867398683986939870398713987239873398743987539876398773987839879398803988139882398833988439885398863988739888398893989039891398923989339894398953989639897398983989939900399013990239903399043990539906399073990839909399103991139912399133991439915399163991739918399193992039921399223992339924399253992639927399283992939930399313993239933399343993539936399373993839939399403994139942399433994439945399463994739948399493995039951399523995339954399553995639957399583995939960399613996239963399643996539966399673996839969399703997139972399733997439975399763997739978399793998039981399823998339984399853998639987399883998939990399913999239993399943999539996399973999839999400004000140002400034000440005400064000740008400094001040011400124001340014400154001640017400184001940020400214002240023400244002540026400274002840029400304003140032400334003440035400364003740038400394004040041400424004340044400454004640047400484004940050400514005240053400544005540056400574005840059400604006140062400634006440065400664006740068400694007040071400724007340074400754007640077400784007940080400814008240083400844008540086400874008840089400904009140092400934009440095400964009740098400994010040101401024010340104401054010640107401084010940110401114011240113401144011540116401174011840119401204012140122401234012440125401264012740128401294013040131401324013340134401354013640137401384013940140401414014240143401444014540146401474014840149401504015140152401534015440155401564015740158401594016040161401624016340164401654016640167401684016940170401714017240173401744017540176401774017840179401804018140182401834018440185401864018740188401894019040191401924019340194401954019640197401984019940200402014020240203402044020540206402074020840209402104021140212402134021440215402164021740218402194022040221402224022340224402254022640227402284022940230402314023240233402344023540236402374023840239402404024140242402434024440245402464024740248402494025040251402524025340254402554025640257402584025940260402614026240263402644026540266402674026840269402704027140272402734027440275402764027740278402794028040281402824028340284402854028640287402884028940290402914029240293402944029540296402974029840299403004030140302403034030440305403064030740308403094031040311403124031340314403154031640317403184031940320403214032240323403244032540326403274032840329403304033140332403334033440335403364033740338403394034040341403424034340344403454034640347403484034940350403514035240353403544035540356403574035840359403604036140362403634036440365403664036740368403694037040371403724037340374403754037640377403784037940380403814038240383403844038540386403874038840389403904039140392403934039440395403964039740398403994040040401404024040340404404054040640407404084040940410404114041240413404144041540416404174041840419404204042140422404234042440425404264042740428404294043040431404324043340434404354043640437404384043940440404414044240443404444044540446404474044840449404504045140452404534045440455404564045740458404594046040461404624046340464404654046640467404684046940470404714047240473404744047540476404774047840479404804048140482404834048440485404864048740488404894049040491404924049340494404954049640497404984049940500405014050240503405044050540506405074050840509405104051140512405134051440515405164051740518405194052040521405224052340524405254052640527405284052940530405314053240533405344053540536405374053840539405404054140542405434054440545405464054740548405494055040551405524055340554405554055640557405584055940560405614056240563405644056540566405674056840569405704057140572405734057440575405764057740578405794058040581405824058340584405854058640587405884058940590405914059240593405944059540596405974059840599406004060140602406034060440605406064060740608406094061040611406124061340614406154061640617406184061940620406214062240623406244062540626406274062840629406304063140632406334063440635406364063740638406394064040641406424064340644406454064640647406484064940650406514065240653406544065540656406574065840659406604066140662406634066440665406664066740668406694067040671406724067340674406754067640677406784067940680406814068240683406844068540686406874068840689406904069140692406934069440695406964069740698406994070040701407024070340704407054070640707407084070940710407114071240713407144071540716407174071840719407204072140722407234072440725407264072740728407294073040731407324073340734407354073640737407384073940740407414074240743407444074540746407474074840749407504075140752407534075440755407564075740758407594076040761407624076340764407654076640767407684076940770407714077240773407744077540776407774077840779407804078140782407834078440785407864078740788407894079040791407924079340794407954079640797407984079940800408014080240803408044080540806408074080840809408104081140812408134081440815408164081740818408194082040821408224082340824408254082640827408284082940830408314083240833408344083540836408374083840839408404084140842408434084440845408464084740848408494085040851408524085340854408554085640857408584085940860408614086240863408644086540866408674086840869408704087140872408734087440875408764087740878408794088040881408824088340884408854088640887408884088940890408914089240893408944089540896408974089840899409004090140902409034090440905409064090740908409094091040911409124091340914409154091640917409184091940920409214092240923409244092540926409274092840929409304093140932409334093440935409364093740938409394094040941409424094340944409454094640947409484094940950409514095240953409544095540956409574095840959409604096140962409634096440965409664096740968409694097040971409724097340974409754097640977409784097940980409814098240983409844098540986409874098840989409904099140992409934099440995409964099740998409994100041001410024100341004410054100641007410084100941010410114101241013410144101541016410174101841019410204102141022410234102441025410264102741028410294103041031410324103341034410354103641037410384103941040410414104241043410444104541046410474104841049410504105141052410534105441055410564105741058410594106041061410624106341064410654106641067410684106941070410714107241073410744107541076410774107841079410804108141082410834108441085410864108741088410894109041091410924109341094410954109641097410984109941100411014110241103411044110541106411074110841109411104111141112411134111441115411164111741118411194112041121411224112341124411254112641127411284112941130411314113241133411344113541136411374113841139411404114141142411434114441145411464114741148411494115041151411524115341154411554115641157411584115941160411614116241163411644116541166411674116841169411704117141172411734117441175411764117741178411794118041181411824118341184411854118641187411884118941190411914119241193411944119541196411974119841199412004120141202412034120441205412064120741208412094121041211412124121341214412154121641217412184121941220412214122241223412244122541226412274122841229412304123141232412334123441235412364123741238412394124041241412424124341244412454124641247412484124941250412514125241253412544125541256412574125841259412604126141262412634126441265412664126741268412694127041271412724127341274412754127641277412784127941280412814128241283412844128541286412874128841289412904129141292412934129441295412964129741298412994130041301413024130341304413054130641307413084130941310413114131241313413144131541316413174131841319413204132141322413234132441325413264132741328413294133041331413324133341334413354133641337413384133941340413414134241343413444134541346413474134841349413504135141352413534135441355413564135741358413594136041361413624136341364413654136641367413684136941370413714137241373413744137541376413774137841379413804138141382413834138441385413864138741388413894139041391413924139341394413954139641397413984139941400414014140241403414044140541406414074140841409414104141141412414134141441415414164141741418414194142041421414224142341424414254142641427414284142941430414314143241433414344143541436414374143841439414404144141442414434144441445414464144741448414494145041451414524145341454414554145641457414584145941460414614146241463414644146541466414674146841469414704147141472414734147441475414764147741478414794148041481414824148341484414854148641487414884148941490414914149241493414944149541496414974149841499415004150141502415034150441505415064150741508415094151041511415124151341514415154151641517415184151941520415214152241523415244152541526415274152841529415304153141532415334153441535415364153741538415394154041541415424154341544415454154641547415484154941550415514155241553415544155541556415574155841559415604156141562415634156441565415664156741568415694157041571415724157341574415754157641577415784157941580415814158241583415844158541586415874158841589415904159141592415934159441595415964159741598415994160041601416024160341604416054160641607416084160941610416114161241613416144161541616416174161841619416204162141622416234162441625416264162741628416294163041631416324163341634416354163641637416384163941640416414164241643416444164541646416474164841649416504165141652416534165441655416564165741658416594166041661416624166341664416654166641667416684166941670416714167241673416744167541676416774167841679416804168141682416834168441685416864168741688416894169041691416924169341694416954169641697416984169941700417014170241703417044170541706417074170841709417104171141712417134171441715417164171741718417194172041721417224172341724417254172641727417284172941730417314173241733417344173541736417374173841739417404174141742417434174441745417464174741748417494175041751417524175341754417554175641757417584175941760417614176241763417644176541766417674176841769417704177141772417734177441775417764177741778417794178041781417824178341784417854178641787417884178941790417914179241793417944179541796417974179841799418004180141802418034180441805418064180741808418094181041811418124181341814418154181641817418184181941820418214182241823418244182541826418274182841829418304183141832418334183441835418364183741838418394184041841418424184341844418454184641847418484184941850418514185241853418544185541856418574185841859418604186141862418634186441865418664186741868418694187041871418724187341874418754187641877418784187941880418814188241883418844188541886418874188841889418904189141892418934189441895418964189741898418994190041901419024190341904419054190641907419084190941910419114191241913419144191541916419174191841919419204192141922419234192441925419264192741928419294193041931419324193341934419354193641937419384193941940419414194241943419444194541946419474194841949419504195141952419534195441955419564195741958419594196041961419624196341964419654196641967419684196941970419714197241973419744197541976419774197841979419804198141982419834198441985419864198741988419894199041991419924199341994419954199641997419984199942000420014200242003420044200542006420074200842009420104201142012420134201442015420164201742018420194202042021420224202342024420254202642027420284202942030420314203242033420344203542036420374203842039420404204142042420434204442045420464204742048420494205042051420524205342054420554205642057420584205942060420614206242063420644206542066420674206842069420704207142072420734207442075420764207742078420794208042081420824208342084420854208642087420884208942090420914209242093420944209542096420974209842099421004210142102421034210442105421064210742108421094211042111421124211342114421154211642117421184211942120421214212242123421244212542126421274212842129421304213142132421334213442135421364213742138421394214042141421424214342144421454214642147421484214942150421514215242153421544215542156421574215842159421604216142162421634216442165421664216742168421694217042171421724217342174421754217642177421784217942180421814218242183421844218542186421874218842189421904219142192421934219442195421964219742198421994220042201422024220342204422054220642207422084220942210422114221242213422144221542216422174221842219422204222142222422234222442225422264222742228422294223042231422324223342234422354223642237422384223942240422414224242243422444224542246422474224842249422504225142252422534225442255422564225742258422594226042261422624226342264422654226642267422684226942270422714227242273422744227542276422774227842279422804228142282422834228442285422864228742288422894229042291422924229342294422954229642297422984229942300423014230242303423044230542306423074230842309423104231142312423134231442315423164231742318423194232042321423224232342324423254232642327423284232942330423314233242333423344233542336423374233842339423404234142342423434234442345423464234742348423494235042351423524235342354423554235642357423584235942360423614236242363423644236542366423674236842369423704237142372423734237442375423764237742378423794238042381423824238342384423854238642387423884238942390423914239242393423944239542396423974239842399424004240142402424034240442405424064240742408424094241042411424124241342414424154241642417424184241942420424214242242423424244242542426424274242842429424304243142432424334243442435424364243742438424394244042441424424244342444424454244642447424484244942450424514245242453424544245542456424574245842459424604246142462424634246442465424664246742468424694247042471424724247342474424754247642477424784247942480424814248242483424844248542486424874248842489424904249142492424934249442495424964249742498424994250042501425024250342504425054250642507425084250942510425114251242513425144251542516425174251842519425204252142522425234252442525425264252742528425294253042531425324253342534425354253642537425384253942540425414254242543425444254542546425474254842549425504255142552425534255442555425564255742558425594256042561425624256342564425654256642567425684256942570425714257242573425744257542576425774257842579425804258142582425834258442585425864258742588425894259042591425924259342594425954259642597425984259942600426014260242603426044260542606426074260842609426104261142612426134261442615426164261742618426194262042621426224262342624426254262642627426284262942630426314263242633426344263542636426374263842639426404264142642426434264442645426464264742648426494265042651426524265342654426554265642657426584265942660426614266242663426644266542666426674266842669426704267142672426734267442675426764267742678426794268042681426824268342684426854268642687426884268942690426914269242693426944269542696426974269842699427004270142702427034270442705427064270742708427094271042711427124271342714427154271642717427184271942720427214272242723427244272542726427274272842729427304273142732427334273442735427364273742738427394274042741427424274342744427454274642747427484274942750427514275242753427544275542756427574275842759427604276142762427634276442765427664276742768427694277042771427724277342774427754277642777427784277942780427814278242783427844278542786427874278842789427904279142792427934279442795427964279742798427994280042801428024280342804428054280642807428084280942810428114281242813428144281542816428174281842819428204282142822428234282442825428264282742828428294283042831428324283342834428354283642837428384283942840428414284242843428444284542846428474284842849428504285142852428534285442855428564285742858428594286042861428624286342864428654286642867428684286942870428714287242873428744287542876428774287842879428804288142882428834288442885428864288742888428894289042891428924289342894428954289642897428984289942900429014290242903429044290542906429074290842909429104291142912429134291442915429164291742918429194292042921429224292342924429254292642927429284292942930429314293242933429344293542936429374293842939429404294142942429434294442945429464294742948429494295042951429524295342954429554295642957429584295942960429614296242963429644296542966429674296842969429704297142972429734297442975429764297742978429794298042981429824298342984429854298642987429884298942990429914299242993429944299542996429974299842999430004300143002430034300443005430064300743008430094301043011430124301343014430154301643017430184301943020430214302243023430244302543026430274302843029430304303143032430334303443035430364303743038430394304043041430424304343044430454304643047430484304943050430514305243053430544305543056430574305843059430604306143062430634306443065430664306743068430694307043071430724307343074430754307643077430784307943080430814308243083430844308543086430874308843089430904309143092430934309443095430964309743098430994310043101431024310343104431054310643107431084310943110431114311243113431144311543116431174311843119431204312143122431234312443125431264312743128431294313043131431324313343134431354313643137431384313943140431414314243143431444314543146431474314843149431504315143152431534315443155431564315743158431594316043161431624316343164431654316643167431684316943170431714317243173431744317543176431774317843179431804318143182431834318443185431864318743188431894319043191431924319343194431954319643197431984319943200432014320243203432044320543206432074320843209432104321143212432134321443215432164321743218432194322043221432224322343224432254322643227432284322943230432314323243233432344323543236432374323843239432404324143242432434324443245432464324743248432494325043251432524325343254432554325643257432584325943260432614326243263432644326543266432674326843269432704327143272432734327443275432764327743278432794328043281432824328343284432854328643287432884328943290432914329243293432944329543296432974329843299433004330143302433034330443305433064330743308433094331043311433124331343314433154331643317433184331943320433214332243323433244332543326433274332843329433304333143332433334333443335433364333743338433394334043341433424334343344433454334643347433484334943350433514335243353433544335543356433574335843359433604336143362433634336443365433664336743368433694337043371433724337343374433754337643377433784337943380433814338243383433844338543386433874338843389433904339143392433934339443395433964339743398433994340043401434024340343404434054340643407434084340943410434114341243413434144341543416434174341843419434204342143422434234342443425434264342743428434294343043431434324343343434434354343643437434384343943440434414344243443434444344543446434474344843449434504345143452434534345443455434564345743458434594346043461434624346343464434654346643467434684346943470434714347243473434744347543476434774347843479434804348143482434834348443485434864348743488434894349043491434924349343494434954349643497434984349943500435014350243503435044350543506435074350843509435104351143512435134351443515435164351743518435194352043521435224352343524435254352643527435284352943530435314353243533435344353543536435374353843539435404354143542435434354443545435464354743548435494355043551435524355343554435554355643557435584355943560435614356243563435644356543566435674356843569435704357143572435734357443575435764357743578435794358043581435824358343584435854358643587435884358943590435914359243593435944359543596435974359843599436004360143602436034360443605436064360743608436094361043611436124361343614436154361643617436184361943620436214362243623436244362543626436274362843629436304363143632436334363443635436364363743638436394364043641436424364343644436454364643647436484364943650436514365243653436544365543656436574365843659436604366143662436634366443665436664366743668436694367043671436724367343674436754367643677436784367943680436814368243683436844368543686436874368843689436904369143692436934369443695436964369743698436994370043701437024370343704437054370643707437084370943710437114371243713437144371543716437174371843719437204372143722437234372443725437264372743728437294373043731437324373343734437354373643737437384373943740437414374243743437444374543746437474374843749437504375143752437534375443755437564375743758437594376043761437624376343764437654376643767437684376943770437714377243773437744377543776437774377843779437804378143782437834378443785437864378743788437894379043791437924379343794437954379643797437984379943800438014380243803438044380543806438074380843809438104381143812438134381443815438164381743818438194382043821438224382343824438254382643827438284382943830438314383243833438344383543836438374383843839438404384143842438434384443845438464384743848438494385043851438524385343854438554385643857438584385943860438614386243863438644386543866438674386843869438704387143872438734387443875438764387743878438794388043881438824388343884438854388643887438884388943890438914389243893438944389543896438974389843899439004390143902439034390443905439064390743908439094391043911439124391343914439154391643917439184391943920439214392243923439244392543926439274392843929439304393143932439334393443935439364393743938439394394043941439424394343944439454394643947439484394943950439514395243953439544395543956439574395843959439604396143962439634396443965439664396743968439694397043971439724397343974439754397643977439784397943980439814398243983439844398543986439874398843989439904399143992439934399443995439964399743998439994400044001440024400344004440054400644007440084400944010440114401244013440144401544016440174401844019440204402144022440234402444025440264402744028440294403044031440324403344034440354403644037440384403944040440414404244043440444404544046440474404844049440504405144052440534405444055440564405744058440594406044061440624406344064440654406644067440684406944070440714407244073440744407544076440774407844079440804408144082440834408444085440864408744088440894409044091440924409344094440954409644097440984409944100441014410244103441044410544106441074410844109441104411144112441134411444115441164411744118441194412044121441224412344124441254412644127441284412944130441314413244133441344413544136441374413844139441404414144142441434414444145441464414744148441494415044151441524415344154441554415644157441584415944160441614416244163441644416544166441674416844169441704417144172441734417444175441764417744178441794418044181441824418344184441854418644187441884418944190441914419244193441944419544196441974419844199442004420144202442034420444205442064420744208442094421044211442124421344214442154421644217442184421944220442214422244223442244422544226442274422844229442304423144232442334423444235442364423744238442394424044241442424424344244442454424644247442484424944250442514425244253442544425544256442574425844259442604426144262442634426444265442664426744268442694427044271442724427344274442754427644277442784427944280442814428244283442844428544286442874428844289442904429144292442934429444295442964429744298442994430044301443024430344304443054430644307443084430944310443114431244313443144431544316443174431844319443204432144322443234432444325443264432744328443294433044331443324433344334443354433644337443384433944340443414434244343443444434544346443474434844349443504435144352443534435444355443564435744358443594436044361443624436344364443654436644367443684436944370443714437244373443744437544376443774437844379443804438144382443834438444385443864438744388443894439044391443924439344394443954439644397443984439944400444014440244403444044440544406444074440844409444104441144412444134441444415444164441744418444194442044421444224442344424444254442644427444284442944430444314443244433444344443544436444374443844439444404444144442444434444444445444464444744448444494445044451444524445344454444554445644457444584445944460444614446244463444644446544466444674446844469444704447144472444734447444475444764447744478444794448044481444824448344484444854448644487444884448944490444914449244493444944449544496444974449844499445004450144502445034450444505445064450744508445094451044511445124451344514445154451644517445184451944520445214452244523445244452544526445274452844529445304453144532445334453444535445364453744538445394454044541445424454344544445454454644547445484454944550445514455244553445544455544556445574455844559445604456144562445634456444565445664456744568445694457044571445724457344574445754457644577445784457944580445814458244583445844458544586445874458844589445904459144592445934459444595445964459744598445994460044601446024460344604446054460644607446084460944610446114461244613446144461544616446174461844619446204462144622446234462444625446264462744628446294463044631446324463344634446354463644637446384463944640446414464244643446444464544646446474464844649446504465144652446534465444655446564465744658446594466044661446624466344664446654466644667446684466944670446714467244673446744467544676446774467844679446804468144682446834468444685446864468744688446894469044691446924469344694446954469644697446984469944700447014470244703447044470544706447074470844709447104471144712447134471444715447164471744718447194472044721447224472344724447254472644727447284472944730447314473244733447344473544736447374473844739447404474144742447434474444745447464474744748447494475044751447524475344754447554475644757447584475944760447614476244763447644476544766447674476844769447704477144772447734477444775447764477744778447794478044781447824478344784447854478644787447884478944790447914479244793447944479544796447974479844799448004480144802448034480444805448064480744808448094481044811448124481344814448154481644817448184481944820448214482244823448244482544826448274482844829448304483144832448334483444835448364483744838448394484044841448424484344844448454484644847448484484944850448514485244853448544485544856448574485844859448604486144862448634486444865448664486744868448694487044871448724487344874448754487644877448784487944880448814488244883448844488544886448874488844889448904489144892448934489444895448964489744898448994490044901449024490344904449054490644907449084490944910449114491244913449144491544916449174491844919449204492144922449234492444925449264492744928449294493044931449324493344934449354493644937449384493944940449414494244943449444494544946449474494844949449504495144952449534495444955449564495744958449594496044961449624496344964449654496644967449684496944970449714497244973449744497544976449774497844979449804498144982449834498444985449864498744988449894499044991449924499344994449954499644997449984499945000450014500245003450044500545006450074500845009450104501145012450134501445015450164501745018450194502045021450224502345024450254502645027450284502945030450314503245033450344503545036450374503845039450404504145042450434504445045450464504745048450494505045051450524505345054450554505645057450584505945060450614506245063450644506545066450674506845069450704507145072450734507445075450764507745078450794508045081450824508345084450854508645087450884508945090450914509245093450944509545096450974509845099451004510145102451034510445105451064510745108451094511045111451124511345114451154511645117451184511945120451214512245123451244512545126451274512845129451304513145132451334513445135451364513745138451394514045141451424514345144451454514645147451484514945150451514515245153451544515545156451574515845159451604516145162451634516445165451664516745168451694517045171451724517345174451754517645177451784517945180451814518245183451844518545186451874518845189451904519145192451934519445195451964519745198451994520045201452024520345204452054520645207452084520945210452114521245213452144521545216452174521845219452204522145222452234522445225452264522745228452294523045231452324523345234452354523645237452384523945240452414524245243452444524545246452474524845249452504525145252452534525445255452564525745258452594526045261452624526345264452654526645267452684526945270452714527245273452744527545276452774527845279452804528145282452834528445285452864528745288452894529045291452924529345294452954529645297452984529945300453014530245303453044530545306453074530845309453104531145312453134531445315453164531745318453194532045321453224532345324453254532645327453284532945330453314533245333453344533545336453374533845339453404534145342453434534445345453464534745348453494535045351453524535345354453554535645357453584535945360453614536245363453644536545366453674536845369453704537145372453734537445375453764537745378453794538045381453824538345384453854538645387453884538945390453914539245393453944539545396453974539845399454004540145402454034540445405454064540745408454094541045411454124541345414454154541645417454184541945420454214542245423454244542545426454274542845429454304543145432454334543445435454364543745438454394544045441454424544345444454454544645447454484544945450454514545245453454544545545456454574545845459454604546145462454634546445465454664546745468454694547045471454724547345474454754547645477454784547945480454814548245483454844548545486454874548845489454904549145492454934549445495454964549745498454994550045501455024550345504455054550645507455084550945510455114551245513455144551545516455174551845519455204552145522455234552445525455264552745528455294553045531455324553345534455354553645537455384553945540455414554245543455444554545546455474554845549455504555145552455534555445555455564555745558455594556045561455624556345564455654556645567455684556945570455714557245573455744557545576455774557845579455804558145582455834558445585455864558745588455894559045591455924559345594455954559645597455984559945600456014560245603456044560545606456074560845609456104561145612456134561445615456164561745618456194562045621456224562345624456254562645627456284562945630456314563245633456344563545636456374563845639456404564145642456434564445645456464564745648456494565045651456524565345654456554565645657456584565945660456614566245663456644566545666456674566845669456704567145672456734567445675456764567745678456794568045681456824568345684456854568645687456884568945690456914569245693456944569545696456974569845699457004570145702457034570445705457064570745708457094571045711457124571345714457154571645717457184571945720457214572245723457244572545726457274572845729457304573145732457334573445735457364573745738457394574045741457424574345744457454574645747457484574945750457514575245753457544575545756457574575845759457604576145762457634576445765457664576745768457694577045771457724577345774457754577645777457784577945780457814578245783457844578545786457874578845789457904579145792457934579445795457964579745798457994580045801458024580345804458054580645807458084580945810458114581245813458144581545816458174581845819458204582145822458234582445825458264582745828458294583045831458324583345834458354583645837458384583945840458414584245843458444584545846458474584845849458504585145852458534585445855458564585745858458594586045861458624586345864458654586645867458684586945870458714587245873458744587545876458774587845879458804588145882458834588445885458864588745888458894589045891458924589345894458954589645897458984589945900459014590245903459044590545906459074590845909459104591145912459134591445915459164591745918459194592045921459224592345924459254592645927459284592945930459314593245933459344593545936459374593845939459404594145942459434594445945459464594745948459494595045951459524595345954459554595645957459584595945960459614596245963459644596545966459674596845969459704597145972459734597445975459764597745978459794598045981459824598345984459854598645987459884598945990459914599245993459944599545996459974599845999460004600146002460034600446005460064600746008460094601046011460124601346014460154601646017460184601946020460214602246023460244602546026460274602846029460304603146032460334603446035460364603746038460394604046041460424604346044460454604646047460484604946050460514605246053460544605546056460574605846059460604606146062460634606446065460664606746068460694607046071460724607346074460754607646077460784607946080460814608246083460844608546086460874608846089460904609146092460934609446095460964609746098460994610046101461024610346104461054610646107461084610946110461114611246113461144611546116461174611846119461204612146122461234612446125461264612746128461294613046131461324613346134461354613646137461384613946140461414614246143461444614546146461474614846149461504615146152461534615446155461564615746158461594616046161461624616346164461654616646167461684616946170461714617246173461744617546176461774617846179461804618146182461834618446185461864618746188461894619046191461924619346194461954619646197461984619946200462014620246203462044620546206462074620846209462104621146212462134621446215462164621746218462194622046221462224622346224462254622646227462284622946230462314623246233462344623546236462374623846239462404624146242462434624446245462464624746248462494625046251462524625346254462554625646257462584625946260462614626246263462644626546266462674626846269462704627146272462734627446275462764627746278462794628046281462824628346284462854628646287462884628946290462914629246293462944629546296462974629846299463004630146302463034630446305463064630746308463094631046311463124631346314463154631646317463184631946320463214632246323463244632546326463274632846329463304633146332463334633446335463364633746338463394634046341463424634346344463454634646347463484634946350463514635246353463544635546356463574635846359463604636146362463634636446365463664636746368463694637046371463724637346374463754637646377463784637946380463814638246383463844638546386463874638846389463904639146392463934639446395463964639746398463994640046401464024640346404464054640646407464084640946410464114641246413464144641546416464174641846419464204642146422464234642446425464264642746428464294643046431464324643346434464354643646437464384643946440464414644246443464444644546446464474644846449464504645146452464534645446455464564645746458464594646046461464624646346464464654646646467464684646946470464714647246473464744647546476464774647846479464804648146482464834648446485464864648746488464894649046491464924649346494464954649646497464984649946500465014650246503465044650546506465074650846509465104651146512465134651446515465164651746518465194652046521465224652346524465254652646527465284652946530465314653246533465344653546536465374653846539465404654146542465434654446545465464654746548465494655046551465524655346554465554655646557465584655946560465614656246563465644656546566465674656846569465704657146572465734657446575465764657746578465794658046581465824658346584465854658646587465884658946590465914659246593465944659546596465974659846599466004660146602466034660446605466064660746608466094661046611466124661346614466154661646617466184661946620466214662246623466244662546626466274662846629466304663146632466334663446635466364663746638466394664046641466424664346644466454664646647466484664946650466514665246653466544665546656466574665846659466604666146662466634666446665466664666746668466694667046671466724667346674466754667646677466784667946680466814668246683466844668546686466874668846689466904669146692466934669446695466964669746698466994670046701467024670346704467054670646707467084670946710467114671246713467144671546716467174671846719467204672146722467234672446725467264672746728467294673046731467324673346734467354673646737467384673946740467414674246743467444674546746467474674846749467504675146752467534675446755467564675746758467594676046761467624676346764467654676646767467684676946770467714677246773467744677546776467774677846779467804678146782467834678446785467864678746788467894679046791467924679346794467954679646797467984679946800468014680246803468044680546806468074680846809468104681146812468134681446815468164681746818468194682046821468224682346824468254682646827468284682946830468314683246833468344683546836468374683846839468404684146842468434684446845468464684746848468494685046851468524685346854468554685646857468584685946860468614686246863468644686546866468674686846869468704687146872468734687446875468764687746878468794688046881468824688346884468854688646887468884688946890468914689246893468944689546896468974689846899469004690146902469034690446905469064690746908469094691046911469124691346914469154691646917469184691946920469214692246923469244692546926469274692846929469304693146932469334693446935469364693746938469394694046941469424694346944469454694646947469484694946950469514695246953469544695546956469574695846959469604696146962469634696446965469664696746968469694697046971469724697346974469754697646977469784697946980469814698246983469844698546986469874698846989469904699146992469934699446995469964699746998469994700047001470024700347004470054700647007470084700947010470114701247013470144701547016470174701847019470204702147022470234702447025470264702747028470294703047031470324703347034470354703647037470384703947040470414704247043470444704547046470474704847049470504705147052470534705447055470564705747058470594706047061470624706347064470654706647067470684706947070470714707247073470744707547076470774707847079470804708147082470834708447085470864708747088470894709047091470924709347094470954709647097470984709947100471014710247103471044710547106471074710847109471104711147112471134711447115471164711747118471194712047121471224712347124471254712647127471284712947130471314713247133471344713547136471374713847139471404714147142471434714447145471464714747148471494715047151471524715347154471554715647157471584715947160471614716247163471644716547166471674716847169471704717147172471734717447175471764717747178471794718047181471824718347184471854718647187471884718947190471914719247193471944719547196471974719847199472004720147202472034720447205472064720747208472094721047211472124721347214472154721647217472184721947220472214722247223472244722547226472274722847229472304723147232472334723447235472364723747238472394724047241472424724347244472454724647247472484724947250472514725247253472544725547256472574725847259472604726147262472634726447265472664726747268472694727047271472724727347274472754727647277472784727947280472814728247283472844728547286472874728847289472904729147292472934729447295472964729747298472994730047301473024730347304473054730647307473084730947310473114731247313473144731547316473174731847319473204732147322473234732447325473264732747328473294733047331473324733347334473354733647337473384733947340473414734247343473444734547346473474734847349473504735147352473534735447355473564735747358473594736047361473624736347364473654736647367473684736947370473714737247373473744737547376473774737847379473804738147382473834738447385473864738747388473894739047391473924739347394473954739647397473984739947400474014740247403474044740547406474074740847409474104741147412474134741447415474164741747418474194742047421474224742347424474254742647427474284742947430474314743247433474344743547436474374743847439474404744147442474434744447445474464744747448474494745047451474524745347454474554745647457474584745947460474614746247463474644746547466474674746847469474704747147472474734747447475474764747747478474794748047481474824748347484474854748647487474884748947490474914749247493474944749547496474974749847499475004750147502475034750447505475064750747508475094751047511475124751347514475154751647517475184751947520475214752247523475244752547526475274752847529475304753147532475334753447535475364753747538475394754047541475424754347544475454754647547475484754947550475514755247553475544755547556475574755847559475604756147562475634756447565475664756747568475694757047571475724757347574475754757647577475784757947580475814758247583475844758547586475874758847589475904759147592475934759447595475964759747598475994760047601476024760347604476054760647607476084760947610476114761247613476144761547616476174761847619476204762147622476234762447625476264762747628476294763047631476324763347634476354763647637476384763947640476414764247643476444764547646476474764847649476504765147652476534765447655476564765747658476594766047661476624766347664476654766647667476684766947670476714767247673476744767547676476774767847679476804768147682476834768447685476864768747688476894769047691476924769347694476954769647697476984769947700477014770247703477044770547706477074770847709477104771147712477134771447715477164771747718477194772047721477224772347724477254772647727477284772947730477314773247733477344773547736477374773847739477404774147742477434774447745477464774747748477494775047751477524775347754477554775647757477584775947760477614776247763477644776547766477674776847769477704777147772477734777447775477764777747778477794778047781477824778347784477854778647787477884778947790477914779247793477944779547796477974779847799478004780147802478034780447805478064780747808478094781047811478124781347814478154781647817478184781947820478214782247823478244782547826478274782847829478304783147832478334783447835478364783747838478394784047841478424784347844478454784647847478484784947850478514785247853478544785547856478574785847859478604786147862478634786447865478664786747868478694787047871478724787347874478754787647877478784787947880478814788247883478844788547886478874788847889478904789147892478934789447895478964789747898478994790047901479024790347904479054790647907479084790947910479114791247913479144791547916479174791847919479204792147922479234792447925479264792747928479294793047931479324793347934479354793647937479384793947940479414794247943479444794547946479474794847949479504795147952479534795447955479564795747958479594796047961479624796347964479654796647967479684796947970479714797247973479744797547976479774797847979479804798147982479834798447985479864798747988479894799047991479924799347994479954799647997479984799948000480014800248003480044800548006480074800848009480104801148012480134801448015480164801748018480194802048021480224802348024480254802648027480284802948030480314803248033480344803548036480374803848039480404804148042480434804448045480464804748048480494805048051480524805348054480554805648057480584805948060480614806248063480644806548066480674806848069480704807148072480734807448075480764807748078480794808048081480824808348084480854808648087480884808948090480914809248093480944809548096480974809848099481004810148102481034810448105481064810748108481094811048111481124811348114481154811648117481184811948120481214812248123481244812548126481274812848129481304813148132481334813448135481364813748138481394814048141481424814348144481454814648147481484814948150481514815248153481544815548156481574815848159481604816148162481634816448165481664816748168481694817048171481724817348174481754817648177481784817948180481814818248183481844818548186481874818848189481904819148192481934819448195481964819748198481994820048201482024820348204482054820648207482084820948210482114821248213482144821548216482174821848219482204822148222482234822448225482264822748228482294823048231482324823348234482354823648237482384823948240482414824248243482444824548246482474824848249482504825148252482534825448255482564825748258482594826048261482624826348264482654826648267482684826948270482714827248273482744827548276482774827848279482804828148282482834828448285482864828748288482894829048291482924829348294482954829648297482984829948300483014830248303483044830548306483074830848309483104831148312483134831448315483164831748318483194832048321483224832348324483254832648327483284832948330483314833248333483344833548336483374833848339483404834148342483434834448345483464834748348483494835048351483524835348354483554835648357483584835948360483614836248363483644836548366483674836848369483704837148372483734837448375483764837748378483794838048381483824838348384483854838648387483884838948390483914839248393483944839548396483974839848399484004840148402484034840448405484064840748408484094841048411484124841348414484154841648417484184841948420484214842248423484244842548426484274842848429484304843148432484334843448435484364843748438484394844048441484424844348444484454844648447484484844948450484514845248453484544845548456484574845848459484604846148462484634846448465484664846748468484694847048471484724847348474484754847648477484784847948480484814848248483484844848548486484874848848489484904849148492484934849448495484964849748498484994850048501485024850348504485054850648507485084850948510485114851248513485144851548516485174851848519485204852148522485234852448525485264852748528485294853048531485324853348534485354853648537485384853948540485414854248543485444854548546485474854848549485504855148552485534855448555485564855748558485594856048561485624856348564485654856648567485684856948570485714857248573485744857548576485774857848579485804858148582485834858448585485864858748588485894859048591485924859348594485954859648597485984859948600486014860248603486044860548606486074860848609486104861148612486134861448615486164861748618486194862048621486224862348624486254862648627486284862948630486314863248633486344863548636486374863848639486404864148642486434864448645486464864748648486494865048651486524865348654486554865648657486584865948660486614866248663486644866548666486674866848669486704867148672486734867448675486764867748678486794868048681486824868348684486854868648687486884868948690486914869248693486944869548696486974869848699487004870148702487034870448705487064870748708487094871048711487124871348714487154871648717487184871948720487214872248723487244872548726487274872848729487304873148732487334873448735487364873748738487394874048741487424874348744487454874648747487484874948750487514875248753487544875548756487574875848759487604876148762487634876448765487664876748768487694877048771487724877348774487754877648777487784877948780487814878248783487844878548786487874878848789487904879148792487934879448795487964879748798487994880048801488024880348804488054880648807488084880948810488114881248813488144881548816488174881848819488204882148822488234882448825488264882748828488294883048831488324883348834488354883648837488384883948840488414884248843488444884548846488474884848849488504885148852488534885448855488564885748858488594886048861488624886348864488654886648867488684886948870488714887248873488744887548876488774887848879488804888148882488834888448885488864888748888488894889048891488924889348894488954889648897488984889948900489014890248903489044890548906489074890848909489104891148912489134891448915489164891748918489194892048921489224892348924489254892648927489284892948930489314893248933489344893548936489374893848939489404894148942489434894448945489464894748948489494895048951489524895348954489554895648957489584895948960489614896248963489644896548966489674896848969489704897148972489734897448975489764897748978489794898048981489824898348984489854898648987489884898948990489914899248993489944899548996489974899848999490004900149002490034900449005490064900749008490094901049011490124901349014490154901649017490184901949020490214902249023490244902549026490274902849029490304903149032490334903449035490364903749038490394904049041490424904349044490454904649047490484904949050490514905249053490544905549056490574905849059490604906149062490634906449065490664906749068490694907049071490724907349074490754907649077490784907949080490814908249083490844908549086490874908849089490904909149092490934909449095490964909749098490994910049101491024910349104491054910649107491084910949110491114911249113491144911549116491174911849119491204912149122491234912449125491264912749128491294913049131491324913349134491354913649137491384913949140491414914249143491444914549146491474914849149491504915149152491534915449155491564915749158491594916049161491624916349164491654916649167491684916949170491714917249173491744917549176491774917849179491804918149182491834918449185491864918749188491894919049191491924919349194491954919649197491984919949200492014920249203492044920549206492074920849209492104921149212492134921449215492164921749218492194922049221492224922349224492254922649227492284922949230492314923249233492344923549236492374923849239492404924149242492434924449245492464924749248492494925049251492524925349254492554925649257492584925949260492614926249263492644926549266492674926849269492704927149272492734927449275492764927749278492794928049281492824928349284492854928649287492884928949290492914929249293492944929549296492974929849299493004930149302493034930449305493064930749308493094931049311493124931349314493154931649317493184931949320493214932249323493244932549326493274932849329493304933149332493334933449335493364933749338493394934049341493424934349344493454934649347493484934949350493514935249353493544935549356493574935849359493604936149362493634936449365493664936749368493694937049371493724937349374493754937649377493784937949380493814938249383493844938549386493874938849389493904939149392493934939449395493964939749398493994940049401494024940349404494054940649407494084940949410494114941249413494144941549416494174941849419494204942149422494234942449425494264942749428494294943049431494324943349434494354943649437494384943949440494414944249443494444944549446494474944849449494504945149452494534945449455494564945749458494594946049461494624946349464494654946649467494684946949470494714947249473494744947549476494774947849479494804948149482494834948449485494864948749488494894949049491494924949349494494954949649497494984949949500495014950249503495044950549506495074950849509495104951149512495134951449515495164951749518495194952049521495224952349524495254952649527495284952949530495314953249533495344953549536495374953849539495404954149542495434954449545495464954749548495494955049551495524955349554495554955649557495584955949560495614956249563495644956549566495674956849569495704957149572495734957449575495764957749578495794958049581495824958349584495854958649587495884958949590495914959249593495944959549596495974959849599496004960149602496034960449605496064960749608496094961049611496124961349614496154961649617496184961949620496214962249623496244962549626496274962849629496304963149632496334963449635496364963749638496394964049641496424964349644496454964649647496484964949650496514965249653496544965549656496574965849659496604966149662496634966449665496664966749668496694967049671496724967349674496754967649677496784967949680496814968249683496844968549686496874968849689496904969149692496934969449695496964969749698496994970049701497024970349704497054970649707497084970949710497114971249713497144971549716497174971849719497204972149722497234972449725497264972749728497294973049731497324973349734497354973649737497384973949740497414974249743497444974549746497474974849749497504975149752497534975449755497564975749758497594976049761497624976349764497654976649767497684976949770497714977249773497744977549776497774977849779497804978149782497834978449785497864978749788497894979049791497924979349794497954979649797497984979949800498014980249803498044980549806498074980849809498104981149812498134981449815498164981749818498194982049821498224982349824498254982649827498284982949830498314983249833498344983549836498374983849839498404984149842498434984449845498464984749848498494985049851498524985349854498554985649857498584985949860498614986249863498644986549866498674986849869498704987149872498734987449875498764987749878498794988049881498824988349884498854988649887498884988949890498914989249893498944989549896498974989849899499004990149902499034990449905499064990749908499094991049911499124991349914499154991649917499184991949920499214992249923499244992549926499274992849929499304993149932499334993449935499364993749938499394994049941499424994349944499454994649947499484994949950499514995249953499544995549956499574995849959499604996149962499634996449965499664996749968499694997049971499724997349974499754997649977499784997949980499814998249983499844998549986499874998849989499904999149992499934999449995499964999749998499995000050001500025000350004500055000650007500085000950010500115001250013500145001550016500175001850019500205002150022500235002450025500265002750028500295003050031500325003350034500355003650037500385003950040500415004250043500445004550046500475004850049500505005150052500535005450055500565005750058500595006050061500625006350064500655006650067500685006950070500715007250073500745007550076500775007850079500805008150082500835008450085500865008750088500895009050091500925009350094500955009650097500985009950100501015010250103501045010550106501075010850109501105011150112501135011450115501165011750118501195012050121501225012350124501255012650127501285012950130501315013250133501345013550136501375013850139501405014150142501435014450145501465014750148501495015050151501525015350154501555015650157501585015950160501615016250163501645016550166501675016850169501705017150172501735017450175501765017750178501795018050181501825018350184501855018650187501885018950190501915019250193501945019550196501975019850199502005020150202502035020450205502065020750208502095021050211502125021350214502155021650217502185021950220502215022250223502245022550226502275022850229502305023150232502335023450235502365023750238502395024050241502425024350244502455024650247502485024950250502515025250253502545025550256502575025850259502605026150262502635026450265502665026750268502695027050271502725027350274502755027650277502785027950280502815028250283502845028550286502875028850289502905029150292502935029450295502965029750298502995030050301503025030350304503055030650307503085030950310503115031250313503145031550316503175031850319503205032150322503235032450325503265032750328503295033050331503325033350334503355033650337503385033950340503415034250343503445034550346503475034850349503505035150352503535035450355503565035750358503595036050361503625036350364503655036650367503685036950370503715037250373503745037550376503775037850379503805038150382503835038450385503865038750388503895039050391503925039350394503955039650397503985039950400504015040250403504045040550406504075040850409504105041150412504135041450415504165041750418504195042050421504225042350424504255042650427504285042950430504315043250433504345043550436504375043850439504405044150442504435044450445504465044750448504495045050451504525045350454504555045650457504585045950460504615046250463504645046550466504675046850469504705047150472504735047450475504765047750478504795048050481504825048350484504855048650487504885048950490504915049250493504945049550496504975049850499505005050150502505035050450505505065050750508505095051050511505125051350514505155051650517505185051950520505215052250523505245052550526505275052850529505305053150532505335053450535505365053750538505395054050541505425054350544505455054650547505485054950550505515055250553505545055550556505575055850559505605056150562505635056450565505665056750568505695057050571505725057350574505755057650577505785057950580505815058250583505845058550586505875058850589505905059150592505935059450595505965059750598505995060050601506025060350604506055060650607506085060950610506115061250613506145061550616506175061850619506205062150622506235062450625506265062750628506295063050631506325063350634506355063650637506385063950640506415064250643506445064550646506475064850649506505065150652506535065450655506565065750658506595066050661506625066350664506655066650667506685066950670506715067250673506745067550676506775067850679506805068150682506835068450685506865068750688506895069050691506925069350694506955069650697506985069950700507015070250703507045070550706507075070850709507105071150712507135071450715507165071750718507195072050721507225072350724507255072650727507285072950730507315073250733507345073550736507375073850739507405074150742507435074450745507465074750748507495075050751507525075350754507555075650757507585075950760507615076250763507645076550766507675076850769507705077150772507735077450775507765077750778507795078050781507825078350784507855078650787507885078950790507915079250793507945079550796507975079850799508005080150802508035080450805508065080750808508095081050811508125081350814508155081650817508185081950820508215082250823508245082550826508275082850829508305083150832508335083450835508365083750838508395084050841508425084350844508455084650847508485084950850508515085250853508545085550856508575085850859508605086150862508635086450865508665086750868508695087050871508725087350874508755087650877508785087950880508815088250883508845088550886508875088850889508905089150892508935089450895508965089750898508995090050901509025090350904509055090650907509085090950910509115091250913509145091550916509175091850919509205092150922509235092450925509265092750928509295093050931509325093350934509355093650937509385093950940509415094250943509445094550946509475094850949509505095150952509535095450955509565095750958509595096050961509625096350964509655096650967509685096950970509715097250973509745097550976509775097850979509805098150982509835098450985509865098750988509895099050991509925099350994509955099650997509985099951000510015100251003510045100551006510075100851009510105101151012510135101451015510165101751018510195102051021510225102351024510255102651027510285102951030510315103251033510345103551036510375103851039510405104151042510435104451045510465104751048510495105051051510525105351054510555105651057510585105951060510615106251063510645106551066510675106851069510705107151072510735107451075510765107751078510795108051081510825108351084510855108651087510885108951090510915109251093510945109551096510975109851099511005110151102511035110451105511065110751108511095111051111511125111351114511155111651117511185111951120511215112251123511245112551126511275112851129511305113151132511335113451135511365113751138511395114051141511425114351144511455114651147511485114951150511515115251153511545115551156511575115851159511605116151162511635116451165511665116751168511695117051171511725117351174511755117651177511785117951180511815118251183511845118551186511875118851189511905119151192511935119451195511965119751198511995120051201512025120351204512055120651207512085120951210512115121251213512145121551216512175121851219512205122151222512235122451225512265122751228512295123051231512325123351234512355123651237512385123951240512415124251243512445124551246512475124851249512505125151252512535125451255512565125751258512595126051261512625126351264512655126651267512685126951270512715127251273512745127551276512775127851279512805128151282512835128451285512865128751288512895129051291512925129351294512955129651297512985129951300513015130251303513045130551306513075130851309513105131151312513135131451315513165131751318513195132051321513225132351324513255132651327513285132951330513315133251333513345133551336513375133851339513405134151342513435134451345513465134751348513495135051351513525135351354513555135651357513585135951360513615136251363513645136551366513675136851369513705137151372513735137451375513765137751378513795138051381513825138351384513855138651387513885138951390513915139251393513945139551396513975139851399514005140151402514035140451405514065140751408514095141051411514125141351414514155141651417514185141951420514215142251423514245142551426514275142851429514305143151432514335143451435514365143751438514395144051441514425144351444514455144651447514485144951450514515145251453514545145551456514575145851459514605146151462514635146451465514665146751468514695147051471514725147351474514755147651477514785147951480514815148251483514845148551486514875148851489514905149151492514935149451495514965149751498514995150051501515025150351504515055150651507515085150951510515115151251513515145151551516515175151851519515205152151522515235152451525515265152751528515295153051531515325153351534515355153651537515385153951540515415154251543515445154551546515475154851549515505155151552515535155451555515565155751558515595156051561515625156351564515655156651567515685156951570515715157251573515745157551576515775157851579515805158151582515835158451585515865158751588515895159051591515925159351594515955159651597515985159951600516015160251603516045160551606516075160851609516105161151612516135161451615516165161751618516195162051621516225162351624516255162651627516285162951630516315163251633516345163551636516375163851639516405164151642516435164451645516465164751648516495165051651516525165351654516555165651657516585165951660516615166251663516645166551666516675166851669516705167151672516735167451675516765167751678516795168051681516825168351684516855168651687516885168951690516915169251693516945169551696516975169851699517005170151702517035170451705517065170751708517095171051711517125171351714517155171651717517185171951720517215172251723517245172551726517275172851729517305173151732517335173451735517365173751738517395174051741517425174351744517455174651747517485174951750517515175251753517545175551756517575175851759517605176151762517635176451765517665176751768517695177051771517725177351774517755177651777517785177951780517815178251783517845178551786517875178851789517905179151792517935179451795517965179751798517995180051801518025180351804518055180651807518085180951810518115181251813518145181551816518175181851819518205182151822518235182451825518265182751828518295183051831518325183351834518355183651837518385183951840518415184251843518445184551846518475184851849518505185151852518535185451855518565185751858518595186051861518625186351864518655186651867518685186951870518715187251873518745187551876518775187851879518805188151882518835188451885518865188751888518895189051891518925189351894518955189651897518985189951900519015190251903519045190551906519075190851909519105191151912519135191451915519165191751918519195192051921519225192351924519255192651927519285192951930519315193251933519345193551936519375193851939519405194151942519435194451945519465194751948519495195051951519525195351954519555195651957519585195951960519615196251963519645196551966519675196851969519705197151972519735197451975519765197751978519795198051981519825198351984519855198651987519885198951990519915199251993519945199551996519975199851999520005200152002520035200452005520065200752008520095201052011520125201352014520155201652017520185201952020520215202252023520245202552026520275202852029520305203152032520335203452035520365203752038520395204052041520425204352044520455204652047520485204952050520515205252053520545205552056520575205852059520605206152062520635206452065520665206752068520695207052071520725207352074520755207652077520785207952080520815208252083520845208552086520875208852089520905209152092520935209452095520965209752098520995210052101521025210352104521055210652107521085210952110521115211252113521145211552116521175211852119521205212152122521235212452125521265212752128521295213052131521325213352134521355213652137521385213952140521415214252143521445214552146521475214852149521505215152152521535215452155521565215752158521595216052161521625216352164521655216652167521685216952170521715217252173521745217552176521775217852179521805218152182521835218452185521865218752188521895219052191521925219352194521955219652197521985219952200522015220252203522045220552206522075220852209522105221152212522135221452215522165221752218522195222052221522225222352224522255222652227522285222952230522315223252233522345223552236522375223852239522405224152242522435224452245522465224752248522495225052251522525225352254522555225652257522585225952260522615226252263522645226552266522675226852269522705227152272522735227452275522765227752278522795228052281522825228352284522855228652287522885228952290522915229252293522945229552296522975229852299523005230152302523035230452305523065230752308523095231052311523125231352314523155231652317523185231952320523215232252323523245232552326523275232852329523305233152332523335233452335523365233752338523395234052341523425234352344523455234652347523485234952350523515235252353523545235552356523575235852359523605236152362523635236452365523665236752368523695237052371523725237352374523755237652377523785237952380523815238252383523845238552386523875238852389523905239152392523935239452395523965239752398523995240052401524025240352404524055240652407524085240952410524115241252413524145241552416524175241852419524205242152422524235242452425524265242752428524295243052431524325243352434524355243652437524385243952440524415244252443524445244552446524475244852449524505245152452524535245452455524565245752458524595246052461524625246352464524655246652467524685246952470524715247252473524745247552476524775247852479524805248152482524835248452485524865248752488524895249052491524925249352494524955249652497524985249952500525015250252503525045250552506525075250852509525105251152512525135251452515525165251752518525195252052521525225252352524525255252652527525285252952530525315253252533525345253552536525375253852539525405254152542525435254452545525465254752548525495255052551525525255352554525555255652557525585255952560525615256252563525645256552566525675256852569525705257152572525735257452575525765257752578525795258052581525825258352584525855258652587525885258952590525915259252593525945259552596525975259852599526005260152602526035260452605526065260752608526095261052611526125261352614526155261652617526185261952620526215262252623526245262552626526275262852629526305263152632526335263452635526365263752638526395264052641526425264352644526455264652647526485264952650526515265252653526545265552656526575265852659526605266152662526635266452665526665266752668526695267052671526725267352674526755267652677526785267952680526815268252683526845268552686526875268852689526905269152692526935269452695526965269752698526995270052701527025270352704527055270652707527085270952710527115271252713527145271552716527175271852719527205272152722527235272452725527265272752728527295273052731527325273352734527355273652737527385273952740527415274252743527445274552746527475274852749527505275152752527535275452755527565275752758527595276052761527625276352764527655276652767527685276952770527715277252773527745277552776527775277852779527805278152782527835278452785527865278752788527895279052791527925279352794527955279652797527985279952800528015280252803528045280552806528075280852809528105281152812528135281452815528165281752818528195282052821528225282352824528255282652827528285282952830528315283252833528345283552836528375283852839528405284152842528435284452845528465284752848528495285052851528525285352854528555285652857528585285952860528615286252863528645286552866528675286852869528705287152872528735287452875528765287752878528795288052881528825288352884528855288652887528885288952890528915289252893528945289552896528975289852899529005290152902529035290452905529065290752908529095291052911529125291352914529155291652917529185291952920529215292252923529245292552926529275292852929529305293152932529335293452935529365293752938529395294052941529425294352944529455294652947529485294952950529515295252953529545295552956529575295852959529605296152962529635296452965529665296752968529695297052971529725297352974529755297652977529785297952980529815298252983529845298552986529875298852989529905299152992529935299452995529965299752998529995300053001530025300353004530055300653007530085300953010530115301253013530145301553016530175301853019530205302153022530235302453025530265302753028530295303053031530325303353034530355303653037530385303953040530415304253043530445304553046530475304853049530505305153052530535305453055530565305753058530595306053061530625306353064530655306653067530685306953070530715307253073530745307553076530775307853079530805308153082530835308453085530865308753088530895309053091530925309353094530955309653097530985309953100531015310253103531045310553106531075310853109531105311153112531135311453115531165311753118531195312053121531225312353124531255312653127531285312953130531315313253133531345313553136531375313853139531405314153142531435314453145531465314753148531495315053151531525315353154531555315653157531585315953160531615316253163531645316553166531675316853169531705317153172531735317453175531765317753178531795318053181531825318353184531855318653187531885318953190531915319253193531945319553196531975319853199532005320153202532035320453205532065320753208532095321053211532125321353214532155321653217532185321953220532215322253223532245322553226532275322853229532305323153232532335323453235532365323753238532395324053241532425324353244532455324653247532485324953250532515325253253532545325553256532575325853259532605326153262532635326453265532665326753268532695327053271532725327353274532755327653277532785327953280532815328253283532845328553286532875328853289532905329153292532935329453295532965329753298532995330053301533025330353304533055330653307533085330953310533115331253313533145331553316533175331853319533205332153322533235332453325533265332753328533295333053331533325333353334533355333653337533385333953340533415334253343533445334553346533475334853349533505335153352533535335453355533565335753358533595336053361533625336353364533655336653367533685336953370533715337253373533745337553376533775337853379533805338153382533835338453385533865338753388533895339053391533925339353394533955339653397533985339953400534015340253403534045340553406534075340853409534105341153412534135341453415534165341753418534195342053421534225342353424534255342653427534285342953430534315343253433534345343553436534375343853439534405344153442534435344453445534465344753448534495345053451534525345353454534555345653457534585345953460534615346253463534645346553466534675346853469534705347153472534735347453475534765347753478534795348053481534825348353484534855348653487534885348953490534915349253493534945349553496534975349853499535005350153502535035350453505535065350753508535095351053511535125351353514535155351653517535185351953520535215352253523535245352553526535275352853529535305353153532535335353453535535365353753538535395354053541535425354353544535455354653547535485354953550535515355253553535545355553556535575355853559535605356153562535635356453565535665356753568535695357053571535725357353574535755357653577535785357953580535815358253583535845358553586535875358853589535905359153592535935359453595535965359753598535995360053601536025360353604536055360653607536085360953610536115361253613536145361553616536175361853619536205362153622536235362453625536265362753628536295363053631536325363353634536355363653637536385363953640536415364253643536445364553646536475364853649536505365153652536535365453655536565365753658536595366053661536625366353664536655366653667536685366953670536715367253673536745367553676536775367853679536805368153682536835368453685536865368753688536895369053691536925369353694536955369653697536985369953700537015370253703537045370553706537075370853709537105371153712537135371453715537165371753718537195372053721537225372353724537255372653727537285372953730537315373253733537345373553736537375373853739537405374153742537435374453745537465374753748537495375053751537525375353754537555375653757537585375953760537615376253763537645376553766537675376853769537705377153772537735377453775537765377753778537795378053781537825378353784537855378653787537885378953790537915379253793537945379553796537975379853799538005380153802538035380453805538065380753808538095381053811538125381353814538155381653817538185381953820538215382253823538245382553826538275382853829538305383153832538335383453835538365383753838538395384053841538425384353844538455384653847538485384953850538515385253853538545385553856538575385853859538605386153862538635386453865538665386753868538695387053871538725387353874538755387653877538785387953880538815388253883538845388553886538875388853889538905389153892538935389453895538965389753898538995390053901539025390353904539055390653907539085390953910539115391253913539145391553916539175391853919539205392153922539235392453925539265392753928539295393053931539325393353934539355393653937539385393953940539415394253943539445394553946539475394853949539505395153952539535395453955539565395753958539595396053961539625396353964539655396653967539685396953970539715397253973539745397553976539775397853979539805398153982539835398453985539865398753988539895399053991539925399353994539955399653997539985399954000540015400254003540045400554006540075400854009540105401154012540135401454015540165401754018540195402054021540225402354024540255402654027540285402954030540315403254033540345403554036540375403854039540405404154042540435404454045540465404754048540495405054051540525405354054540555405654057540585405954060540615406254063540645406554066540675406854069540705407154072540735407454075540765407754078540795408054081540825408354084540855408654087540885408954090540915409254093540945409554096540975409854099541005410154102541035410454105541065410754108541095411054111541125411354114541155411654117541185411954120541215412254123541245412554126541275412854129541305413154132541335413454135541365413754138541395414054141541425414354144541455414654147541485414954150541515415254153541545415554156541575415854159541605416154162541635416454165541665416754168541695417054171541725417354174541755417654177541785417954180541815418254183541845418554186541875418854189541905419154192541935419454195541965419754198541995420054201542025420354204542055420654207542085420954210542115421254213542145421554216542175421854219542205422154222542235422454225542265422754228542295423054231542325423354234542355423654237542385423954240542415424254243542445424554246542475424854249542505425154252542535425454255542565425754258542595426054261542625426354264542655426654267542685426954270542715427254273542745427554276542775427854279542805428154282542835428454285542865428754288542895429054291542925429354294542955429654297542985429954300543015430254303543045430554306543075430854309543105431154312543135431454315543165431754318543195432054321543225432354324543255432654327543285432954330543315433254333543345433554336543375433854339543405434154342543435434454345543465434754348543495435054351543525435354354543555435654357543585435954360543615436254363543645436554366543675436854369543705437154372543735437454375543765437754378543795438054381543825438354384543855438654387543885438954390543915439254393543945439554396543975439854399544005440154402544035440454405544065440754408544095441054411544125441354414544155441654417544185441954420544215442254423544245442554426544275442854429544305443154432544335443454435544365443754438544395444054441544425444354444544455444654447544485444954450544515445254453544545445554456544575445854459544605446154462544635446454465544665446754468544695447054471544725447354474544755447654477544785447954480544815448254483544845448554486544875448854489544905449154492544935449454495544965449754498544995450054501545025450354504545055450654507545085450954510545115451254513545145451554516545175451854519545205452154522545235452454525545265452754528545295453054531545325453354534545355453654537545385453954540545415454254543545445454554546545475454854549545505455154552545535455454555545565455754558545595456054561545625456354564545655456654567545685456954570545715457254573545745457554576545775457854579545805458154582545835458454585545865458754588545895459054591545925459354594545955459654597545985459954600546015460254603546045460554606546075460854609546105461154612546135461454615546165461754618546195462054621546225462354624546255462654627546285462954630546315463254633546345463554636546375463854639546405464154642546435464454645546465464754648546495465054651546525465354654546555465654657546585465954660546615466254663546645466554666546675466854669546705467154672546735467454675546765467754678546795468054681546825468354684546855468654687546885468954690546915469254693546945469554696546975469854699547005470154702547035470454705547065470754708547095471054711547125471354714547155471654717547185471954720547215472254723547245472554726547275472854729547305473154732547335473454735547365473754738547395474054741547425474354744547455474654747547485474954750547515475254753547545475554756547575475854759547605476154762547635476454765547665476754768547695477054771547725477354774547755477654777547785477954780547815478254783547845478554786547875478854789547905479154792547935479454795547965479754798547995480054801548025480354804548055480654807548085480954810548115481254813548145481554816548175481854819548205482154822548235482454825548265482754828548295483054831548325483354834548355483654837548385483954840548415484254843548445484554846548475484854849548505485154852548535485454855548565485754858548595486054861548625486354864548655486654867548685486954870548715487254873548745487554876548775487854879548805488154882548835488454885548865488754888548895489054891548925489354894548955489654897548985489954900549015490254903549045490554906549075490854909549105491154912549135491454915549165491754918549195492054921549225492354924549255492654927549285492954930549315493254933549345493554936549375493854939549405494154942549435494454945549465494754948549495495054951549525495354954549555495654957549585495954960549615496254963549645496554966549675496854969549705497154972549735497454975549765497754978549795498054981549825498354984549855498654987549885498954990549915499254993549945499554996549975499854999550005500155002550035500455005550065500755008550095501055011550125501355014550155501655017550185501955020550215502255023550245502555026550275502855029550305503155032550335503455035550365503755038550395504055041550425504355044550455504655047550485504955050550515505255053550545505555056550575505855059550605506155062550635506455065550665506755068550695507055071550725507355074550755507655077550785507955080550815508255083550845508555086550875508855089550905509155092550935509455095550965509755098550995510055101551025510355104551055510655107551085510955110551115511255113551145511555116551175511855119551205512155122551235512455125551265512755128551295513055131551325513355134551355513655137551385513955140551415514255143551445514555146551475514855149551505515155152551535515455155551565515755158551595516055161551625516355164551655516655167551685516955170551715517255173551745517555176551775517855179551805518155182551835518455185551865518755188551895519055191551925519355194551955519655197551985519955200552015520255203552045520555206552075520855209552105521155212552135521455215552165521755218552195522055221552225522355224552255522655227552285522955230552315523255233552345523555236552375523855239552405524155242552435524455245552465524755248552495525055251552525525355254552555525655257552585525955260552615526255263552645526555266552675526855269552705527155272552735527455275552765527755278552795528055281552825528355284552855528655287552885528955290552915529255293552945529555296552975529855299553005530155302553035530455305553065530755308553095531055311553125531355314553155531655317553185531955320553215532255323553245532555326553275532855329553305533155332553335533455335553365533755338553395534055341553425534355344553455534655347553485534955350553515535255353553545535555356553575535855359553605536155362553635536455365553665536755368553695537055371553725537355374553755537655377553785537955380553815538255383553845538555386553875538855389553905539155392553935539455395553965539755398553995540055401554025540355404554055540655407554085540955410554115541255413554145541555416554175541855419554205542155422554235542455425554265542755428554295543055431554325543355434554355543655437554385543955440554415544255443554445544555446554475544855449554505545155452554535545455455554565545755458554595546055461554625546355464554655546655467554685546955470554715547255473554745547555476554775547855479554805548155482554835548455485554865548755488554895549055491554925549355494554955549655497554985549955500555015550255503555045550555506555075550855509555105551155512555135551455515555165551755518555195552055521555225552355524555255552655527555285552955530555315553255533555345553555536555375553855539555405554155542555435554455545555465554755548555495555055551555525555355554555555555655557555585555955560555615556255563555645556555566555675556855569555705557155572555735557455575555765557755578555795558055581555825558355584555855558655587555885558955590555915559255593555945559555596555975559855599556005560155602556035560455605556065560755608556095561055611556125561355614556155561655617556185561955620556215562255623556245562555626556275562855629556305563155632556335563455635556365563755638556395564055641556425564355644556455564655647556485564955650556515565255653556545565555656556575565855659556605566155662556635566455665556665566755668556695567055671556725567355674556755567655677556785567955680556815568255683556845568555686556875568855689556905569155692556935569455695556965569755698556995570055701557025570355704557055570655707557085570955710557115571255713557145571555716557175571855719557205572155722557235572455725557265572755728557295573055731557325573355734557355573655737557385573955740557415574255743557445574555746557475574855749557505575155752557535575455755557565575755758557595576055761557625576355764557655576655767557685576955770557715577255773557745577555776557775577855779557805578155782557835578455785557865578755788557895579055791557925579355794557955579655797557985579955800558015580255803558045580555806558075580855809558105581155812558135581455815558165581755818558195582055821558225582355824558255582655827558285582955830558315583255833558345583555836558375583855839558405584155842558435584455845558465584755848558495585055851558525585355854558555585655857558585585955860558615586255863558645586555866558675586855869558705587155872558735587455875558765587755878558795588055881558825588355884558855588655887558885588955890558915589255893558945589555896558975589855899559005590155902559035590455905559065590755908559095591055911559125591355914559155591655917559185591955920559215592255923559245592555926559275592855929559305593155932559335593455935559365593755938559395594055941559425594355944559455594655947559485594955950559515595255953559545595555956559575595855959559605596155962559635596455965559665596755968559695597055971559725597355974559755597655977559785597955980559815598255983559845598555986559875598855989559905599155992559935599455995559965599755998559995600056001560025600356004560055600656007560085600956010560115601256013560145601556016560175601856019560205602156022560235602456025560265602756028560295603056031560325603356034560355603656037560385603956040560415604256043560445604556046560475604856049560505605156052560535605456055560565605756058560595606056061560625606356064560655606656067560685606956070560715607256073560745607556076560775607856079560805608156082560835608456085560865608756088560895609056091560925609356094560955609656097560985609956100561015610256103561045610556106561075610856109561105611156112561135611456115561165611756118561195612056121561225612356124561255612656127561285612956130561315613256133561345613556136561375613856139561405614156142561435614456145561465614756148561495615056151561525615356154561555615656157561585615956160561615616256163561645616556166561675616856169561705617156172561735617456175561765617756178561795618056181561825618356184561855618656187561885618956190561915619256193561945619556196561975619856199562005620156202562035620456205562065620756208562095621056211562125621356214562155621656217562185621956220562215622256223562245622556226562275622856229562305623156232562335623456235562365623756238562395624056241562425624356244562455624656247562485624956250562515625256253562545625556256562575625856259562605626156262562635626456265562665626756268562695627056271562725627356274562755627656277562785627956280562815628256283562845628556286562875628856289562905629156292562935629456295562965629756298562995630056301563025630356304563055630656307563085630956310563115631256313563145631556316563175631856319563205632156322563235632456325563265632756328563295633056331563325633356334563355633656337563385633956340563415634256343563445634556346563475634856349563505635156352563535635456355563565635756358563595636056361563625636356364563655636656367563685636956370563715637256373563745637556376563775637856379563805638156382563835638456385563865638756388563895639056391563925639356394563955639656397563985639956400564015640256403564045640556406564075640856409564105641156412564135641456415564165641756418564195642056421564225642356424564255642656427564285642956430564315643256433564345643556436564375643856439564405644156442564435644456445564465644756448564495645056451564525645356454564555645656457564585645956460564615646256463564645646556466564675646856469564705647156472564735647456475564765647756478564795648056481564825648356484564855648656487564885648956490564915649256493564945649556496564975649856499565005650156502565035650456505565065650756508565095651056511565125651356514565155651656517565185651956520565215652256523565245652556526565275652856529565305653156532565335653456535565365653756538565395654056541565425654356544565455654656547565485654956550565515655256553565545655556556565575655856559565605656156562565635656456565565665656756568565695657056571565725657356574565755657656577565785657956580565815658256583565845658556586565875658856589565905659156592565935659456595565965659756598565995660056601566025660356604566055660656607566085660956610566115661256613566145661556616566175661856619566205662156622566235662456625566265662756628566295663056631566325663356634566355663656637566385663956640566415664256643566445664556646566475664856649566505665156652566535665456655566565665756658566595666056661566625666356664566655666656667566685666956670566715667256673566745667556676566775667856679566805668156682566835668456685566865668756688566895669056691566925669356694566955669656697566985669956700567015670256703567045670556706567075670856709567105671156712567135671456715567165671756718567195672056721567225672356724567255672656727567285672956730567315673256733567345673556736567375673856739567405674156742567435674456745567465674756748567495675056751567525675356754567555675656757567585675956760567615676256763567645676556766567675676856769567705677156772567735677456775567765677756778567795678056781567825678356784567855678656787567885678956790567915679256793567945679556796567975679856799568005680156802568035680456805568065680756808568095681056811568125681356814568155681656817568185681956820568215682256823568245682556826568275682856829568305683156832568335683456835568365683756838568395684056841568425684356844568455684656847568485684956850568515685256853568545685556856568575685856859568605686156862568635686456865568665686756868568695687056871568725687356874568755687656877568785687956880568815688256883568845688556886568875688856889568905689156892568935689456895568965689756898568995690056901569025690356904569055690656907569085690956910569115691256913569145691556916569175691856919569205692156922569235692456925569265692756928569295693056931569325693356934569355693656937569385693956940569415694256943569445694556946569475694856949569505695156952569535695456955569565695756958569595696056961569625696356964569655696656967569685696956970569715697256973569745697556976569775697856979569805698156982569835698456985569865698756988569895699056991569925699356994569955699656997569985699957000570015700257003570045700557006570075700857009570105701157012570135701457015570165701757018570195702057021570225702357024570255702657027570285702957030570315703257033570345703557036570375703857039570405704157042570435704457045570465704757048570495705057051570525705357054570555705657057570585705957060570615706257063570645706557066570675706857069570705707157072570735707457075570765707757078570795708057081570825708357084570855708657087570885708957090570915709257093570945709557096570975709857099571005710157102571035710457105571065710757108571095711057111571125711357114571155711657117571185711957120571215712257123571245712557126571275712857129571305713157132571335713457135571365713757138571395714057141571425714357144571455714657147571485714957150571515715257153571545715557156571575715857159571605716157162571635716457165571665716757168571695717057171571725717357174571755717657177571785717957180571815718257183571845718557186571875718857189571905719157192571935719457195571965719757198571995720057201572025720357204572055720657207572085720957210572115721257213572145721557216572175721857219572205722157222572235722457225572265722757228572295723057231572325723357234572355723657237572385723957240572415724257243572445724557246572475724857249572505725157252572535725457255572565725757258572595726057261572625726357264572655726657267572685726957270572715727257273572745727557276572775727857279572805728157282572835728457285572865728757288572895729057291572925729357294572955729657297572985729957300573015730257303573045730557306573075730857309573105731157312573135731457315573165731757318573195732057321573225732357324573255732657327573285732957330573315733257333573345733557336573375733857339573405734157342573435734457345573465734757348573495735057351573525735357354573555735657357573585735957360573615736257363573645736557366573675736857369573705737157372573735737457375573765737757378573795738057381573825738357384573855738657387573885738957390573915739257393573945739557396573975739857399574005740157402574035740457405574065740757408574095741057411574125741357414574155741657417574185741957420574215742257423574245742557426574275742857429574305743157432574335743457435574365743757438574395744057441574425744357444574455744657447574485744957450574515745257453574545745557456574575745857459574605746157462574635746457465574665746757468574695747057471574725747357474574755747657477574785747957480574815748257483574845748557486574875748857489574905749157492574935749457495574965749757498574995750057501575025750357504575055750657507575085750957510575115751257513575145751557516575175751857519575205752157522575235752457525575265752757528575295753057531575325753357534575355753657537575385753957540575415754257543575445754557546575475754857549575505755157552575535755457555575565755757558575595756057561575625756357564575655756657567575685756957570575715757257573575745757557576575775757857579575805758157582575835758457585575865758757588575895759057591575925759357594575955759657597575985759957600576015760257603576045760557606576075760857609576105761157612576135761457615576165761757618576195762057621576225762357624576255762657627576285762957630576315763257633576345763557636576375763857639576405764157642576435764457645576465764757648576495765057651576525765357654576555765657657576585765957660576615766257663576645766557666576675766857669576705767157672576735767457675576765767757678576795768057681576825768357684576855768657687576885768957690576915769257693576945769557696576975769857699577005770157702577035770457705577065770757708577095771057711577125771357714577155771657717577185771957720577215772257723577245772557726577275772857729577305773157732577335773457735577365773757738577395774057741577425774357744577455774657747577485774957750577515775257753577545775557756577575775857759577605776157762577635776457765577665776757768577695777057771577725777357774577755777657777577785777957780577815778257783577845778557786577875778857789577905779157792577935779457795577965779757798577995780057801578025780357804578055780657807578085780957810578115781257813578145781557816578175781857819578205782157822578235782457825578265782757828578295783057831578325783357834578355783657837578385783957840578415784257843578445784557846578475784857849578505785157852578535785457855578565785757858578595786057861578625786357864578655786657867578685786957870578715787257873578745787557876578775787857879578805788157882578835788457885578865788757888578895789057891578925789357894578955789657897578985789957900579015790257903579045790557906579075790857909579105791157912579135791457915579165791757918579195792057921579225792357924579255792657927579285792957930579315793257933579345793557936579375793857939579405794157942579435794457945579465794757948579495795057951579525795357954579555795657957579585795957960579615796257963579645796557966579675796857969579705797157972579735797457975579765797757978579795798057981579825798357984579855798657987579885798957990579915799257993579945799557996579975799857999580005800158002580035800458005580065800758008580095801058011580125801358014580155801658017580185801958020580215802258023580245802558026580275802858029580305803158032580335803458035580365803758038580395804058041580425804358044580455804658047580485804958050580515805258053580545805558056580575805858059580605806158062580635806458065580665806758068580695807058071580725807358074580755807658077580785807958080580815808258083580845808558086580875808858089580905809158092580935809458095580965809758098580995810058101581025810358104581055810658107581085810958110581115811258113581145811558116581175811858119581205812158122581235812458125581265812758128581295813058131581325813358134581355813658137581385813958140581415814258143581445814558146581475814858149581505815158152581535815458155581565815758158581595816058161581625816358164581655816658167581685816958170581715817258173581745817558176581775817858179581805818158182581835818458185581865818758188581895819058191581925819358194581955819658197581985819958200582015820258203582045820558206582075820858209582105821158212582135821458215582165821758218582195822058221582225822358224582255822658227582285822958230582315823258233582345823558236582375823858239582405824158242582435824458245582465824758248582495825058251582525825358254582555825658257582585825958260582615826258263582645826558266582675826858269582705827158272582735827458275582765827758278582795828058281582825828358284582855828658287582885828958290582915829258293582945829558296582975829858299583005830158302583035830458305583065830758308583095831058311583125831358314583155831658317583185831958320583215832258323583245832558326583275832858329583305833158332583335833458335583365833758338583395834058341583425834358344583455834658347583485834958350583515835258353583545835558356583575835858359583605836158362583635836458365583665836758368583695837058371583725837358374583755837658377583785837958380583815838258383583845838558386583875838858389583905839158392583935839458395583965839758398583995840058401584025840358404584055840658407584085840958410584115841258413584145841558416584175841858419584205842158422584235842458425584265842758428584295843058431584325843358434584355843658437584385843958440584415844258443584445844558446584475844858449584505845158452584535845458455584565845758458584595846058461584625846358464584655846658467584685846958470584715847258473584745847558476584775847858479584805848158482584835848458485584865848758488584895849058491584925849358494584955849658497584985849958500585015850258503585045850558506585075850858509585105851158512585135851458515585165851758518585195852058521585225852358524585255852658527585285852958530585315853258533585345853558536585375853858539585405854158542585435854458545585465854758548585495855058551585525855358554585555855658557585585855958560585615856258563585645856558566585675856858569585705857158572585735857458575585765857758578585795858058581585825858358584585855858658587585885858958590585915859258593585945859558596585975859858599586005860158602586035860458605586065860758608586095861058611586125861358614586155861658617586185861958620586215862258623586245862558626586275862858629586305863158632586335863458635586365863758638586395864058641586425864358644586455864658647586485864958650586515865258653586545865558656586575865858659586605866158662586635866458665586665866758668586695867058671586725867358674586755867658677586785867958680586815868258683586845868558686586875868858689586905869158692586935869458695586965869758698586995870058701587025870358704587055870658707587085870958710587115871258713587145871558716587175871858719587205872158722587235872458725587265872758728587295873058731587325873358734587355873658737587385873958740587415874258743587445874558746587475874858749587505875158752587535875458755587565875758758587595876058761587625876358764587655876658767587685876958770587715877258773587745877558776587775877858779587805878158782587835878458785587865878758788587895879058791587925879358794587955879658797587985879958800588015880258803588045880558806588075880858809588105881158812588135881458815588165881758818588195882058821588225882358824588255882658827588285882958830588315883258833588345883558836588375883858839588405884158842588435884458845588465884758848588495885058851588525885358854588555885658857588585885958860588615886258863588645886558866588675886858869588705887158872588735887458875588765887758878588795888058881588825888358884588855888658887588885888958890588915889258893588945889558896588975889858899589005890158902589035890458905589065890758908589095891058911589125891358914589155891658917589185891958920589215892258923589245892558926589275892858929589305893158932589335893458935589365893758938589395894058941589425894358944589455894658947589485894958950589515895258953589545895558956589575895858959589605896158962589635896458965589665896758968589695897058971589725897358974589755897658977589785897958980589815898258983589845898558986589875898858989589905899158992589935899458995589965899758998589995900059001590025900359004590055900659007590085900959010590115901259013590145901559016590175901859019590205902159022590235902459025590265902759028590295903059031590325903359034590355903659037590385903959040590415904259043590445904559046590475904859049590505905159052590535905459055590565905759058590595906059061590625906359064590655906659067590685906959070590715907259073590745907559076590775907859079590805908159082590835908459085590865908759088590895909059091590925909359094590955909659097590985909959100591015910259103591045910559106591075910859109591105911159112591135911459115591165911759118591195912059121591225912359124591255912659127591285912959130591315913259133591345913559136591375913859139591405914159142591435914459145591465914759148591495915059151591525915359154591555915659157591585915959160591615916259163591645916559166591675916859169591705917159172591735917459175591765917759178591795918059181591825918359184591855918659187591885918959190591915919259193591945919559196591975919859199592005920159202592035920459205592065920759208592095921059211592125921359214592155921659217592185921959220592215922259223592245922559226592275922859229592305923159232592335923459235592365923759238592395924059241592425924359244592455924659247592485924959250592515925259253592545925559256592575925859259592605926159262592635926459265592665926759268592695927059271592725927359274592755927659277592785927959280592815928259283592845928559286592875928859289592905929159292592935929459295592965929759298592995930059301593025930359304593055930659307593085930959310593115931259313593145931559316593175931859319593205932159322593235932459325593265932759328593295933059331593325933359334593355933659337593385933959340593415934259343593445934559346593475934859349593505935159352593535935459355593565935759358593595936059361593625936359364593655936659367593685936959370593715937259373593745937559376593775937859379593805938159382593835938459385593865938759388593895939059391593925939359394593955939659397593985939959400594015940259403594045940559406594075940859409594105941159412594135941459415594165941759418594195942059421594225942359424594255942659427594285942959430594315943259433594345943559436594375943859439594405944159442594435944459445594465944759448594495945059451594525945359454594555945659457594585945959460594615946259463594645946559466594675946859469594705947159472594735947459475594765947759478594795948059481594825948359484594855948659487594885948959490594915949259493594945949559496594975949859499595005950159502595035950459505595065950759508595095951059511595125951359514595155951659517595185951959520595215952259523595245952559526595275952859529595305953159532595335953459535595365953759538595395954059541595425954359544595455954659547595485954959550595515955259553595545955559556595575955859559595605956159562595635956459565595665956759568595695957059571595725957359574595755957659577595785957959580595815958259583595845958559586595875958859589595905959159592595935959459595595965959759598595995960059601596025960359604596055960659607596085960959610596115961259613596145961559616596175961859619596205962159622596235962459625596265962759628596295963059631596325963359634596355963659637596385963959640596415964259643596445964559646596475964859649596505965159652596535965459655596565965759658596595966059661596625966359664596655966659667596685966959670596715967259673596745967559676596775967859679596805968159682596835968459685596865968759688596895969059691596925969359694596955969659697596985969959700597015970259703597045970559706597075970859709597105971159712597135971459715597165971759718597195972059721597225972359724597255972659727597285972959730597315973259733597345973559736597375973859739597405974159742597435974459745597465974759748597495975059751597525975359754597555975659757597585975959760597615976259763597645976559766597675976859769597705977159772597735977459775597765977759778597795978059781597825978359784597855978659787597885978959790597915979259793597945979559796597975979859799598005980159802598035980459805598065980759808598095981059811598125981359814598155981659817598185981959820598215982259823598245982559826598275982859829598305983159832598335983459835598365983759838598395984059841598425984359844598455984659847598485984959850598515985259853598545985559856598575985859859598605986159862598635986459865598665986759868598695987059871598725987359874598755987659877598785987959880598815988259883598845988559886598875988859889598905989159892598935989459895598965989759898598995990059901599025990359904599055990659907599085990959910599115991259913599145991559916599175991859919599205992159922599235992459925599265992759928599295993059931599325993359934599355993659937599385993959940599415994259943599445994559946599475994859949599505995159952599535995459955599565995759958599595996059961599625996359964599655996659967599685996959970599715997259973599745997559976599775997859979599805998159982599835998459985599865998759988599895999059991599925999359994599955999659997599985999960000600016000260003600046000560006600076000860009600106001160012600136001460015600166001760018600196002060021600226002360024600256002660027600286002960030600316003260033600346003560036600376003860039600406004160042600436004460045600466004760048600496005060051600526005360054600556005660057600586005960060600616006260063600646006560066600676006860069600706007160072600736007460075600766007760078600796008060081600826008360084600856008660087600886008960090600916009260093600946009560096600976009860099601006010160102601036010460105601066010760108601096011060111601126011360114601156011660117601186011960120601216012260123601246012560126601276012860129601306013160132601336013460135601366013760138601396014060141601426014360144601456014660147601486014960150601516015260153601546015560156601576015860159601606016160162601636016460165601666016760168601696017060171601726017360174601756017660177601786017960180601816018260183601846018560186601876018860189601906019160192601936019460195601966019760198601996020060201602026020360204602056020660207602086020960210602116021260213602146021560216602176021860219602206022160222602236022460225602266022760228602296023060231602326023360234602356023660237602386023960240602416024260243602446024560246602476024860249602506025160252602536025460255602566025760258602596026060261602626026360264602656026660267602686026960270602716027260273602746027560276602776027860279602806028160282602836028460285602866028760288602896029060291602926029360294602956029660297602986029960300603016030260303603046030560306603076030860309603106031160312603136031460315603166031760318603196032060321603226032360324603256032660327603286032960330603316033260333603346033560336603376033860339603406034160342603436034460345603466034760348603496035060351603526035360354603556035660357603586035960360603616036260363603646036560366603676036860369603706037160372603736037460375603766037760378603796038060381603826038360384603856038660387603886038960390603916039260393603946039560396603976039860399604006040160402604036040460405604066040760408604096041060411604126041360414604156041660417604186041960420604216042260423604246042560426604276042860429604306043160432604336043460435604366043760438604396044060441604426044360444604456044660447604486044960450604516045260453604546045560456604576045860459604606046160462604636046460465604666046760468604696047060471604726047360474604756047660477604786047960480604816048260483604846048560486604876048860489604906049160492604936049460495604966049760498604996050060501605026050360504605056050660507605086050960510605116051260513605146051560516605176051860519605206052160522605236052460525605266052760528605296053060531605326053360534605356053660537605386053960540605416054260543605446054560546605476054860549605506055160552605536055460555605566055760558605596056060561605626056360564605656056660567605686056960570605716057260573605746057560576605776057860579605806058160582605836058460585605866058760588605896059060591605926059360594605956059660597605986059960600606016060260603606046060560606606076060860609606106061160612606136061460615606166061760618606196062060621606226062360624606256062660627606286062960630606316063260633606346063560636606376063860639606406064160642606436064460645606466064760648606496065060651606526065360654606556065660657606586065960660606616066260663606646066560666606676066860669606706067160672606736067460675606766067760678606796068060681606826068360684606856068660687606886068960690606916069260693606946069560696606976069860699607006070160702607036070460705607066070760708607096071060711607126071360714607156071660717607186071960720607216072260723607246072560726607276072860729607306073160732607336073460735607366073760738607396074060741607426074360744607456074660747607486074960750607516075260753607546075560756607576075860759607606076160762607636076460765607666076760768607696077060771607726077360774607756077660777607786077960780607816078260783607846078560786607876078860789607906079160792607936079460795607966079760798607996080060801608026080360804608056080660807608086080960810608116081260813608146081560816608176081860819608206082160822608236082460825608266082760828608296083060831608326083360834608356083660837608386083960840608416084260843608446084560846608476084860849608506085160852608536085460855608566085760858608596086060861608626086360864608656086660867608686086960870608716087260873608746087560876608776087860879608806088160882608836088460885608866088760888608896089060891608926089360894608956089660897608986089960900609016090260903609046090560906609076090860909609106091160912609136091460915609166091760918609196092060921609226092360924609256092660927609286092960930609316093260933609346093560936609376093860939609406094160942609436094460945609466094760948609496095060951609526095360954609556095660957609586095960960609616096260963609646096560966609676096860969609706097160972609736097460975609766097760978609796098060981609826098360984609856098660987609886098960990609916099260993609946099560996609976099860999610006100161002610036100461005610066100761008610096101061011610126101361014610156101661017610186101961020610216102261023610246102561026610276102861029610306103161032610336103461035610366103761038610396104061041610426104361044610456104661047610486104961050610516105261053610546105561056610576105861059610606106161062610636106461065610666106761068610696107061071610726107361074610756107661077610786107961080610816108261083610846108561086610876108861089610906109161092610936109461095610966109761098610996110061101611026110361104611056110661107611086110961110611116111261113611146111561116611176111861119611206112161122611236112461125611266112761128611296113061131611326113361134611356113661137611386113961140611416114261143611446114561146611476114861149611506115161152611536115461155611566115761158611596116061161611626116361164611656116661167611686116961170611716117261173611746117561176611776117861179611806118161182611836118461185611866118761188611896119061191611926119361194611956119661197611986119961200612016120261203612046120561206612076120861209612106121161212612136121461215612166121761218612196122061221612226122361224612256122661227612286122961230612316123261233612346123561236612376123861239612406124161242612436124461245612466124761248612496125061251612526125361254612556125661257612586125961260612616126261263612646126561266612676126861269612706127161272612736127461275612766127761278612796128061281612826128361284612856128661287612886128961290612916129261293612946129561296612976129861299613006130161302613036130461305613066130761308613096131061311613126131361314613156131661317613186131961320613216132261323613246132561326613276132861329613306133161332613336133461335613366133761338613396134061341613426134361344613456134661347613486134961350613516135261353613546135561356613576135861359613606136161362613636136461365613666136761368613696137061371613726137361374613756137661377613786137961380613816138261383613846138561386613876138861389613906139161392613936139461395613966139761398613996140061401614026140361404614056140661407614086140961410614116141261413614146141561416614176141861419614206142161422614236142461425614266142761428614296143061431614326143361434614356143661437614386143961440614416144261443614446144561446614476144861449614506145161452614536145461455614566145761458614596146061461614626146361464614656146661467614686146961470614716147261473614746147561476614776147861479614806148161482614836148461485614866148761488614896149061491614926149361494614956149661497614986149961500615016150261503615046150561506615076150861509615106151161512615136151461515615166151761518615196152061521615226152361524615256152661527615286152961530615316153261533615346153561536615376153861539615406154161542615436154461545615466154761548615496155061551615526155361554615556155661557615586155961560615616156261563615646156561566615676156861569615706157161572615736157461575615766157761578615796158061581615826158361584615856158661587615886158961590615916159261593615946159561596615976159861599616006160161602616036160461605616066160761608616096161061611616126161361614616156161661617616186161961620616216162261623616246162561626616276162861629616306163161632616336163461635616366163761638616396164061641616426164361644616456164661647616486164961650616516165261653616546165561656616576165861659616606166161662616636166461665616666166761668616696167061671616726167361674616756167661677616786167961680616816168261683616846168561686616876168861689616906169161692616936169461695616966169761698616996170061701617026170361704617056170661707617086170961710617116171261713617146171561716617176171861719617206172161722617236172461725617266172761728617296173061731617326173361734617356173661737617386173961740617416174261743617446174561746617476174861749617506175161752617536175461755617566175761758617596176061761617626176361764617656176661767617686176961770617716177261773617746177561776617776177861779617806178161782617836178461785617866178761788617896179061791617926179361794617956179661797617986179961800618016180261803618046180561806618076180861809618106181161812618136181461815618166181761818618196182061821618226182361824618256182661827618286182961830618316183261833618346183561836618376183861839618406184161842618436184461845618466184761848618496185061851618526185361854618556185661857618586185961860618616186261863618646186561866618676186861869618706187161872618736187461875618766187761878618796188061881618826188361884618856188661887618886188961890618916189261893618946189561896618976189861899619006190161902619036190461905619066190761908619096191061911619126191361914619156191661917619186191961920619216192261923619246192561926619276192861929619306193161932619336193461935619366193761938619396194061941619426194361944619456194661947619486194961950619516195261953619546195561956619576195861959619606196161962619636196461965619666196761968619696197061971619726197361974619756197661977619786197961980619816198261983619846198561986619876198861989619906199161992619936199461995619966199761998619996200062001620026200362004620056200662007620086200962010620116201262013620146201562016620176201862019620206202162022620236202462025620266202762028620296203062031620326203362034620356203662037620386203962040620416204262043620446204562046620476204862049620506205162052620536205462055620566205762058620596206062061620626206362064620656206662067620686206962070620716207262073620746207562076620776207862079620806208162082620836208462085620866208762088620896209062091620926209362094620956209662097620986209962100621016210262103621046210562106621076210862109621106211162112621136211462115621166211762118621196212062121621226212362124621256212662127621286212962130621316213262133621346213562136621376213862139621406214162142621436214462145621466214762148621496215062151621526215362154621556215662157621586215962160621616216262163621646216562166621676216862169621706217162172621736217462175621766217762178621796218062181621826218362184621856218662187621886218962190621916219262193621946219562196621976219862199622006220162202622036220462205622066220762208622096221062211622126221362214622156221662217622186221962220622216222262223622246222562226622276222862229622306223162232622336223462235622366223762238622396224062241622426224362244622456224662247622486224962250622516225262253622546225562256622576225862259622606226162262622636226462265622666226762268622696227062271622726227362274622756227662277622786227962280622816228262283622846228562286622876228862289622906229162292622936229462295622966229762298622996230062301623026230362304623056230662307623086230962310623116231262313623146231562316623176231862319623206232162322623236232462325623266232762328623296233062331623326233362334623356233662337623386233962340623416234262343623446234562346623476234862349623506235162352623536235462355623566235762358623596236062361623626236362364623656236662367623686236962370623716237262373623746237562376623776237862379623806238162382623836238462385623866238762388623896239062391623926239362394623956239662397623986239962400624016240262403624046240562406624076240862409624106241162412624136241462415624166241762418624196242062421624226242362424624256242662427624286242962430624316243262433624346243562436624376243862439624406244162442624436244462445624466244762448624496245062451624526245362454624556245662457624586245962460624616246262463624646246562466624676246862469624706247162472624736247462475624766247762478624796248062481624826248362484624856248662487624886248962490624916249262493624946249562496624976249862499625006250162502625036250462505625066250762508625096251062511625126251362514625156251662517625186251962520625216252262523625246252562526625276252862529625306253162532625336253462535625366253762538625396254062541625426254362544625456254662547625486254962550625516255262553625546255562556625576255862559625606256162562625636256462565625666256762568625696257062571625726257362574625756257662577625786257962580625816258262583625846258562586625876258862589625906259162592625936259462595625966259762598625996260062601626026260362604626056260662607626086260962610626116261262613626146261562616626176261862619626206262162622626236262462625626266262762628626296263062631626326263362634626356263662637626386263962640626416264262643626446264562646626476264862649626506265162652626536265462655626566265762658626596266062661626626266362664626656266662667626686266962670626716267262673626746267562676626776267862679626806268162682626836268462685626866268762688626896269062691626926269362694626956269662697626986269962700627016270262703627046270562706627076270862709627106271162712627136271462715627166271762718627196272062721627226272362724627256272662727627286272962730627316273262733627346273562736627376273862739627406274162742627436274462745627466274762748627496275062751627526275362754627556275662757627586275962760627616276262763627646276562766627676276862769627706277162772627736277462775627766277762778627796278062781627826278362784627856278662787627886278962790627916279262793627946279562796627976279862799628006280162802628036280462805628066280762808628096281062811628126281362814628156281662817628186281962820628216282262823628246282562826628276282862829628306283162832628336283462835628366283762838628396284062841628426284362844628456284662847628486284962850628516285262853628546285562856628576285862859628606286162862628636286462865628666286762868628696287062871628726287362874628756287662877628786287962880628816288262883628846288562886628876288862889628906289162892628936289462895628966289762898628996290062901629026290362904629056290662907629086290962910629116291262913629146291562916629176291862919629206292162922629236292462925629266292762928629296293062931629326293362934629356293662937629386293962940629416294262943629446294562946629476294862949629506295162952629536295462955629566295762958629596296062961629626296362964629656296662967629686296962970629716297262973629746297562976629776297862979629806298162982629836298462985629866298762988629896299062991629926299362994629956299662997629986299963000630016300263003630046300563006630076300863009630106301163012630136301463015630166301763018630196302063021630226302363024630256302663027630286302963030630316303263033630346303563036630376303863039630406304163042630436304463045630466304763048630496305063051630526305363054630556305663057630586305963060630616306263063630646306563066630676306863069630706307163072630736307463075630766307763078630796308063081630826308363084630856308663087630886308963090630916309263093630946309563096630976309863099631006310163102631036310463105631066310763108631096311063111631126311363114631156311663117631186311963120631216312263123631246312563126631276312863129631306313163132631336313463135631366313763138631396314063141631426314363144631456314663147631486314963150631516315263153631546315563156631576315863159631606316163162631636316463165631666316763168631696317063171631726317363174631756317663177631786317963180631816318263183631846318563186631876318863189631906319163192631936319463195631966319763198631996320063201632026320363204632056320663207632086320963210632116321263213632146321563216632176321863219632206322163222632236322463225632266322763228632296323063231632326323363234632356323663237632386323963240632416324263243632446324563246632476324863249632506325163252632536325463255632566325763258632596326063261632626326363264632656326663267632686326963270632716327263273632746327563276632776327863279632806328163282632836328463285632866328763288632896329063291632926329363294632956329663297632986329963300633016330263303633046330563306633076330863309633106331163312633136331463315633166331763318633196332063321633226332363324633256332663327633286332963330633316333263333633346333563336633376333863339633406334163342633436334463345633466334763348633496335063351633526335363354633556335663357633586335963360633616336263363633646336563366633676336863369633706337163372633736337463375633766337763378633796338063381633826338363384633856338663387633886338963390633916339263393633946339563396633976339863399634006340163402634036340463405634066340763408634096341063411634126341363414634156341663417634186341963420634216342263423634246342563426634276342863429634306343163432634336343463435634366343763438634396344063441634426344363444634456344663447634486344963450634516345263453634546345563456634576345863459634606346163462634636346463465634666346763468634696347063471634726347363474634756347663477634786347963480634816348263483634846348563486634876348863489634906349163492634936349463495634966349763498634996350063501635026350363504635056350663507635086350963510635116351263513635146351563516635176351863519635206352163522635236352463525635266352763528635296353063531635326353363534635356353663537635386353963540635416354263543635446354563546635476354863549635506355163552635536355463555635566355763558635596356063561635626356363564635656356663567635686356963570635716357263573635746357563576635776357863579635806358163582635836358463585635866358763588635896359063591635926359363594635956359663597635986359963600636016360263603636046360563606636076360863609636106361163612636136361463615636166361763618636196362063621636226362363624636256362663627636286362963630636316363263633636346363563636636376363863639636406364163642636436364463645636466364763648636496365063651636526365363654636556365663657636586365963660636616366263663636646366563666636676366863669636706367163672636736367463675636766367763678636796368063681636826368363684636856368663687636886368963690636916369263693636946369563696636976369863699637006370163702637036370463705637066370763708637096371063711637126371363714637156371663717637186371963720637216372263723637246372563726637276372863729637306373163732637336373463735637366373763738637396374063741637426374363744637456374663747637486374963750637516375263753637546375563756637576375863759637606376163762637636376463765637666376763768637696377063771637726377363774637756377663777637786377963780637816378263783637846378563786637876378863789637906379163792637936379463795637966379763798637996380063801638026380363804638056380663807638086380963810638116381263813638146381563816638176381863819638206382163822638236382463825638266382763828638296383063831638326383363834638356383663837638386383963840638416384263843638446384563846638476384863849638506385163852638536385463855638566385763858638596386063861638626386363864638656386663867638686386963870638716387263873638746387563876638776387863879638806388163882638836388463885638866388763888638896389063891638926389363894638956389663897638986389963900639016390263903639046390563906639076390863909639106391163912639136391463915639166391763918639196392063921639226392363924639256392663927639286392963930639316393263933639346393563936639376393863939639406394163942639436394463945639466394763948639496395063951639526395363954639556395663957639586395963960639616396263963639646396563966639676396863969639706397163972639736397463975639766397763978639796398063981639826398363984639856398663987639886398963990639916399263993639946399563996639976399863999640006400164002640036400464005640066400764008640096401064011640126401364014640156401664017640186401964020640216402264023640246402564026640276402864029640306403164032640336403464035640366403764038640396404064041640426404364044640456404664047640486404964050640516405264053640546405564056640576405864059640606406164062640636406464065640666406764068640696407064071640726407364074640756407664077640786407964080640816408264083640846408564086640876408864089640906409164092640936409464095640966409764098640996410064101641026410364104641056410664107641086410964110641116411264113641146411564116641176411864119641206412164122641236412464125641266412764128641296413064131641326413364134641356413664137641386413964140641416414264143641446414564146641476414864149641506415164152641536415464155641566415764158641596416064161641626416364164641656416664167641686416964170641716417264173641746417564176641776417864179641806418164182641836418464185641866418764188641896419064191641926419364194641956419664197641986419964200642016420264203642046420564206642076420864209642106421164212642136421464215642166421764218642196422064221642226422364224642256422664227642286422964230642316423264233642346423564236642376423864239642406424164242642436424464245642466424764248642496425064251642526425364254642556425664257642586425964260642616426264263642646426564266642676426864269642706427164272642736427464275642766427764278642796428064281642826428364284642856428664287642886428964290642916429264293642946429564296642976429864299643006430164302643036430464305643066430764308643096431064311643126431364314643156431664317643186431964320643216432264323643246432564326643276432864329643306433164332643336433464335643366433764338643396434064341643426434364344643456434664347643486434964350643516435264353643546435564356643576435864359643606436164362643636436464365643666436764368643696437064371643726437364374643756437664377643786437964380643816438264383643846438564386643876438864389643906439164392643936439464395643966439764398643996440064401644026440364404644056440664407644086440964410644116441264413644146441564416644176441864419644206442164422644236442464425644266442764428644296443064431644326443364434644356443664437644386443964440644416444264443644446444564446644476444864449644506445164452644536445464455644566445764458644596446064461644626446364464644656446664467644686446964470644716447264473644746447564476644776447864479644806448164482644836448464485644866448764488644896449064491644926449364494644956449664497644986449964500645016450264503645046450564506645076450864509645106451164512645136451464515645166451764518645196452064521645226452364524645256452664527645286452964530645316453264533645346453564536645376453864539645406454164542645436454464545645466454764548645496455064551645526455364554645556455664557645586455964560645616456264563645646456564566645676456864569645706457164572645736457464575645766457764578645796458064581645826458364584645856458664587645886458964590645916459264593645946459564596645976459864599646006460164602646036460464605646066460764608646096461064611646126461364614646156461664617646186461964620646216462264623646246462564626646276462864629646306463164632646336463464635646366463764638646396464064641646426464364644646456464664647646486464964650646516465264653646546465564656646576465864659646606466164662646636466464665646666466764668646696467064671646726467364674646756467664677646786467964680646816468264683646846468564686646876468864689646906469164692646936469464695646966469764698646996470064701647026470364704647056470664707647086470964710647116471264713647146471564716647176471864719647206472164722647236472464725647266472764728647296473064731647326473364734647356473664737647386473964740647416474264743647446474564746647476474864749647506475164752647536475464755647566475764758647596476064761647626476364764647656476664767647686476964770647716477264773647746477564776647776477864779647806478164782647836478464785647866478764788647896479064791647926479364794647956479664797647986479964800648016480264803648046480564806648076480864809648106481164812648136481464815648166481764818648196482064821648226482364824648256482664827648286482964830648316483264833648346483564836648376483864839648406484164842648436484464845648466484764848648496485064851648526485364854648556485664857648586485964860648616486264863648646486564866648676486864869648706487164872648736487464875648766487764878648796488064881648826488364884648856488664887648886488964890648916489264893648946489564896648976489864899649006490164902649036490464905649066490764908649096491064911649126491364914649156491664917649186491964920649216492264923649246492564926649276492864929649306493164932649336493464935649366493764938649396494064941649426494364944649456494664947649486494964950649516495264953649546495564956649576495864959649606496164962649636496464965649666496764968649696497064971649726497364974649756497664977649786497964980649816498264983649846498564986649876498864989649906499164992649936499464995649966499764998649996500065001650026500365004650056500665007650086500965010650116501265013650146501565016650176501865019650206502165022650236502465025650266502765028650296503065031650326503365034650356503665037650386503965040650416504265043650446504565046650476504865049650506505165052650536505465055650566505765058650596506065061650626506365064650656506665067650686506965070650716507265073650746507565076650776507865079650806508165082650836508465085650866508765088650896509065091650926509365094650956509665097650986509965100651016510265103651046510565106651076510865109651106511165112651136511465115651166511765118651196512065121651226512365124651256512665127651286512965130651316513265133651346513565136651376513865139651406514165142651436514465145651466514765148651496515065151651526515365154651556515665157651586515965160651616516265163651646516565166651676516865169651706517165172651736517465175651766517765178651796518065181651826518365184651856518665187651886518965190651916519265193651946519565196651976519865199652006520165202652036520465205652066520765208652096521065211652126521365214652156521665217652186521965220652216522265223652246522565226652276522865229652306523165232652336523465235652366523765238652396524065241652426524365244652456524665247652486524965250652516525265253652546525565256652576525865259652606526165262652636526465265652666526765268652696527065271652726527365274652756527665277652786527965280652816528265283652846528565286652876528865289652906529165292652936529465295652966529765298652996530065301653026530365304653056530665307653086530965310653116531265313653146531565316653176531865319653206532165322653236532465325653266532765328653296533065331653326533365334653356533665337653386533965340653416534265343653446534565346653476534865349653506535165352653536535465355653566535765358653596536065361653626536365364653656536665367653686536965370653716537265373653746537565376653776537865379653806538165382653836538465385653866538765388653896539065391653926539365394653956539665397653986539965400654016540265403654046540565406654076540865409654106541165412654136541465415654166541765418654196542065421654226542365424654256542665427654286542965430654316543265433654346543565436654376543865439654406544165442654436544465445654466544765448654496545065451654526545365454654556545665457654586545965460654616546265463654646546565466654676546865469654706547165472654736547465475654766547765478654796548065481654826548365484654856548665487654886548965490654916549265493654946549565496654976549865499655006550165502655036550465505655066550765508655096551065511655126551365514655156551665517655186551965520655216552265523655246552565526655276552865529655306553165532655336553465535655366553765538655396554065541655426554365544655456554665547655486554965550655516555265553655546555565556655576555865559655606556165562655636556465565655666556765568655696557065571655726557365574655756557665577655786557965580655816558265583655846558565586655876558865589655906559165592655936559465595655966559765598655996560065601656026560365604656056560665607656086560965610656116561265613656146561565616656176561865619656206562165622656236562465625656266562765628656296563065631656326563365634656356563665637656386563965640656416564265643656446564565646656476564865649656506565165652656536565465655656566565765658656596566065661656626566365664656656566665667656686566965670656716567265673656746567565676656776567865679656806568165682656836568465685656866568765688656896569065691656926569365694656956569665697656986569965700657016570265703657046570565706657076570865709657106571165712657136571465715657166571765718657196572065721657226572365724657256572665727657286572965730657316573265733657346573565736657376573865739657406574165742657436574465745657466574765748657496575065751657526575365754657556575665757657586575965760657616576265763657646576565766657676576865769657706577165772657736577465775657766577765778657796578065781657826578365784657856578665787657886578965790657916579265793657946579565796657976579865799658006580165802658036580465805658066580765808658096581065811658126581365814658156581665817658186581965820658216582265823658246582565826658276582865829658306583165832658336583465835658366583765838658396584065841658426584365844658456584665847658486584965850658516585265853658546585565856658576585865859658606586165862658636586465865658666586765868658696587065871658726587365874658756587665877658786587965880658816588265883658846588565886658876588865889658906589165892658936589465895658966589765898658996590065901659026590365904659056590665907659086590965910659116591265913659146591565916659176591865919659206592165922659236592465925659266592765928659296593065931659326593365934659356593665937659386593965940659416594265943659446594565946659476594865949659506595165952659536595465955659566595765958659596596065961659626596365964659656596665967659686596965970659716597265973659746597565976659776597865979659806598165982659836598465985659866598765988659896599065991659926599365994659956599665997659986599966000660016600266003660046600566006660076600866009660106601166012660136601466015660166601766018660196602066021660226602366024660256602666027660286602966030660316603266033660346603566036660376603866039660406604166042660436604466045660466604766048660496605066051660526605366054660556605666057660586605966060660616606266063660646606566066660676606866069660706607166072660736607466075660766607766078660796608066081660826608366084660856608666087660886608966090660916609266093660946609566096660976609866099661006610166102661036610466105661066610766108661096611066111661126611366114661156611666117661186611966120661216612266123661246612566126661276612866129661306613166132661336613466135661366613766138661396614066141661426614366144661456614666147661486614966150661516615266153661546615566156661576615866159661606616166162661636616466165661666616766168661696617066171661726617366174661756617666177661786617966180661816618266183661846618566186661876618866189661906619166192661936619466195661966619766198661996620066201662026620366204662056620666207662086620966210662116621266213662146621566216662176621866219662206622166222662236622466225662266622766228662296623066231662326623366234662356623666237662386623966240662416624266243662446624566246662476624866249662506625166252662536625466255662566625766258662596626066261662626626366264662656626666267662686626966270662716627266273662746627566276662776627866279662806628166282662836628466285662866628766288662896629066291662926629366294662956629666297662986629966300663016630266303663046630566306663076630866309663106631166312663136631466315663166631766318663196632066321663226632366324663256632666327663286632966330663316633266333663346633566336663376633866339663406634166342663436634466345663466634766348663496635066351663526635366354663556635666357663586635966360663616636266363663646636566366663676636866369663706637166372663736637466375663766637766378663796638066381663826638366384663856638666387663886638966390663916639266393663946639566396663976639866399664006640166402664036640466405664066640766408664096641066411664126641366414664156641666417664186641966420664216642266423664246642566426664276642866429664306643166432664336643466435664366643766438664396644066441664426644366444664456644666447664486644966450664516645266453664546645566456664576645866459664606646166462664636646466465664666646766468664696647066471664726647366474664756647666477664786647966480664816648266483664846648566486664876648866489664906649166492664936649466495664966649766498664996650066501665026650366504665056650666507665086650966510665116651266513665146651566516665176651866519665206652166522665236652466525665266652766528665296653066531665326653366534665356653666537665386653966540665416654266543665446654566546665476654866549665506655166552665536655466555665566655766558665596656066561665626656366564665656656666567665686656966570665716657266573665746657566576665776657866579665806658166582665836658466585665866658766588665896659066591665926659366594665956659666597665986659966600666016660266603666046660566606666076660866609666106661166612666136661466615666166661766618666196662066621666226662366624666256662666627666286662966630666316663266633666346663566636666376663866639666406664166642666436664466645666466664766648666496665066651666526665366654666556665666657666586665966660666616666266663666646666566666666676666866669666706667166672666736667466675666766667766678666796668066681666826668366684666856668666687666886668966690666916669266693666946669566696666976669866699667006670166702667036670466705667066670766708667096671066711667126671366714667156671666717667186671966720667216672266723667246672566726667276672866729667306673166732667336673466735667366673766738667396674066741667426674366744667456674666747667486674966750667516675266753667546675566756667576675866759667606676166762667636676466765667666676766768667696677066771667726677366774667756677666777667786677966780667816678266783667846678566786667876678866789667906679166792667936679466795667966679766798667996680066801668026680366804668056680666807668086680966810668116681266813668146681566816668176681866819668206682166822668236682466825668266682766828668296683066831668326683366834668356683666837668386683966840668416684266843668446684566846668476684866849668506685166852668536685466855668566685766858668596686066861668626686366864668656686666867668686686966870668716687266873668746687566876668776687866879668806688166882668836688466885668866688766888668896689066891668926689366894668956689666897668986689966900669016690266903669046690566906669076690866909669106691166912669136691466915669166691766918669196692066921669226692366924669256692666927669286692966930669316693266933669346693566936669376693866939669406694166942669436694466945669466694766948669496695066951669526695366954669556695666957669586695966960669616696266963669646696566966669676696866969669706697166972669736697466975669766697766978669796698066981669826698366984669856698666987669886698966990669916699266993669946699566996669976699866999670006700167002670036700467005670066700767008670096701067011670126701367014670156701667017670186701967020670216702267023670246702567026670276702867029670306703167032670336703467035670366703767038670396704067041670426704367044670456704667047670486704967050670516705267053670546705567056670576705867059670606706167062670636706467065670666706767068670696707067071670726707367074670756707667077670786707967080670816708267083670846708567086670876708867089670906709167092670936709467095670966709767098670996710067101671026710367104671056710667107671086710967110671116711267113671146711567116671176711867119671206712167122671236712467125671266712767128671296713067131671326713367134671356713667137671386713967140671416714267143671446714567146671476714867149671506715167152671536715467155671566715767158671596716067161671626716367164671656716667167671686716967170671716717267173671746717567176671776717867179671806718167182671836718467185671866718767188671896719067191671926719367194671956719667197671986719967200672016720267203672046720567206672076720867209672106721167212672136721467215672166721767218672196722067221672226722367224672256722667227672286722967230672316723267233672346723567236672376723867239672406724167242672436724467245672466724767248672496725067251672526725367254672556725667257672586725967260672616726267263672646726567266672676726867269672706727167272672736727467275672766727767278672796728067281672826728367284672856728667287672886728967290672916729267293672946729567296672976729867299673006730167302673036730467305673066730767308673096731067311673126731367314673156731667317673186731967320673216732267323673246732567326673276732867329673306733167332673336733467335673366733767338673396734067341673426734367344673456734667347673486734967350673516735267353673546735567356673576735867359673606736167362673636736467365673666736767368673696737067371673726737367374673756737667377673786737967380673816738267383673846738567386673876738867389673906739167392673936739467395673966739767398673996740067401674026740367404674056740667407674086740967410674116741267413674146741567416674176741867419674206742167422674236742467425674266742767428674296743067431674326743367434674356743667437674386743967440674416744267443674446744567446674476744867449674506745167452674536745467455674566745767458674596746067461674626746367464674656746667467674686746967470674716747267473674746747567476674776747867479674806748167482674836748467485674866748767488674896749067491674926749367494674956749667497674986749967500675016750267503675046750567506675076750867509675106751167512675136751467515675166751767518675196752067521675226752367524675256752667527675286752967530675316753267533675346753567536675376753867539675406754167542675436754467545675466754767548675496755067551675526755367554675556755667557675586755967560675616756267563675646756567566675676756867569675706757167572675736757467575675766757767578675796758067581675826758367584675856758667587675886758967590675916759267593675946759567596675976759867599676006760167602676036760467605676066760767608676096761067611676126761367614676156761667617676186761967620676216762267623676246762567626676276762867629676306763167632676336763467635676366763767638676396764067641676426764367644676456764667647676486764967650676516765267653676546765567656676576765867659676606766167662676636766467665676666766767668676696767067671676726767367674676756767667677676786767967680676816768267683676846768567686676876768867689676906769167692676936769467695676966769767698676996770067701677026770367704677056770667707677086770967710677116771267713677146771567716677176771867719677206772167722677236772467725677266772767728677296773067731677326773367734677356773667737677386773967740677416774267743677446774567746677476774867749677506775167752677536775467755677566775767758677596776067761677626776367764677656776667767677686776967770677716777267773677746777567776677776777867779677806778167782677836778467785677866778767788677896779067791677926779367794677956779667797677986779967800678016780267803678046780567806678076780867809678106781167812678136781467815678166781767818678196782067821678226782367824678256782667827678286782967830678316783267833678346783567836678376783867839678406784167842678436784467845678466784767848678496785067851678526785367854678556785667857678586785967860678616786267863678646786567866678676786867869678706787167872678736787467875678766787767878678796788067881678826788367884678856788667887678886788967890678916789267893678946789567896678976789867899679006790167902679036790467905679066790767908679096791067911679126791367914679156791667917679186791967920679216792267923679246792567926679276792867929679306793167932679336793467935679366793767938679396794067941679426794367944679456794667947679486794967950679516795267953679546795567956679576795867959679606796167962679636796467965679666796767968679696797067971679726797367974679756797667977679786797967980679816798267983679846798567986679876798867989679906799167992679936799467995679966799767998679996800068001680026800368004680056800668007680086800968010680116801268013680146801568016680176801868019680206802168022680236802468025680266802768028680296803068031680326803368034680356803668037680386803968040680416804268043680446804568046680476804868049680506805168052680536805468055680566805768058680596806068061680626806368064680656806668067680686806968070680716807268073680746807568076680776807868079680806808168082680836808468085680866808768088680896809068091680926809368094680956809668097680986809968100681016810268103681046810568106681076810868109681106811168112681136811468115681166811768118681196812068121681226812368124681256812668127681286812968130681316813268133681346813568136681376813868139681406814168142681436814468145681466814768148681496815068151681526815368154681556815668157681586815968160681616816268163681646816568166681676816868169681706817168172681736817468175681766817768178681796818068181681826818368184681856818668187681886818968190681916819268193681946819568196681976819868199682006820168202682036820468205682066820768208682096821068211682126821368214682156821668217682186821968220682216822268223682246822568226682276822868229682306823168232682336823468235682366823768238682396824068241682426824368244682456824668247682486824968250682516825268253682546825568256682576825868259682606826168262682636826468265682666826768268682696827068271682726827368274682756827668277682786827968280682816828268283682846828568286682876828868289682906829168292682936829468295682966829768298682996830068301683026830368304683056830668307683086830968310683116831268313683146831568316683176831868319683206832168322683236832468325683266832768328683296833068331683326833368334683356833668337683386833968340683416834268343683446834568346683476834868349683506835168352683536835468355683566835768358683596836068361683626836368364683656836668367683686836968370683716837268373683746837568376683776837868379683806838168382683836838468385683866838768388683896839068391683926839368394683956839668397683986839968400684016840268403684046840568406684076840868409684106841168412684136841468415684166841768418684196842068421684226842368424684256842668427684286842968430684316843268433684346843568436684376843868439684406844168442684436844468445684466844768448684496845068451684526845368454684556845668457684586845968460684616846268463684646846568466684676846868469684706847168472684736847468475684766847768478684796848068481684826848368484684856848668487684886848968490684916849268493684946849568496684976849868499685006850168502685036850468505685066850768508685096851068511685126851368514685156851668517685186851968520685216852268523685246852568526685276852868529685306853168532685336853468535685366853768538685396854068541685426854368544685456854668547685486854968550685516855268553685546855568556685576855868559685606856168562685636856468565685666856768568685696857068571685726857368574685756857668577685786857968580685816858268583685846858568586685876858868589685906859168592685936859468595685966859768598685996860068601686026860368604686056860668607686086860968610686116861268613686146861568616686176861868619686206862168622686236862468625686266862768628686296863068631686326863368634686356863668637686386863968640686416864268643686446864568646686476864868649686506865168652686536865468655686566865768658686596866068661686626866368664686656866668667686686866968670686716867268673686746867568676686776867868679686806868168682686836868468685686866868768688686896869068691686926869368694686956869668697686986869968700687016870268703687046870568706687076870868709687106871168712687136871468715687166871768718687196872068721687226872368724687256872668727687286872968730687316873268733687346873568736687376873868739687406874168742687436874468745687466874768748687496875068751687526875368754687556875668757687586875968760687616876268763687646876568766687676876868769687706877168772687736877468775687766877768778687796878068781687826878368784687856878668787687886878968790687916879268793687946879568796687976879868799688006880168802688036880468805688066880768808688096881068811688126881368814688156881668817688186881968820688216882268823688246882568826688276882868829688306883168832688336883468835688366883768838688396884068841688426884368844688456884668847688486884968850688516885268853688546885568856688576885868859688606886168862688636886468865688666886768868688696887068871688726887368874688756887668877688786887968880688816888268883688846888568886688876888868889688906889168892688936889468895688966889768898688996890068901689026890368904689056890668907689086890968910689116891268913689146891568916689176891868919689206892168922689236892468925689266892768928689296893068931689326893368934689356893668937689386893968940689416894268943689446894568946689476894868949689506895168952689536895468955689566895768958689596896068961689626896368964689656896668967689686896968970689716897268973689746897568976689776897868979689806898168982689836898468985689866898768988689896899068991689926899368994689956899668997689986899969000690016900269003690046900569006690076900869009690106901169012690136901469015690166901769018690196902069021690226902369024690256902669027690286902969030690316903269033690346903569036690376903869039690406904169042690436904469045690466904769048690496905069051690526905369054690556905669057690586905969060690616906269063690646906569066690676906869069690706907169072690736907469075690766907769078690796908069081690826908369084690856908669087690886908969090690916909269093690946909569096690976909869099691006910169102691036910469105691066910769108691096911069111691126911369114691156911669117691186911969120691216912269123691246912569126691276912869129691306913169132691336913469135691366913769138691396914069141691426914369144691456914669147691486914969150691516915269153691546915569156691576915869159691606916169162691636916469165691666916769168691696917069171691726917369174691756917669177691786917969180691816918269183691846918569186691876918869189691906919169192691936919469195691966919769198691996920069201692026920369204692056920669207692086920969210692116921269213692146921569216692176921869219692206922169222692236922469225692266922769228692296923069231692326923369234692356923669237692386923969240692416924269243692446924569246692476924869249692506925169252692536925469255692566925769258692596926069261692626926369264692656926669267692686926969270692716927269273692746927569276692776927869279692806928169282692836928469285692866928769288692896929069291692926929369294692956929669297692986929969300693016930269303693046930569306693076930869309693106931169312693136931469315693166931769318693196932069321693226932369324693256932669327693286932969330693316933269333693346933569336693376933869339693406934169342693436934469345693466934769348693496935069351693526935369354693556935669357693586935969360693616936269363693646936569366693676936869369693706937169372693736937469375693766937769378693796938069381693826938369384693856938669387693886938969390693916939269393693946939569396693976939869399694006940169402694036940469405694066940769408694096941069411694126941369414694156941669417694186941969420694216942269423694246942569426694276942869429694306943169432694336943469435694366943769438694396944069441694426944369444694456944669447694486944969450694516945269453694546945569456694576945869459694606946169462694636946469465694666946769468694696947069471694726947369474694756947669477694786947969480694816948269483694846948569486694876948869489694906949169492694936949469495694966949769498694996950069501695026950369504695056950669507695086950969510695116951269513695146951569516695176951869519695206952169522695236952469525695266952769528695296953069531695326953369534695356953669537695386953969540695416954269543695446954569546695476954869549695506955169552695536955469555695566955769558695596956069561695626956369564695656956669567695686956969570695716957269573695746957569576695776957869579695806958169582695836958469585695866958769588695896959069591695926959369594695956959669597695986959969600696016960269603696046960569606696076960869609696106961169612696136961469615696166961769618696196962069621696226962369624696256962669627696286962969630696316963269633696346963569636696376963869639696406964169642696436964469645696466964769648696496965069651696526965369654696556965669657696586965969660696616966269663696646966569666696676966869669696706967169672696736967469675696766967769678696796968069681696826968369684696856968669687696886968969690696916969269693696946969569696696976969869699697006970169702697036970469705697066970769708697096971069711697126971369714697156971669717697186971969720697216972269723697246972569726697276972869729697306973169732697336973469735697366973769738697396974069741697426974369744697456974669747697486974969750697516975269753697546975569756697576975869759697606976169762697636976469765697666976769768697696977069771697726977369774697756977669777697786977969780697816978269783697846978569786697876978869789697906979169792697936979469795697966979769798697996980069801698026980369804698056980669807698086980969810698116981269813698146981569816698176981869819698206982169822698236982469825698266982769828698296983069831698326983369834698356983669837698386983969840698416984269843698446984569846698476984869849698506985169852698536985469855698566985769858698596986069861698626986369864698656986669867698686986969870698716987269873698746987569876698776987869879698806988169882698836988469885698866988769888698896989069891698926989369894698956989669897698986989969900699016990269903699046990569906699076990869909699106991169912699136991469915699166991769918699196992069921699226992369924699256992669927699286992969930699316993269933699346993569936699376993869939699406994169942699436994469945699466994769948699496995069951699526995369954699556995669957699586995969960699616996269963699646996569966699676996869969699706997169972699736997469975699766997769978699796998069981699826998369984699856998669987699886998969990699916999269993699946999569996699976999869999700007000170002700037000470005700067000770008700097001070011700127001370014700157001670017700187001970020700217002270023700247002570026700277002870029700307003170032700337003470035700367003770038700397004070041700427004370044700457004670047700487004970050700517005270053700547005570056700577005870059700607006170062700637006470065700667006770068700697007070071700727007370074700757007670077700787007970080700817008270083700847008570086700877008870089700907009170092700937009470095700967009770098700997010070101701027010370104701057010670107701087010970110701117011270113701147011570116701177011870119701207012170122701237012470125701267012770128701297013070131701327013370134701357013670137701387013970140701417014270143701447014570146701477014870149701507015170152701537015470155701567015770158701597016070161701627016370164701657016670167701687016970170701717017270173701747017570176701777017870179701807018170182701837018470185701867018770188701897019070191701927019370194701957019670197701987019970200702017020270203702047020570206702077020870209702107021170212702137021470215702167021770218702197022070221702227022370224702257022670227702287022970230702317023270233702347023570236702377023870239702407024170242702437024470245702467024770248702497025070251702527025370254702557025670257702587025970260702617026270263702647026570266702677026870269702707027170272702737027470275702767027770278702797028070281702827028370284702857028670287702887028970290702917029270293702947029570296702977029870299703007030170302703037030470305703067030770308703097031070311703127031370314703157031670317703187031970320703217032270323703247032570326703277032870329703307033170332703337033470335703367033770338703397034070341703427034370344703457034670347703487034970350703517035270353703547035570356703577035870359703607036170362703637036470365703667036770368703697037070371703727037370374703757037670377703787037970380703817038270383703847038570386703877038870389703907039170392703937039470395703967039770398703997040070401704027040370404704057040670407704087040970410704117041270413704147041570416704177041870419704207042170422704237042470425704267042770428704297043070431704327043370434704357043670437704387043970440704417044270443704447044570446704477044870449704507045170452704537045470455704567045770458704597046070461704627046370464704657046670467704687046970470704717047270473704747047570476704777047870479704807048170482704837048470485704867048770488704897049070491704927049370494704957049670497704987049970500705017050270503705047050570506705077050870509705107051170512705137051470515705167051770518705197052070521705227052370524705257052670527705287052970530705317053270533705347053570536705377053870539705407054170542705437054470545705467054770548705497055070551705527055370554705557055670557705587055970560705617056270563705647056570566705677056870569705707057170572705737057470575705767057770578705797058070581705827058370584705857058670587705887058970590705917059270593705947059570596705977059870599706007060170602706037060470605706067060770608706097061070611706127061370614706157061670617706187061970620706217062270623706247062570626706277062870629706307063170632706337063470635706367063770638706397064070641706427064370644706457064670647706487064970650706517065270653706547065570656706577065870659706607066170662706637066470665706667066770668706697067070671706727067370674706757067670677706787067970680706817068270683706847068570686706877068870689706907069170692706937069470695706967069770698706997070070701707027070370704707057070670707707087070970710707117071270713707147071570716707177071870719707207072170722707237072470725707267072770728707297073070731707327073370734707357073670737707387073970740707417074270743707447074570746707477074870749707507075170752707537075470755707567075770758707597076070761707627076370764707657076670767707687076970770707717077270773707747077570776707777077870779707807078170782707837078470785707867078770788707897079070791707927079370794707957079670797707987079970800708017080270803708047080570806708077080870809708107081170812708137081470815708167081770818708197082070821708227082370824708257082670827708287082970830708317083270833708347083570836708377083870839708407084170842708437084470845708467084770848708497085070851708527085370854708557085670857708587085970860708617086270863708647086570866708677086870869708707087170872708737087470875708767087770878708797088070881708827088370884708857088670887708887088970890708917089270893708947089570896708977089870899709007090170902709037090470905709067090770908709097091070911709127091370914709157091670917709187091970920709217092270923709247092570926709277092870929709307093170932709337093470935709367093770938709397094070941709427094370944709457094670947709487094970950709517095270953709547095570956709577095870959709607096170962709637096470965709667096770968709697097070971709727097370974709757097670977709787097970980709817098270983709847098570986709877098870989709907099170992709937099470995709967099770998709997100071001710027100371004710057100671007710087100971010710117101271013710147101571016710177101871019710207102171022710237102471025710267102771028710297103071031710327103371034710357103671037710387103971040710417104271043710447104571046710477104871049710507105171052710537105471055710567105771058710597106071061710627106371064710657106671067710687106971070710717107271073710747107571076710777107871079710807108171082710837108471085710867108771088710897109071091710927109371094710957109671097710987109971100711017110271103711047110571106711077110871109711107111171112711137111471115711167111771118711197112071121711227112371124711257112671127711287112971130711317113271133711347113571136711377113871139711407114171142711437114471145711467114771148711497115071151711527115371154711557115671157711587115971160711617116271163711647116571166711677116871169711707117171172711737117471175711767117771178711797118071181711827118371184711857118671187711887118971190711917119271193711947119571196711977119871199712007120171202712037120471205712067120771208712097121071211712127121371214712157121671217712187121971220712217122271223712247122571226712277122871229712307123171232712337123471235712367123771238712397124071241712427124371244712457124671247712487124971250712517125271253712547125571256712577125871259712607126171262712637126471265712667126771268712697127071271712727127371274712757127671277712787127971280712817128271283712847128571286712877128871289712907129171292712937129471295712967129771298712997130071301713027130371304713057130671307713087130971310713117131271313713147131571316713177131871319713207132171322713237132471325713267132771328713297133071331713327133371334713357133671337713387133971340713417134271343713447134571346713477134871349713507135171352713537135471355713567135771358713597136071361713627136371364713657136671367713687136971370713717137271373713747137571376713777137871379713807138171382713837138471385713867138771388713897139071391713927139371394713957139671397713987139971400714017140271403714047140571406714077140871409714107141171412714137141471415714167141771418714197142071421714227142371424714257142671427714287142971430714317143271433714347143571436714377143871439714407144171442714437144471445714467144771448714497145071451714527145371454714557145671457714587145971460714617146271463714647146571466714677146871469714707147171472714737147471475714767147771478714797148071481714827148371484714857148671487714887148971490714917149271493714947149571496714977149871499715007150171502715037150471505715067150771508715097151071511715127151371514715157151671517715187151971520715217152271523715247152571526715277152871529715307153171532715337153471535715367153771538715397154071541715427154371544715457154671547715487154971550715517155271553715547155571556715577155871559715607156171562715637156471565715667156771568715697157071571715727157371574715757157671577715787157971580715817158271583715847158571586715877158871589715907159171592715937159471595715967159771598715997160071601716027160371604716057160671607716087160971610716117161271613716147161571616716177161871619716207162171622716237162471625716267162771628716297163071631716327163371634716357163671637716387163971640716417164271643716447164571646716477164871649716507165171652716537165471655716567165771658716597166071661716627166371664716657166671667716687166971670716717167271673716747167571676716777167871679716807168171682716837168471685716867168771688716897169071691716927169371694716957169671697716987169971700717017170271703717047170571706717077170871709717107171171712717137171471715717167171771718717197172071721717227172371724717257172671727717287172971730717317173271733717347173571736717377173871739717407174171742717437174471745717467174771748717497175071751717527175371754717557175671757717587175971760717617176271763717647176571766717677176871769717707177171772717737177471775717767177771778717797178071781717827178371784717857178671787717887178971790717917179271793717947179571796717977179871799718007180171802718037180471805718067180771808718097181071811718127181371814718157181671817718187181971820718217182271823718247182571826718277182871829718307183171832718337183471835718367183771838718397184071841718427184371844718457184671847718487184971850718517185271853718547185571856718577185871859718607186171862718637186471865718667186771868718697187071871718727187371874718757187671877718787187971880718817188271883718847188571886718877188871889718907189171892718937189471895718967189771898718997190071901719027190371904719057190671907719087190971910719117191271913719147191571916719177191871919719207192171922719237192471925719267192771928719297193071931719327193371934719357193671937719387193971940719417194271943719447194571946719477194871949719507195171952719537195471955719567195771958719597196071961719627196371964719657196671967719687196971970719717197271973719747197571976719777197871979719807198171982719837198471985719867198771988719897199071991719927199371994719957199671997719987199972000720017200272003720047200572006720077200872009720107201172012720137201472015720167201772018720197202072021720227202372024720257202672027720287202972030720317203272033720347203572036720377203872039720407204172042720437204472045720467204772048720497205072051720527205372054720557205672057720587205972060720617206272063720647206572066720677206872069720707207172072720737207472075720767207772078720797208072081720827208372084720857208672087720887208972090720917209272093720947209572096720977209872099721007210172102721037210472105721067210772108721097211072111721127211372114721157211672117721187211972120721217212272123721247212572126721277212872129721307213172132721337213472135721367213772138721397214072141721427214372144721457214672147721487214972150721517215272153721547215572156721577215872159721607216172162721637216472165721667216772168721697217072171721727217372174721757217672177721787217972180721817218272183721847218572186721877218872189721907219172192721937219472195721967219772198721997220072201722027220372204722057220672207722087220972210722117221272213722147221572216722177221872219722207222172222722237222472225722267222772228722297223072231722327223372234722357223672237722387223972240722417224272243722447224572246722477224872249722507225172252722537225472255722567225772258722597226072261722627226372264722657226672267722687226972270722717227272273722747227572276722777227872279722807228172282722837228472285722867228772288722897229072291722927229372294722957229672297722987229972300723017230272303723047230572306723077230872309723107231172312723137231472315723167231772318723197232072321723227232372324723257232672327723287232972330723317233272333723347233572336723377233872339723407234172342723437234472345723467234772348723497235072351723527235372354723557235672357723587235972360723617236272363723647236572366723677236872369723707237172372723737237472375723767237772378723797238072381723827238372384723857238672387723887238972390723917239272393723947239572396723977239872399724007240172402724037240472405724067240772408724097241072411724127241372414724157241672417724187241972420724217242272423724247242572426724277242872429724307243172432724337243472435724367243772438724397244072441724427244372444724457244672447724487244972450724517245272453724547245572456724577245872459724607246172462724637246472465724667246772468724697247072471724727247372474724757247672477724787247972480724817248272483724847248572486724877248872489724907249172492724937249472495724967249772498724997250072501725027250372504725057250672507725087250972510725117251272513725147251572516725177251872519725207252172522725237252472525725267252772528725297253072531725327253372534725357253672537725387253972540725417254272543725447254572546725477254872549725507255172552725537255472555725567255772558725597256072561725627256372564725657256672567725687256972570725717257272573725747257572576725777257872579725807258172582725837258472585725867258772588725897259072591725927259372594725957259672597725987259972600726017260272603726047260572606726077260872609726107261172612726137261472615726167261772618726197262072621726227262372624726257262672627726287262972630726317263272633726347263572636726377263872639726407264172642726437264472645726467264772648726497265072651726527265372654726557265672657726587265972660726617266272663726647266572666726677266872669726707267172672726737267472675726767267772678726797268072681726827268372684726857268672687726887268972690726917269272693726947269572696726977269872699727007270172702727037270472705727067270772708727097271072711727127271372714727157271672717727187271972720727217272272723727247272572726727277272872729727307273172732727337273472735727367273772738727397274072741727427274372744727457274672747727487274972750727517275272753727547275572756727577275872759727607276172762727637276472765727667276772768727697277072771727727277372774727757277672777727787277972780727817278272783727847278572786727877278872789727907279172792727937279472795727967279772798727997280072801728027280372804728057280672807728087280972810728117281272813728147281572816728177281872819728207282172822728237282472825728267282772828728297283072831728327283372834728357283672837728387283972840728417284272843728447284572846728477284872849728507285172852728537285472855728567285772858728597286072861728627286372864728657286672867728687286972870728717287272873728747287572876728777287872879728807288172882728837288472885728867288772888728897289072891728927289372894728957289672897728987289972900729017290272903729047290572906729077290872909729107291172912729137291472915729167291772918729197292072921729227292372924729257292672927729287292972930729317293272933729347293572936729377293872939729407294172942729437294472945729467294772948729497295072951729527295372954729557295672957729587295972960729617296272963729647296572966729677296872969729707297172972729737297472975729767297772978729797298072981729827298372984729857298672987729887298972990729917299272993729947299572996729977299872999730007300173002730037300473005730067300773008730097301073011730127301373014730157301673017730187301973020730217302273023730247302573026730277302873029730307303173032730337303473035730367303773038730397304073041730427304373044730457304673047730487304973050730517305273053730547305573056730577305873059730607306173062730637306473065730667306773068730697307073071730727307373074730757307673077730787307973080730817308273083730847308573086730877308873089730907309173092730937309473095730967309773098730997310073101731027310373104731057310673107731087310973110731117311273113731147311573116731177311873119731207312173122731237312473125731267312773128731297313073131731327313373134731357313673137731387313973140731417314273143731447314573146731477314873149731507315173152731537315473155731567315773158731597316073161731627316373164731657316673167731687316973170731717317273173731747317573176731777317873179731807318173182731837318473185731867318773188731897319073191731927319373194731957319673197731987319973200732017320273203732047320573206732077320873209732107321173212732137321473215732167321773218732197322073221732227322373224732257322673227732287322973230732317323273233732347323573236732377323873239732407324173242732437324473245732467324773248732497325073251732527325373254732557325673257732587325973260732617326273263732647326573266732677326873269732707327173272732737327473275732767327773278732797328073281732827328373284732857328673287732887328973290732917329273293732947329573296732977329873299733007330173302733037330473305733067330773308733097331073311733127331373314733157331673317733187331973320733217332273323733247332573326733277332873329733307333173332733337333473335733367333773338733397334073341733427334373344733457334673347733487334973350733517335273353733547335573356733577335873359733607336173362733637336473365733667336773368733697337073371733727337373374733757337673377733787337973380733817338273383733847338573386733877338873389733907339173392733937339473395733967339773398733997340073401734027340373404734057340673407734087340973410734117341273413734147341573416734177341873419734207342173422734237342473425734267342773428734297343073431734327343373434734357343673437734387343973440734417344273443734447344573446734477344873449734507345173452734537345473455734567345773458734597346073461734627346373464734657346673467734687346973470734717347273473734747347573476734777347873479734807348173482734837348473485734867348773488734897349073491734927349373494734957349673497734987349973500735017350273503735047350573506735077350873509735107351173512735137351473515735167351773518735197352073521735227352373524735257352673527735287352973530735317353273533735347353573536735377353873539735407354173542735437354473545735467354773548735497355073551735527355373554735557355673557735587355973560735617356273563735647356573566735677356873569735707357173572735737357473575735767357773578735797358073581735827358373584735857358673587735887358973590735917359273593735947359573596735977359873599736007360173602736037360473605736067360773608736097361073611736127361373614736157361673617736187361973620736217362273623736247362573626736277362873629736307363173632736337363473635736367363773638736397364073641736427364373644736457364673647736487364973650736517365273653736547365573656736577365873659736607366173662736637366473665736667366773668736697367073671736727367373674736757367673677736787367973680736817368273683736847368573686736877368873689736907369173692736937369473695736967369773698736997370073701737027370373704737057370673707737087370973710737117371273713737147371573716737177371873719737207372173722737237372473725737267372773728737297373073731737327373373734737357373673737737387373973740737417374273743737447374573746737477374873749737507375173752737537375473755737567375773758737597376073761737627376373764737657376673767737687376973770737717377273773737747377573776737777377873779737807378173782737837378473785737867378773788737897379073791737927379373794737957379673797737987379973800738017380273803738047380573806738077380873809738107381173812738137381473815738167381773818738197382073821738227382373824738257382673827738287382973830738317383273833738347383573836738377383873839738407384173842738437384473845738467384773848738497385073851738527385373854738557385673857738587385973860738617386273863738647386573866738677386873869738707387173872738737387473875738767387773878738797388073881738827388373884738857388673887738887388973890738917389273893738947389573896738977389873899739007390173902739037390473905739067390773908739097391073911739127391373914739157391673917739187391973920739217392273923739247392573926739277392873929739307393173932739337393473935739367393773938739397394073941739427394373944739457394673947739487394973950739517395273953739547395573956739577395873959739607396173962739637396473965739667396773968739697397073971739727397373974739757397673977739787397973980739817398273983739847398573986739877398873989739907399173992739937399473995739967399773998739997400074001740027400374004740057400674007740087400974010740117401274013740147401574016740177401874019740207402174022740237402474025740267402774028740297403074031740327403374034740357403674037740387403974040740417404274043740447404574046740477404874049740507405174052740537405474055740567405774058740597406074061740627406374064740657406674067740687406974070740717407274073740747407574076740777407874079740807408174082740837408474085740867408774088740897409074091740927409374094740957409674097740987409974100741017410274103741047410574106741077410874109741107411174112741137411474115741167411774118741197412074121741227412374124741257412674127741287412974130741317413274133741347413574136741377413874139741407414174142741437414474145741467414774148741497415074151741527415374154741557415674157741587415974160741617416274163741647416574166741677416874169741707417174172741737417474175741767417774178741797418074181741827418374184741857418674187741887418974190741917419274193741947419574196741977419874199742007420174202742037420474205742067420774208742097421074211742127421374214742157421674217742187421974220742217422274223742247422574226742277422874229742307423174232742337423474235742367423774238742397424074241742427424374244742457424674247742487424974250742517425274253742547425574256742577425874259742607426174262742637426474265742667426774268742697427074271742727427374274742757427674277742787427974280742817428274283742847428574286742877428874289742907429174292742937429474295742967429774298742997430074301743027430374304743057430674307743087430974310743117431274313743147431574316743177431874319743207432174322743237432474325743267432774328743297433074331743327433374334743357433674337743387433974340743417434274343743447434574346743477434874349743507435174352743537435474355743567435774358743597436074361743627436374364743657436674367743687436974370743717437274373743747437574376743777437874379743807438174382743837438474385743867438774388743897439074391743927439374394743957439674397743987439974400744017440274403744047440574406744077440874409744107441174412744137441474415744167441774418744197442074421744227442374424744257442674427744287442974430744317443274433744347443574436744377443874439744407444174442744437444474445744467444774448744497445074451744527445374454744557445674457744587445974460744617446274463744647446574466744677446874469744707447174472744737447474475744767447774478744797448074481744827448374484744857448674487744887448974490744917449274493744947449574496744977449874499745007450174502745037450474505745067450774508745097451074511745127451374514745157451674517745187451974520745217452274523745247452574526745277452874529745307453174532745337453474535745367453774538745397454074541745427454374544745457454674547745487454974550745517455274553745547455574556745577455874559745607456174562745637456474565745667456774568745697457074571745727457374574745757457674577745787457974580745817458274583745847458574586745877458874589745907459174592745937459474595745967459774598745997460074601746027460374604746057460674607746087460974610746117461274613746147461574616746177461874619746207462174622746237462474625746267462774628746297463074631746327463374634746357463674637746387463974640746417464274643746447464574646746477464874649746507465174652746537465474655746567465774658746597466074661746627466374664746657466674667746687466974670746717467274673746747467574676746777467874679746807468174682746837468474685746867468774688746897469074691746927469374694746957469674697746987469974700747017470274703747047470574706747077470874709747107471174712747137471474715747167471774718747197472074721747227472374724747257472674727747287472974730747317473274733747347473574736747377473874739747407474174742747437474474745747467474774748747497475074751747527475374754747557475674757747587475974760747617476274763747647476574766747677476874769747707477174772747737477474775747767477774778747797478074781747827478374784747857478674787747887478974790747917479274793747947479574796747977479874799748007480174802748037480474805748067480774808748097481074811748127481374814748157481674817748187481974820748217482274823748247482574826748277482874829748307483174832748337483474835748367483774838748397484074841748427484374844748457484674847748487484974850748517485274853748547485574856748577485874859748607486174862748637486474865748667486774868748697487074871748727487374874748757487674877748787487974880748817488274883748847488574886748877488874889748907489174892748937489474895748967489774898748997490074901749027490374904749057490674907749087490974910749117491274913749147491574916749177491874919749207492174922749237492474925749267492774928749297493074931749327493374934749357493674937749387493974940749417494274943749447494574946749477494874949749507495174952749537495474955749567495774958749597496074961749627496374964749657496674967749687496974970749717497274973749747497574976749777497874979749807498174982749837498474985749867498774988749897499074991749927499374994749957499674997749987499975000750017500275003750047500575006750077500875009750107501175012750137501475015750167501775018750197502075021750227502375024750257502675027750287502975030750317503275033750347503575036750377503875039750407504175042750437504475045750467504775048750497505075051750527505375054750557505675057750587505975060750617506275063750647506575066750677506875069750707507175072750737507475075750767507775078750797508075081750827508375084750857508675087750887508975090750917509275093750947509575096750977509875099751007510175102751037510475105751067510775108751097511075111751127511375114751157511675117751187511975120751217512275123751247512575126751277512875129751307513175132751337513475135751367513775138751397514075141751427514375144751457514675147751487514975150751517515275153751547515575156751577515875159751607516175162751637516475165751667516775168751697517075171751727517375174751757517675177751787517975180751817518275183751847518575186751877518875189751907519175192751937519475195751967519775198751997520075201752027520375204752057520675207752087520975210752117521275213752147521575216752177521875219752207522175222752237522475225752267522775228752297523075231752327523375234752357523675237752387523975240752417524275243752447524575246752477524875249752507525175252752537525475255752567525775258752597526075261752627526375264752657526675267752687526975270752717527275273752747527575276752777527875279752807528175282752837528475285752867528775288752897529075291752927529375294752957529675297752987529975300753017530275303753047530575306753077530875309753107531175312753137531475315753167531775318753197532075321753227532375324753257532675327753287532975330753317533275333753347533575336753377533875339753407534175342753437534475345753467534775348753497535075351753527535375354753557535675357753587535975360753617536275363753647536575366753677536875369753707537175372753737537475375753767537775378753797538075381753827538375384753857538675387753887538975390753917539275393753947539575396753977539875399754007540175402754037540475405754067540775408754097541075411754127541375414754157541675417754187541975420754217542275423754247542575426754277542875429754307543175432754337543475435754367543775438754397544075441754427544375444754457544675447754487544975450754517545275453754547545575456754577545875459754607546175462754637546475465754667546775468754697547075471754727547375474754757547675477754787547975480754817548275483754847548575486754877548875489754907549175492754937549475495754967549775498754997550075501755027550375504755057550675507755087550975510755117551275513755147551575516755177551875519755207552175522755237552475525755267552775528755297553075531755327553375534755357553675537755387553975540755417554275543755447554575546755477554875549755507555175552755537555475555755567555775558755597556075561755627556375564755657556675567755687556975570755717557275573755747557575576755777557875579755807558175582755837558475585755867558775588755897559075591755927559375594755957559675597755987559975600756017560275603756047560575606756077560875609756107561175612756137561475615756167561775618756197562075621756227562375624756257562675627756287562975630756317563275633756347563575636756377563875639756407564175642756437564475645756467564775648756497565075651756527565375654756557565675657756587565975660756617566275663756647566575666756677566875669756707567175672756737567475675756767567775678756797568075681756827568375684756857568675687756887568975690756917569275693756947569575696756977569875699757007570175702757037570475705757067570775708757097571075711757127571375714757157571675717757187571975720757217572275723757247572575726757277572875729757307573175732757337573475735757367573775738757397574075741757427574375744757457574675747757487574975750757517575275753757547575575756757577575875759757607576175762757637576475765757667576775768757697577075771757727577375774757757577675777757787577975780757817578275783757847578575786757877578875789757907579175792757937579475795757967579775798757997580075801758027580375804758057580675807758087580975810758117581275813758147581575816758177581875819758207582175822758237582475825758267582775828758297583075831758327583375834758357583675837758387583975840758417584275843758447584575846758477584875849758507585175852758537585475855758567585775858758597586075861758627586375864758657586675867758687586975870758717587275873758747587575876758777587875879758807588175882758837588475885758867588775888758897589075891758927589375894758957589675897758987589975900759017590275903759047590575906759077590875909759107591175912759137591475915759167591775918759197592075921759227592375924759257592675927759287592975930759317593275933759347593575936759377593875939759407594175942759437594475945759467594775948759497595075951759527595375954759557595675957759587595975960759617596275963759647596575966759677596875969759707597175972759737597475975759767597775978759797598075981759827598375984759857598675987759887598975990759917599275993759947599575996759977599875999760007600176002760037600476005760067600776008760097601076011760127601376014760157601676017760187601976020760217602276023760247602576026760277602876029760307603176032760337603476035760367603776038760397604076041760427604376044760457604676047760487604976050760517605276053760547605576056760577605876059760607606176062760637606476065760667606776068760697607076071760727607376074760757607676077760787607976080760817608276083760847608576086760877608876089760907609176092760937609476095760967609776098760997610076101761027610376104761057610676107761087610976110761117611276113761147611576116761177611876119761207612176122761237612476125761267612776128761297613076131761327613376134761357613676137761387613976140761417614276143761447614576146761477614876149761507615176152761537615476155761567615776158761597616076161761627616376164761657616676167761687616976170761717617276173761747617576176761777617876179761807618176182761837618476185761867618776188761897619076191761927619376194761957619676197761987619976200762017620276203762047620576206762077620876209762107621176212762137621476215762167621776218762197622076221762227622376224762257622676227762287622976230762317623276233762347623576236762377623876239762407624176242762437624476245762467624776248762497625076251762527625376254762557625676257762587625976260762617626276263762647626576266762677626876269762707627176272762737627476275762767627776278762797628076281762827628376284762857628676287762887628976290762917629276293762947629576296762977629876299763007630176302763037630476305763067630776308763097631076311763127631376314763157631676317763187631976320763217632276323763247632576326763277632876329763307633176332763337633476335763367633776338763397634076341763427634376344763457634676347763487634976350763517635276353763547635576356763577635876359763607636176362763637636476365763667636776368763697637076371763727637376374763757637676377763787637976380763817638276383763847638576386763877638876389763907639176392763937639476395763967639776398763997640076401764027640376404764057640676407764087640976410764117641276413764147641576416764177641876419764207642176422764237642476425764267642776428764297643076431764327643376434764357643676437764387643976440764417644276443764447644576446764477644876449764507645176452764537645476455764567645776458764597646076461764627646376464764657646676467764687646976470764717647276473764747647576476764777647876479764807648176482764837648476485764867648776488764897649076491764927649376494764957649676497764987649976500765017650276503765047650576506765077650876509765107651176512765137651476515765167651776518765197652076521765227652376524765257652676527765287652976530765317653276533765347653576536765377653876539765407654176542765437654476545765467654776548765497655076551765527655376554765557655676557765587655976560765617656276563765647656576566765677656876569765707657176572765737657476575765767657776578765797658076581765827658376584765857658676587765887658976590765917659276593765947659576596765977659876599766007660176602766037660476605766067660776608766097661076611766127661376614766157661676617766187661976620766217662276623766247662576626766277662876629766307663176632766337663476635766367663776638766397664076641766427664376644766457664676647766487664976650766517665276653766547665576656766577665876659766607666176662766637666476665766667666776668766697667076671766727667376674766757667676677766787667976680766817668276683766847668576686766877668876689766907669176692766937669476695766967669776698766997670076701767027670376704767057670676707767087670976710767117671276713767147671576716767177671876719767207672176722767237672476725767267672776728767297673076731767327673376734767357673676737767387673976740767417674276743767447674576746767477674876749767507675176752767537675476755767567675776758767597676076761767627676376764767657676676767767687676976770767717677276773767747677576776767777677876779767807678176782767837678476785767867678776788767897679076791767927679376794767957679676797767987679976800768017680276803768047680576806768077680876809768107681176812768137681476815768167681776818768197682076821768227682376824768257682676827768287682976830768317683276833768347683576836768377683876839768407684176842768437684476845768467684776848768497685076851768527685376854768557685676857768587685976860768617686276863768647686576866768677686876869768707687176872768737687476875768767687776878768797688076881768827688376884768857688676887768887688976890768917689276893768947689576896768977689876899769007690176902769037690476905769067690776908769097691076911769127691376914769157691676917769187691976920769217692276923769247692576926769277692876929769307693176932769337693476935769367693776938769397694076941769427694376944769457694676947769487694976950769517695276953769547695576956769577695876959769607696176962769637696476965769667696776968769697697076971769727697376974769757697676977769787697976980769817698276983769847698576986769877698876989769907699176992769937699476995769967699776998769997700077001770027700377004770057700677007770087700977010770117701277013770147701577016770177701877019770207702177022770237702477025770267702777028770297703077031770327703377034770357703677037770387703977040770417704277043770447704577046770477704877049770507705177052770537705477055770567705777058770597706077061770627706377064770657706677067770687706977070770717707277073770747707577076770777707877079770807708177082770837708477085770867708777088770897709077091770927709377094770957709677097770987709977100771017710277103771047710577106771077710877109771107711177112771137711477115771167711777118771197712077121771227712377124771257712677127771287712977130771317713277133771347713577136771377713877139771407714177142771437714477145771467714777148771497715077151771527715377154771557715677157771587715977160771617716277163771647716577166771677716877169771707717177172771737717477175771767717777178771797718077181771827718377184771857718677187771887718977190771917719277193771947719577196771977719877199772007720177202772037720477205772067720777208772097721077211772127721377214772157721677217772187721977220772217722277223772247722577226772277722877229772307723177232772337723477235772367723777238772397724077241772427724377244772457724677247772487724977250772517725277253772547725577256772577725877259772607726177262772637726477265772667726777268772697727077271772727727377274772757727677277772787727977280772817728277283772847728577286772877728877289772907729177292772937729477295772967729777298772997730077301773027730377304773057730677307773087730977310773117731277313773147731577316773177731877319773207732177322773237732477325773267732777328773297733077331773327733377334773357733677337773387733977340773417734277343773447734577346773477734877349773507735177352773537735477355773567735777358773597736077361773627736377364773657736677367773687736977370773717737277373773747737577376773777737877379773807738177382773837738477385773867738777388773897739077391773927739377394773957739677397773987739977400774017740277403774047740577406774077740877409774107741177412774137741477415774167741777418774197742077421774227742377424774257742677427774287742977430774317743277433774347743577436774377743877439774407744177442774437744477445774467744777448774497745077451774527745377454774557745677457774587745977460774617746277463774647746577466774677746877469774707747177472774737747477475774767747777478774797748077481774827748377484774857748677487774887748977490774917749277493774947749577496774977749877499775007750177502775037750477505775067750777508775097751077511775127751377514775157751677517775187751977520775217752277523775247752577526775277752877529775307753177532775337753477535775367753777538775397754077541775427754377544775457754677547775487754977550775517755277553775547755577556775577755877559775607756177562775637756477565775667756777568775697757077571775727757377574775757757677577775787757977580775817758277583775847758577586775877758877589775907759177592775937759477595775967759777598775997760077601776027760377604776057760677607776087760977610776117761277613776147761577616776177761877619776207762177622776237762477625776267762777628776297763077631776327763377634776357763677637776387763977640776417764277643776447764577646776477764877649776507765177652776537765477655776567765777658776597766077661776627766377664776657766677667776687766977670776717767277673776747767577676776777767877679776807768177682776837768477685776867768777688776897769077691776927769377694776957769677697776987769977700777017770277703777047770577706777077770877709777107771177712777137771477715777167771777718777197772077721777227772377724777257772677727777287772977730777317773277733777347773577736777377773877739777407774177742777437774477745777467774777748777497775077751777527775377754777557775677757777587775977760777617776277763777647776577766777677776877769777707777177772777737777477775777767777777778777797778077781777827778377784777857778677787777887778977790777917779277793777947779577796777977779877799778007780177802778037780477805778067780777808778097781077811778127781377814778157781677817778187781977820778217782277823778247782577826778277782877829778307783177832778337783477835778367783777838778397784077841778427784377844778457784677847778487784977850778517785277853778547785577856778577785877859778607786177862778637786477865778667786777868778697787077871778727787377874778757787677877778787787977880778817788277883778847788577886778877788877889778907789177892778937789477895778967789777898778997790077901779027790377904779057790677907779087790977910779117791277913779147791577916779177791877919779207792177922779237792477925779267792777928779297793077931779327793377934779357793677937779387793977940779417794277943779447794577946779477794877949779507795177952779537795477955779567795777958779597796077961779627796377964779657796677967779687796977970779717797277973779747797577976779777797877979779807798177982779837798477985779867798777988779897799077991779927799377994779957799677997779987799978000780017800278003780047800578006780077800878009780107801178012780137801478015780167801778018780197802078021780227802378024780257802678027780287802978030780317803278033780347803578036780377803878039780407804178042780437804478045780467804778048780497805078051780527805378054780557805678057780587805978060780617806278063780647806578066780677806878069780707807178072780737807478075780767807778078780797808078081780827808378084780857808678087780887808978090780917809278093780947809578096780977809878099781007810178102781037810478105781067810778108781097811078111781127811378114781157811678117781187811978120781217812278123781247812578126781277812878129781307813178132781337813478135781367813778138781397814078141781427814378144781457814678147781487814978150781517815278153781547815578156781577815878159781607816178162781637816478165781667816778168781697817078171781727817378174781757817678177781787817978180781817818278183781847818578186781877818878189781907819178192781937819478195781967819778198781997820078201782027820378204782057820678207782087820978210782117821278213782147821578216782177821878219782207822178222782237822478225782267822778228782297823078231782327823378234782357823678237782387823978240782417824278243782447824578246782477824878249782507825178252782537825478255782567825778258782597826078261782627826378264782657826678267782687826978270782717827278273782747827578276782777827878279782807828178282782837828478285782867828778288782897829078291782927829378294782957829678297782987829978300783017830278303783047830578306783077830878309783107831178312783137831478315783167831778318783197832078321783227832378324783257832678327783287832978330783317833278333783347833578336783377833878339783407834178342783437834478345783467834778348783497835078351783527835378354783557835678357783587835978360783617836278363783647836578366783677836878369783707837178372783737837478375783767837778378783797838078381783827838378384783857838678387783887838978390783917839278393783947839578396783977839878399784007840178402784037840478405784067840778408784097841078411784127841378414784157841678417784187841978420784217842278423784247842578426784277842878429784307843178432784337843478435784367843778438784397844078441784427844378444784457844678447784487844978450784517845278453784547845578456784577845878459784607846178462784637846478465784667846778468784697847078471784727847378474784757847678477784787847978480784817848278483784847848578486784877848878489784907849178492784937849478495784967849778498784997850078501785027850378504785057850678507785087850978510785117851278513785147851578516785177851878519785207852178522785237852478525785267852778528785297853078531785327853378534785357853678537785387853978540785417854278543785447854578546785477854878549785507855178552785537855478555785567855778558785597856078561785627856378564785657856678567785687856978570785717857278573785747857578576785777857878579785807858178582785837858478585785867858778588785897859078591785927859378594785957859678597785987859978600786017860278603786047860578606786077860878609786107861178612786137861478615786167861778618786197862078621786227862378624786257862678627786287862978630786317863278633786347863578636786377863878639786407864178642786437864478645786467864778648786497865078651786527865378654786557865678657786587865978660786617866278663786647866578666786677866878669786707867178672786737867478675786767867778678786797868078681786827868378684786857868678687786887868978690786917869278693786947869578696786977869878699787007870178702787037870478705787067870778708787097871078711787127871378714787157871678717787187871978720787217872278723787247872578726787277872878729787307873178732787337873478735787367873778738787397874078741787427874378744787457874678747787487874978750787517875278753787547875578756787577875878759787607876178762787637876478765787667876778768787697877078771787727877378774787757877678777787787877978780787817878278783787847878578786787877878878789787907879178792787937879478795787967879778798787997880078801788027880378804788057880678807788087880978810788117881278813788147881578816788177881878819788207882178822788237882478825788267882778828788297883078831788327883378834788357883678837788387883978840788417884278843788447884578846788477884878849788507885178852788537885478855788567885778858788597886078861788627886378864788657886678867788687886978870788717887278873788747887578876788777887878879788807888178882788837888478885788867888778888788897889078891788927889378894788957889678897788987889978900789017890278903789047890578906789077890878909789107891178912789137891478915789167891778918789197892078921789227892378924789257892678927789287892978930789317893278933789347893578936789377893878939789407894178942789437894478945789467894778948789497895078951789527895378954789557895678957789587895978960789617896278963789647896578966789677896878969789707897178972789737897478975789767897778978789797898078981789827898378984789857898678987789887898978990789917899278993789947899578996789977899878999790007900179002790037900479005790067900779008790097901079011790127901379014790157901679017790187901979020790217902279023790247902579026790277902879029790307903179032790337903479035790367903779038790397904079041790427904379044790457904679047790487904979050790517905279053790547905579056790577905879059790607906179062790637906479065790667906779068790697907079071790727907379074790757907679077790787907979080790817908279083790847908579086790877908879089790907909179092790937909479095790967909779098790997910079101791027910379104791057910679107791087910979110791117911279113791147911579116791177911879119791207912179122791237912479125791267912779128791297913079131791327913379134791357913679137791387913979140791417914279143791447914579146791477914879149791507915179152791537915479155791567915779158791597916079161791627916379164791657916679167791687916979170791717917279173791747917579176791777917879179791807918179182791837918479185791867918779188791897919079191791927919379194791957919679197791987919979200792017920279203792047920579206792077920879209792107921179212792137921479215792167921779218792197922079221792227922379224792257922679227792287922979230792317923279233792347923579236792377923879239792407924179242792437924479245792467924779248792497925079251792527925379254792557925679257792587925979260792617926279263792647926579266792677926879269792707927179272792737927479275792767927779278792797928079281792827928379284792857928679287792887928979290792917929279293792947929579296792977929879299793007930179302793037930479305793067930779308793097931079311793127931379314793157931679317793187931979320793217932279323793247932579326793277932879329793307933179332793337933479335793367933779338793397934079341793427934379344793457934679347793487934979350793517935279353793547935579356793577935879359793607936179362793637936479365793667936779368793697937079371793727937379374793757937679377793787937979380793817938279383793847938579386793877938879389793907939179392793937939479395793967939779398793997940079401794027940379404794057940679407794087940979410794117941279413794147941579416794177941879419794207942179422794237942479425794267942779428794297943079431794327943379434794357943679437794387943979440794417944279443794447944579446794477944879449794507945179452794537945479455794567945779458794597946079461794627946379464794657946679467794687946979470794717947279473794747947579476794777947879479794807948179482794837948479485794867948779488794897949079491794927949379494794957949679497794987949979500795017950279503795047950579506795077950879509795107951179512795137951479515795167951779518795197952079521795227952379524795257952679527795287952979530795317953279533795347953579536795377953879539795407954179542795437954479545795467954779548795497955079551795527955379554795557955679557795587955979560795617956279563795647956579566795677956879569795707957179572795737957479575795767957779578795797958079581795827958379584795857958679587795887958979590795917959279593795947959579596795977959879599796007960179602796037960479605796067960779608796097961079611796127961379614796157961679617796187961979620796217962279623796247962579626796277962879629796307963179632796337963479635796367963779638796397964079641796427964379644796457964679647796487964979650796517965279653796547965579656796577965879659796607966179662796637966479665796667966779668796697967079671796727967379674796757967679677796787967979680796817968279683796847968579686796877968879689796907969179692796937969479695796967969779698796997970079701797027970379704797057970679707797087970979710797117971279713797147971579716797177971879719797207972179722797237972479725797267972779728797297973079731797327973379734797357973679737797387973979740797417974279743797447974579746797477974879749797507975179752797537975479755797567975779758797597976079761797627976379764797657976679767797687976979770797717977279773797747977579776797777977879779797807978179782797837978479785797867978779788797897979079791797927979379794797957979679797797987979979800798017980279803798047980579806798077980879809798107981179812798137981479815798167981779818798197982079821798227982379824798257982679827798287982979830798317983279833798347983579836798377983879839798407984179842798437984479845798467984779848798497985079851798527985379854798557985679857798587985979860798617986279863798647986579866798677986879869798707987179872798737987479875798767987779878798797988079881798827988379884798857988679887798887988979890798917989279893798947989579896798977989879899799007990179902799037990479905799067990779908799097991079911799127991379914799157991679917799187991979920799217992279923799247992579926799277992879929799307993179932799337993479935799367993779938799397994079941799427994379944799457994679947799487994979950799517995279953799547995579956799577995879959799607996179962799637996479965799667996779968799697997079971799727997379974799757997679977799787997979980799817998279983799847998579986799877998879989799907999179992799937999479995799967999779998799998000080001800028000380004800058000680007800088000980010800118001280013800148001580016800178001880019800208002180022800238002480025800268002780028800298003080031800328003380034800358003680037800388003980040800418004280043800448004580046800478004880049800508005180052800538005480055800568005780058800598006080061800628006380064800658006680067800688006980070800718007280073800748007580076800778007880079800808008180082800838008480085800868008780088800898009080091800928009380094800958009680097800988009980100801018010280103801048010580106801078010880109801108011180112801138011480115801168011780118801198012080121801228012380124801258012680127801288012980130801318013280133801348013580136801378013880139801408014180142801438014480145801468014780148801498015080151801528015380154801558015680157801588015980160801618016280163801648016580166801678016880169801708017180172801738017480175801768017780178801798018080181801828018380184801858018680187801888018980190801918019280193801948019580196801978019880199802008020180202802038020480205802068020780208802098021080211802128021380214802158021680217802188021980220802218022280223802248022580226802278022880229802308023180232802338023480235802368023780238802398024080241802428024380244802458024680247802488024980250802518025280253802548025580256802578025880259802608026180262802638026480265802668026780268802698027080271802728027380274802758027680277802788027980280802818028280283802848028580286802878028880289802908029180292802938029480295802968029780298802998030080301803028030380304803058030680307803088030980310803118031280313803148031580316803178031880319803208032180322803238032480325803268032780328803298033080331803328033380334803358033680337803388033980340803418034280343803448034580346803478034880349803508035180352803538035480355803568035780358803598036080361803628036380364803658036680367803688036980370803718037280373803748037580376803778037880379803808038180382803838038480385803868038780388803898039080391803928039380394803958039680397803988039980400804018040280403804048040580406804078040880409804108041180412804138041480415804168041780418804198042080421804228042380424804258042680427804288042980430804318043280433804348043580436804378043880439804408044180442804438044480445804468044780448804498045080451804528045380454804558045680457804588045980460804618046280463804648046580466804678046880469804708047180472804738047480475804768047780478804798048080481804828048380484804858048680487804888048980490804918049280493804948049580496804978049880499805008050180502805038050480505805068050780508805098051080511805128051380514805158051680517805188051980520805218052280523805248052580526805278052880529805308053180532805338053480535805368053780538805398054080541805428054380544805458054680547805488054980550805518055280553805548055580556805578055880559805608056180562805638056480565805668056780568805698057080571805728057380574805758057680577805788057980580805818058280583805848058580586805878058880589805908059180592805938059480595805968059780598805998060080601806028060380604806058060680607806088060980610806118061280613806148061580616806178061880619806208062180622806238062480625806268062780628806298063080631806328063380634806358063680637806388063980640806418064280643806448064580646806478064880649806508065180652806538065480655806568065780658806598066080661806628066380664806658066680667806688066980670806718067280673806748067580676806778067880679806808068180682806838068480685806868068780688806898069080691806928069380694806958069680697806988069980700807018070280703807048070580706807078070880709807108071180712807138071480715807168071780718807198072080721807228072380724807258072680727807288072980730807318073280733807348073580736807378073880739807408074180742807438074480745807468074780748807498075080751807528075380754807558075680757807588075980760807618076280763807648076580766807678076880769807708077180772807738077480775807768077780778807798078080781807828078380784807858078680787807888078980790807918079280793807948079580796807978079880799808008080180802808038080480805808068080780808808098081080811808128081380814808158081680817808188081980820808218082280823808248082580826808278082880829808308083180832808338083480835808368083780838808398084080841808428084380844808458084680847808488084980850808518085280853808548085580856808578085880859808608086180862808638086480865808668086780868808698087080871808728087380874808758087680877808788087980880808818088280883808848088580886808878088880889808908089180892808938089480895808968089780898808998090080901809028090380904809058090680907809088090980910809118091280913809148091580916809178091880919809208092180922809238092480925809268092780928809298093080931809328093380934809358093680937809388093980940809418094280943809448094580946809478094880949809508095180952809538095480955809568095780958809598096080961809628096380964809658096680967809688096980970809718097280973809748097580976809778097880979809808098180982809838098480985809868098780988809898099080991809928099380994809958099680997809988099981000810018100281003810048100581006810078100881009810108101181012810138101481015810168101781018810198102081021810228102381024810258102681027810288102981030810318103281033810348103581036810378103881039810408104181042810438104481045810468104781048810498105081051810528105381054810558105681057810588105981060810618106281063810648106581066810678106881069810708107181072810738107481075810768107781078810798108081081810828108381084810858108681087810888108981090810918109281093810948109581096810978109881099811008110181102811038110481105811068110781108811098111081111811128111381114811158111681117811188111981120811218112281123811248112581126811278112881129811308113181132811338113481135811368113781138811398114081141811428114381144811458114681147811488114981150811518115281153811548115581156811578115881159811608116181162811638116481165811668116781168811698117081171811728117381174811758117681177811788117981180811818118281183811848118581186811878118881189811908119181192811938119481195811968119781198811998120081201812028120381204812058120681207812088120981210812118121281213812148121581216812178121881219812208122181222812238122481225812268122781228812298123081231812328123381234812358123681237812388123981240812418124281243812448124581246812478124881249812508125181252812538125481255812568125781258812598126081261812628126381264812658126681267812688126981270812718127281273812748127581276812778127881279812808128181282812838128481285812868128781288812898129081291812928129381294812958129681297812988129981300813018130281303813048130581306813078130881309813108131181312813138131481315813168131781318813198132081321813228132381324813258132681327813288132981330813318133281333813348133581336813378133881339813408134181342813438134481345813468134781348813498135081351813528135381354813558135681357813588135981360813618136281363813648136581366813678136881369813708137181372813738137481375813768137781378813798138081381813828138381384813858138681387813888138981390813918139281393813948139581396813978139881399814008140181402814038140481405814068140781408814098141081411814128141381414814158141681417814188141981420814218142281423814248142581426814278142881429814308143181432814338143481435814368143781438814398144081441814428144381444814458144681447814488144981450814518145281453814548145581456814578145881459814608146181462814638146481465814668146781468814698147081471814728147381474814758147681477814788147981480814818148281483814848148581486814878148881489814908149181492814938149481495814968149781498814998150081501815028150381504815058150681507815088150981510815118151281513815148151581516815178151881519815208152181522815238152481525815268152781528815298153081531815328153381534815358153681537815388153981540815418154281543815448154581546815478154881549815508155181552815538155481555815568155781558815598156081561815628156381564815658156681567815688156981570815718157281573815748157581576815778157881579815808158181582815838158481585815868158781588815898159081591815928159381594815958159681597815988159981600816018160281603816048160581606816078160881609816108161181612816138161481615816168161781618816198162081621816228162381624816258162681627816288162981630816318163281633816348163581636816378163881639816408164181642816438164481645816468164781648816498165081651816528165381654816558165681657816588165981660816618166281663816648166581666816678166881669816708167181672816738167481675816768167781678816798168081681816828168381684816858168681687816888168981690816918169281693816948169581696816978169881699817008170181702817038170481705817068170781708817098171081711817128171381714817158171681717817188171981720817218172281723817248172581726817278172881729817308173181732817338173481735817368173781738817398174081741817428174381744817458174681747817488174981750817518175281753817548175581756817578175881759817608176181762817638176481765817668176781768817698177081771817728177381774817758177681777817788177981780817818178281783817848178581786817878178881789817908179181792817938179481795817968179781798817998180081801818028180381804818058180681807818088180981810818118181281813818148181581816818178181881819818208182181822818238182481825818268182781828818298183081831818328183381834818358183681837818388183981840818418184281843818448184581846818478184881849818508185181852818538185481855818568185781858818598186081861818628186381864818658186681867818688186981870818718187281873818748187581876818778187881879818808188181882818838188481885818868188781888818898189081891818928189381894818958189681897818988189981900819018190281903819048190581906819078190881909819108191181912819138191481915819168191781918819198192081921819228192381924819258192681927819288192981930819318193281933819348193581936819378193881939819408194181942819438194481945819468194781948819498195081951819528195381954819558195681957819588195981960819618196281963819648196581966819678196881969819708197181972819738197481975819768197781978819798198081981819828198381984819858198681987819888198981990819918199281993819948199581996819978199881999820008200182002820038200482005820068200782008820098201082011820128201382014820158201682017820188201982020820218202282023820248202582026820278202882029820308203182032820338203482035820368203782038820398204082041820428204382044820458204682047820488204982050820518205282053820548205582056820578205882059820608206182062820638206482065820668206782068820698207082071820728207382074820758207682077820788207982080820818208282083820848208582086820878208882089820908209182092820938209482095820968209782098820998210082101821028210382104821058210682107821088210982110821118211282113821148211582116821178211882119821208212182122821238212482125821268212782128821298213082131821328213382134821358213682137821388213982140821418214282143821448214582146821478214882149821508215182152821538215482155821568215782158821598216082161821628216382164821658216682167821688216982170821718217282173821748217582176821778217882179821808218182182821838218482185821868218782188821898219082191821928219382194821958219682197821988219982200822018220282203822048220582206822078220882209822108221182212822138221482215822168221782218822198222082221822228222382224822258222682227822288222982230822318223282233822348223582236822378223882239822408224182242822438224482245822468224782248822498225082251822528225382254822558225682257822588225982260822618226282263822648226582266822678226882269822708227182272822738227482275822768227782278822798228082281822828228382284822858228682287822888228982290822918229282293822948229582296822978229882299823008230182302823038230482305823068230782308823098231082311823128231382314823158231682317823188231982320823218232282323823248232582326823278232882329823308233182332823338233482335823368233782338823398234082341823428234382344823458234682347823488234982350823518235282353823548235582356823578235882359823608236182362823638236482365823668236782368823698237082371823728237382374823758237682377823788237982380823818238282383823848238582386823878238882389823908239182392823938239482395823968239782398823998240082401824028240382404824058240682407824088240982410824118241282413824148241582416824178241882419824208242182422824238242482425824268242782428824298243082431824328243382434824358243682437824388243982440824418244282443824448244582446824478244882449824508245182452824538245482455824568245782458824598246082461824628246382464824658246682467824688246982470824718247282473824748247582476824778247882479824808248182482824838248482485824868248782488824898249082491824928249382494824958249682497824988249982500825018250282503825048250582506825078250882509825108251182512825138251482515825168251782518825198252082521825228252382524825258252682527825288252982530825318253282533825348253582536825378253882539825408254182542825438254482545825468254782548825498255082551825528255382554825558255682557825588255982560825618256282563825648256582566825678256882569825708257182572825738257482575825768257782578825798258082581825828258382584825858258682587825888258982590825918259282593825948259582596825978259882599826008260182602826038260482605826068260782608826098261082611826128261382614826158261682617826188261982620826218262282623826248262582626826278262882629826308263182632826338263482635826368263782638826398264082641826428264382644826458264682647826488264982650826518265282653826548265582656826578265882659826608266182662826638266482665826668266782668826698267082671826728267382674826758267682677826788267982680826818268282683826848268582686826878268882689826908269182692826938269482695826968269782698826998270082701827028270382704827058270682707827088270982710827118271282713827148271582716827178271882719827208272182722827238272482725827268272782728827298273082731827328273382734827358273682737827388273982740827418274282743827448274582746827478274882749827508275182752827538275482755827568275782758827598276082761827628276382764827658276682767827688276982770827718277282773827748277582776827778277882779827808278182782827838278482785827868278782788827898279082791827928279382794827958279682797827988279982800828018280282803828048280582806828078280882809828108281182812828138281482815828168281782818828198282082821828228282382824828258282682827828288282982830828318283282833828348283582836828378283882839828408284182842828438284482845828468284782848828498285082851828528285382854828558285682857828588285982860828618286282863828648286582866828678286882869828708287182872828738287482875828768287782878828798288082881828828288382884828858288682887828888288982890828918289282893828948289582896828978289882899829008290182902829038290482905829068290782908829098291082911829128291382914829158291682917829188291982920829218292282923829248292582926829278292882929829308293182932829338293482935829368293782938829398294082941829428294382944829458294682947829488294982950829518295282953829548295582956829578295882959829608296182962829638296482965829668296782968829698297082971829728297382974829758297682977829788297982980829818298282983829848298582986829878298882989829908299182992829938299482995829968299782998829998300083001830028300383004830058300683007830088300983010830118301283013830148301583016830178301883019830208302183022830238302483025830268302783028830298303083031830328303383034830358303683037830388303983040830418304283043830448304583046830478304883049830508305183052830538305483055830568305783058830598306083061830628306383064830658306683067830688306983070830718307283073830748307583076830778307883079830808308183082830838308483085830868308783088830898309083091830928309383094830958309683097830988309983100831018310283103831048310583106831078310883109831108311183112831138311483115831168311783118831198312083121831228312383124831258312683127831288312983130831318313283133831348313583136831378313883139831408314183142831438314483145831468314783148831498315083151831528315383154831558315683157831588315983160831618316283163831648316583166831678316883169831708317183172831738317483175831768317783178831798318083181831828318383184831858318683187831888318983190831918319283193831948319583196831978319883199832008320183202832038320483205832068320783208832098321083211832128321383214832158321683217832188321983220832218322283223832248322583226832278322883229832308323183232832338323483235832368323783238832398324083241832428324383244832458324683247832488324983250832518325283253832548325583256832578325883259832608326183262832638326483265832668326783268832698327083271832728327383274832758327683277832788327983280832818328283283832848328583286832878328883289832908329183292832938329483295832968329783298832998330083301833028330383304833058330683307833088330983310833118331283313833148331583316833178331883319833208332183322833238332483325833268332783328833298333083331833328333383334833358333683337833388333983340833418334283343833448334583346833478334883349833508335183352833538335483355833568335783358833598336083361833628336383364833658336683367833688336983370833718337283373833748337583376833778337883379833808338183382833838338483385833868338783388833898339083391833928339383394833958339683397833988339983400834018340283403834048340583406834078340883409834108341183412834138341483415834168341783418834198342083421834228342383424834258342683427834288342983430834318343283433834348343583436834378343883439834408344183442834438344483445834468344783448834498345083451834528345383454834558345683457834588345983460834618346283463834648346583466834678346883469834708347183472834738347483475834768347783478834798348083481834828348383484834858348683487834888348983490834918349283493834948349583496834978349883499835008350183502835038350483505835068350783508835098351083511835128351383514835158351683517835188351983520835218352283523835248352583526835278352883529835308353183532835338353483535835368353783538835398354083541835428354383544835458354683547835488354983550835518355283553835548355583556835578355883559835608356183562835638356483565835668356783568835698357083571835728357383574835758357683577835788357983580835818358283583835848358583586835878358883589835908359183592835938359483595835968359783598835998360083601836028360383604836058360683607836088360983610836118361283613836148361583616836178361883619836208362183622836238362483625836268362783628836298363083631836328363383634836358363683637836388363983640836418364283643836448364583646836478364883649836508365183652836538365483655836568365783658836598366083661836628366383664836658366683667836688366983670836718367283673836748367583676836778367883679836808368183682836838368483685836868368783688836898369083691836928369383694836958369683697836988369983700837018370283703837048370583706837078370883709837108371183712837138371483715837168371783718837198372083721837228372383724837258372683727837288372983730837318373283733837348373583736837378373883739837408374183742837438374483745837468374783748837498375083751837528375383754837558375683757837588375983760837618376283763837648376583766837678376883769837708377183772837738377483775837768377783778837798378083781837828378383784837858378683787837888378983790837918379283793837948379583796837978379883799838008380183802838038380483805838068380783808838098381083811838128381383814838158381683817838188381983820838218382283823838248382583826838278382883829838308383183832838338383483835838368383783838838398384083841838428384383844838458384683847838488384983850838518385283853838548385583856838578385883859838608386183862838638386483865838668386783868838698387083871838728387383874838758387683877838788387983880838818388283883838848388583886838878388883889838908389183892838938389483895838968389783898838998390083901839028390383904839058390683907839088390983910839118391283913839148391583916839178391883919839208392183922839238392483925839268392783928839298393083931839328393383934839358393683937839388393983940839418394283943839448394583946839478394883949839508395183952839538395483955839568395783958839598396083961839628396383964839658396683967839688396983970839718397283973839748397583976839778397883979839808398183982839838398483985839868398783988839898399083991839928399383994839958399683997839988399984000840018400284003840048400584006840078400884009840108401184012840138401484015840168401784018840198402084021840228402384024840258402684027840288402984030840318403284033840348403584036840378403884039840408404184042840438404484045840468404784048840498405084051840528405384054840558405684057840588405984060840618406284063840648406584066840678406884069840708407184072840738407484075840768407784078840798408084081840828408384084840858408684087840888408984090840918409284093840948409584096840978409884099841008410184102841038410484105841068410784108841098411084111841128411384114841158411684117841188411984120841218412284123841248412584126841278412884129841308413184132841338413484135841368413784138841398414084141841428414384144841458414684147841488414984150841518415284153841548415584156841578415884159841608416184162841638416484165841668416784168841698417084171841728417384174841758417684177841788417984180841818418284183841848418584186841878418884189841908419184192841938419484195841968419784198841998420084201842028420384204842058420684207842088420984210842118421284213842148421584216842178421884219842208422184222842238422484225842268422784228842298423084231842328423384234842358423684237842388423984240842418424284243842448424584246842478424884249842508425184252842538425484255842568425784258842598426084261842628426384264842658426684267842688426984270842718427284273842748427584276842778427884279842808428184282842838428484285842868428784288842898429084291842928429384294842958429684297842988429984300843018430284303843048430584306843078430884309843108431184312843138431484315843168431784318843198432084321843228432384324843258432684327843288432984330843318433284333843348433584336843378433884339843408434184342843438434484345843468434784348843498435084351843528435384354843558435684357843588435984360843618436284363843648436584366843678436884369843708437184372843738437484375843768437784378843798438084381843828438384384843858438684387843888438984390843918439284393843948439584396843978439884399844008440184402844038440484405844068440784408844098441084411844128441384414844158441684417844188441984420844218442284423844248442584426844278442884429844308443184432844338443484435844368443784438844398444084441844428444384444844458444684447844488444984450844518445284453844548445584456844578445884459844608446184462844638446484465844668446784468844698447084471844728447384474844758447684477844788447984480844818448284483844848448584486844878448884489844908449184492844938449484495844968449784498844998450084501845028450384504845058450684507845088450984510845118451284513845148451584516845178451884519845208452184522845238452484525845268452784528845298453084531845328453384534845358453684537845388453984540845418454284543845448454584546845478454884549845508455184552845538455484555845568455784558845598456084561845628456384564845658456684567845688456984570845718457284573845748457584576845778457884579845808458184582845838458484585845868458784588845898459084591845928459384594845958459684597845988459984600846018460284603846048460584606846078460884609846108461184612846138461484615846168461784618846198462084621846228462384624846258462684627846288462984630846318463284633846348463584636846378463884639846408464184642846438464484645846468464784648846498465084651846528465384654846558465684657846588465984660846618466284663846648466584666846678466884669846708467184672846738467484675846768467784678846798468084681846828468384684846858468684687846888468984690846918469284693846948469584696846978469884699847008470184702847038470484705847068470784708847098471084711847128471384714847158471684717847188471984720847218472284723847248472584726847278472884729847308473184732847338473484735847368473784738847398474084741847428474384744847458474684747847488474984750847518475284753847548475584756847578475884759847608476184762847638476484765847668476784768847698477084771847728477384774847758477684777847788477984780847818478284783847848478584786847878478884789847908479184792847938479484795847968479784798847998480084801848028480384804848058480684807848088480984810848118481284813848148481584816848178481884819848208482184822848238482484825848268482784828848298483084831848328483384834848358483684837848388483984840848418484284843848448484584846848478484884849848508485184852848538485484855848568485784858848598486084861848628486384864848658486684867848688486984870848718487284873848748487584876848778487884879848808488184882848838488484885848868488784888848898489084891848928489384894848958489684897848988489984900849018490284903849048490584906849078490884909849108491184912849138491484915849168491784918849198492084921849228492384924849258492684927849288492984930849318493284933849348493584936849378493884939849408494184942849438494484945849468494784948849498495084951849528495384954849558495684957849588495984960849618496284963849648496584966849678496884969849708497184972849738497484975849768497784978849798498084981849828498384984849858498684987849888498984990849918499284993849948499584996849978499884999850008500185002850038500485005850068500785008850098501085011850128501385014850158501685017850188501985020850218502285023850248502585026850278502885029850308503185032850338503485035850368503785038850398504085041850428504385044850458504685047850488504985050850518505285053850548505585056850578505885059850608506185062850638506485065850668506785068850698507085071850728507385074850758507685077850788507985080850818508285083850848508585086850878508885089850908509185092850938509485095850968509785098850998510085101851028510385104851058510685107851088510985110851118511285113851148511585116851178511885119851208512185122851238512485125851268512785128851298513085131851328513385134851358513685137851388513985140851418514285143851448514585146851478514885149851508515185152851538515485155851568515785158851598516085161851628516385164851658516685167851688516985170851718517285173851748517585176851778517885179851808518185182851838518485185851868518785188851898519085191851928519385194851958519685197851988519985200852018520285203852048520585206852078520885209852108521185212852138521485215852168521785218852198522085221852228522385224852258522685227852288522985230852318523285233852348523585236852378523885239852408524185242852438524485245852468524785248852498525085251852528525385254852558525685257852588525985260852618526285263852648526585266852678526885269852708527185272852738527485275852768527785278852798528085281852828528385284852858528685287852888528985290852918529285293852948529585296852978529885299853008530185302853038530485305853068530785308853098531085311853128531385314853158531685317853188531985320853218532285323853248532585326853278532885329853308533185332853338533485335853368533785338853398534085341853428534385344853458534685347853488534985350853518535285353853548535585356853578535885359853608536185362853638536485365853668536785368853698537085371853728537385374853758537685377853788537985380853818538285383853848538585386853878538885389853908539185392853938539485395853968539785398853998540085401854028540385404854058540685407854088540985410854118541285413854148541585416854178541885419854208542185422854238542485425854268542785428854298543085431854328543385434854358543685437854388543985440854418544285443854448544585446854478544885449854508545185452854538545485455854568545785458854598546085461854628546385464854658546685467854688546985470854718547285473854748547585476854778547885479854808548185482854838548485485854868548785488854898549085491854928549385494854958549685497854988549985500855018550285503855048550585506855078550885509855108551185512855138551485515855168551785518855198552085521855228552385524855258552685527855288552985530855318553285533855348553585536855378553885539855408554185542855438554485545855468554785548855498555085551855528555385554855558555685557855588555985560855618556285563855648556585566855678556885569855708557185572855738557485575855768557785578855798558085581855828558385584855858558685587855888558985590855918559285593855948559585596855978559885599856008560185602856038560485605856068560785608856098561085611856128561385614856158561685617856188561985620856218562285623856248562585626856278562885629856308563185632856338563485635856368563785638856398564085641856428564385644856458564685647856488564985650856518565285653856548565585656856578565885659856608566185662856638566485665856668566785668856698567085671856728567385674856758567685677856788567985680856818568285683856848568585686856878568885689856908569185692856938569485695856968569785698856998570085701857028570385704857058570685707857088570985710857118571285713857148571585716857178571885719857208572185722857238572485725857268572785728857298573085731857328573385734857358573685737857388573985740857418574285743857448574585746857478574885749857508575185752857538575485755857568575785758857598576085761857628576385764857658576685767857688576985770857718577285773857748577585776857778577885779857808578185782857838578485785857868578785788857898579085791857928579385794857958579685797857988579985800858018580285803858048580585806858078580885809858108581185812858138581485815858168581785818858198582085821858228582385824858258582685827858288582985830858318583285833858348583585836858378583885839858408584185842858438584485845858468584785848858498585085851858528585385854858558585685857858588585985860858618586285863858648586585866858678586885869858708587185872858738587485875858768587785878858798588085881858828588385884858858588685887858888588985890858918589285893858948589585896858978589885899859008590185902859038590485905859068590785908859098591085911859128591385914859158591685917859188591985920859218592285923859248592585926859278592885929859308593185932859338593485935859368593785938859398594085941859428594385944859458594685947859488594985950859518595285953859548595585956859578595885959859608596185962859638596485965859668596785968859698597085971859728597385974859758597685977859788597985980859818598285983859848598585986859878598885989859908599185992859938599485995859968599785998859998600086001860028600386004860058600686007860088600986010860118601286013860148601586016860178601886019860208602186022860238602486025860268602786028860298603086031860328603386034860358603686037860388603986040860418604286043860448604586046860478604886049860508605186052860538605486055860568605786058860598606086061860628606386064860658606686067860688606986070860718607286073860748607586076860778607886079860808608186082860838608486085860868608786088860898609086091860928609386094860958609686097860988609986100861018610286103861048610586106861078610886109861108611186112861138611486115861168611786118861198612086121861228612386124861258612686127861288612986130861318613286133861348613586136861378613886139861408614186142861438614486145861468614786148861498615086151861528615386154861558615686157861588615986160861618616286163861648616586166861678616886169861708617186172861738617486175861768617786178861798618086181861828618386184861858618686187861888618986190861918619286193861948619586196861978619886199862008620186202862038620486205862068620786208862098621086211862128621386214862158621686217862188621986220862218622286223862248622586226862278622886229862308623186232862338623486235862368623786238862398624086241862428624386244862458624686247862488624986250862518625286253862548625586256862578625886259862608626186262862638626486265862668626786268862698627086271862728627386274862758627686277862788627986280862818628286283862848628586286862878628886289862908629186292862938629486295862968629786298862998630086301863028630386304863058630686307863088630986310863118631286313863148631586316863178631886319863208632186322863238632486325863268632786328863298633086331863328633386334863358633686337863388633986340863418634286343863448634586346863478634886349863508635186352863538635486355863568635786358863598636086361863628636386364863658636686367863688636986370863718637286373863748637586376863778637886379863808638186382863838638486385863868638786388863898639086391863928639386394863958639686397863988639986400864018640286403864048640586406864078640886409864108641186412864138641486415864168641786418864198642086421864228642386424864258642686427864288642986430864318643286433864348643586436864378643886439864408644186442864438644486445864468644786448864498645086451864528645386454864558645686457864588645986460864618646286463864648646586466864678646886469864708647186472864738647486475864768647786478864798648086481864828648386484864858648686487864888648986490864918649286493864948649586496864978649886499865008650186502865038650486505865068650786508865098651086511865128651386514865158651686517865188651986520865218652286523865248652586526865278652886529865308653186532865338653486535865368653786538865398654086541865428654386544865458654686547865488654986550865518655286553865548655586556865578655886559865608656186562865638656486565865668656786568865698657086571865728657386574865758657686577865788657986580865818658286583865848658586586865878658886589865908659186592865938659486595865968659786598865998660086601866028660386604866058660686607866088660986610866118661286613866148661586616866178661886619866208662186622866238662486625866268662786628866298663086631866328663386634866358663686637866388663986640866418664286643866448664586646866478664886649866508665186652866538665486655866568665786658866598666086661866628666386664866658666686667866688666986670866718667286673866748667586676866778667886679866808668186682866838668486685866868668786688866898669086691866928669386694866958669686697866988669986700867018670286703867048670586706867078670886709867108671186712867138671486715867168671786718867198672086721867228672386724867258672686727867288672986730867318673286733867348673586736867378673886739867408674186742867438674486745867468674786748867498675086751867528675386754867558675686757867588675986760867618676286763867648676586766867678676886769867708677186772867738677486775867768677786778867798678086781867828678386784867858678686787867888678986790867918679286793867948679586796867978679886799868008680186802868038680486805868068680786808868098681086811868128681386814868158681686817868188681986820868218682286823868248682586826868278682886829868308683186832868338683486835868368683786838868398684086841868428684386844868458684686847868488684986850868518685286853868548685586856868578685886859868608686186862868638686486865868668686786868868698687086871868728687386874868758687686877868788687986880868818688286883868848688586886868878688886889868908689186892868938689486895868968689786898868998690086901869028690386904869058690686907869088690986910869118691286913869148691586916869178691886919869208692186922869238692486925869268692786928869298693086931869328693386934869358693686937869388693986940869418694286943869448694586946869478694886949869508695186952869538695486955869568695786958869598696086961869628696386964869658696686967869688696986970869718697286973869748697586976869778697886979869808698186982869838698486985869868698786988869898699086991869928699386994869958699686997869988699987000870018700287003870048700587006870078700887009870108701187012870138701487015870168701787018870198702087021870228702387024870258702687027870288702987030870318703287033870348703587036870378703887039870408704187042870438704487045870468704787048870498705087051870528705387054870558705687057870588705987060870618706287063870648706587066870678706887069870708707187072870738707487075870768707787078870798708087081870828708387084870858708687087870888708987090870918709287093870948709587096870978709887099871008710187102871038710487105871068710787108871098711087111871128711387114871158711687117871188711987120871218712287123871248712587126871278712887129871308713187132871338713487135871368713787138871398714087141871428714387144871458714687147871488714987150871518715287153871548715587156871578715887159871608716187162871638716487165871668716787168871698717087171871728717387174871758717687177871788717987180871818718287183871848718587186871878718887189871908719187192871938719487195871968719787198871998720087201872028720387204872058720687207872088720987210872118721287213872148721587216872178721887219872208722187222872238722487225872268722787228872298723087231872328723387234872358723687237872388723987240872418724287243872448724587246872478724887249872508725187252872538725487255872568725787258872598726087261872628726387264872658726687267872688726987270872718727287273872748727587276872778727887279872808728187282872838728487285872868728787288872898729087291872928729387294872958729687297872988729987300873018730287303873048730587306873078730887309873108731187312873138731487315873168731787318873198732087321873228732387324873258732687327873288732987330873318733287333873348733587336873378733887339873408734187342873438734487345873468734787348873498735087351873528735387354873558735687357873588735987360873618736287363873648736587366873678736887369873708737187372873738737487375873768737787378873798738087381873828738387384873858738687387873888738987390873918739287393873948739587396873978739887399874008740187402874038740487405874068740787408874098741087411874128741387414874158741687417874188741987420874218742287423874248742587426874278742887429874308743187432874338743487435874368743787438874398744087441874428744387444874458744687447874488744987450874518745287453874548745587456874578745887459874608746187462874638746487465874668746787468874698747087471874728747387474874758747687477874788747987480874818748287483874848748587486874878748887489874908749187492874938749487495874968749787498874998750087501875028750387504875058750687507875088750987510875118751287513875148751587516875178751887519875208752187522875238752487525875268752787528875298753087531875328753387534875358753687537875388753987540875418754287543875448754587546875478754887549875508755187552875538755487555875568755787558875598756087561875628756387564875658756687567875688756987570875718757287573875748757587576875778757887579875808758187582875838758487585875868758787588875898759087591875928759387594875958759687597875988759987600876018760287603876048760587606876078760887609876108761187612876138761487615876168761787618876198762087621876228762387624876258762687627876288762987630876318763287633876348763587636876378763887639876408764187642876438764487645876468764787648876498765087651876528765387654876558765687657876588765987660876618766287663876648766587666876678766887669876708767187672876738767487675876768767787678876798768087681876828768387684876858768687687876888768987690876918769287693876948769587696876978769887699877008770187702877038770487705877068770787708877098771087711877128771387714877158771687717877188771987720877218772287723877248772587726877278772887729877308773187732877338773487735877368773787738877398774087741877428774387744877458774687747877488774987750877518775287753877548775587756877578775887759877608776187762877638776487765877668776787768877698777087771877728777387774877758777687777877788777987780877818778287783877848778587786877878778887789877908779187792877938779487795877968779787798877998780087801878028780387804878058780687807878088780987810878118781287813878148781587816878178781887819878208782187822878238782487825878268782787828878298783087831878328783387834878358783687837878388783987840878418784287843878448784587846878478784887849878508785187852878538785487855878568785787858878598786087861878628786387864878658786687867878688786987870878718787287873878748787587876878778787887879878808788187882878838788487885878868788787888878898789087891878928789387894878958789687897878988789987900879018790287903879048790587906879078790887909879108791187912879138791487915879168791787918879198792087921879228792387924879258792687927879288792987930879318793287933879348793587936879378793887939879408794187942879438794487945879468794787948879498795087951879528795387954879558795687957879588795987960879618796287963879648796587966879678796887969879708797187972879738797487975879768797787978879798798087981879828798387984879858798687987879888798987990879918799287993879948799587996879978799887999880008800188002880038800488005880068800788008880098801088011880128801388014880158801688017880188801988020880218802288023880248802588026880278802888029880308803188032880338803488035880368803788038880398804088041880428804388044880458804688047880488804988050880518805288053880548805588056880578805888059880608806188062880638806488065880668806788068880698807088071880728807388074880758807688077880788807988080880818808288083880848808588086880878808888089880908809188092880938809488095880968809788098880998810088101881028810388104881058810688107881088810988110881118811288113881148811588116881178811888119881208812188122881238812488125881268812788128881298813088131881328813388134881358813688137881388813988140881418814288143881448814588146881478814888149881508815188152881538815488155881568815788158881598816088161881628816388164881658816688167881688816988170881718817288173881748817588176881778817888179881808818188182881838818488185881868818788188881898819088191881928819388194881958819688197881988819988200882018820288203882048820588206882078820888209882108821188212882138821488215882168821788218882198822088221882228822388224882258822688227882288822988230882318823288233882348823588236882378823888239882408824188242882438824488245882468824788248882498825088251882528825388254882558825688257882588825988260882618826288263882648826588266882678826888269882708827188272882738827488275882768827788278882798828088281882828828388284882858828688287882888828988290882918829288293882948829588296882978829888299883008830188302883038830488305883068830788308883098831088311883128831388314883158831688317883188831988320883218832288323883248832588326883278832888329883308833188332883338833488335883368833788338883398834088341883428834388344883458834688347883488834988350883518835288353883548835588356883578835888359883608836188362883638836488365883668836788368883698837088371883728837388374883758837688377883788837988380883818838288383883848838588386883878838888389883908839188392883938839488395883968839788398883998840088401884028840388404884058840688407884088840988410884118841288413884148841588416884178841888419884208842188422884238842488425884268842788428884298843088431884328843388434884358843688437884388843988440884418844288443884448844588446884478844888449884508845188452884538845488455884568845788458884598846088461884628846388464884658846688467884688846988470884718847288473884748847588476884778847888479884808848188482884838848488485884868848788488884898849088491884928849388494884958849688497884988849988500885018850288503885048850588506885078850888509885108851188512885138851488515885168851788518885198852088521885228852388524885258852688527885288852988530885318853288533885348853588536885378853888539885408854188542885438854488545885468854788548885498855088551885528855388554885558855688557885588855988560885618856288563885648856588566885678856888569885708857188572885738857488575885768857788578885798858088581885828858388584885858858688587885888858988590885918859288593885948859588596885978859888599886008860188602886038860488605886068860788608886098861088611886128861388614886158861688617886188861988620886218862288623886248862588626886278862888629886308863188632886338863488635886368863788638886398864088641886428864388644886458864688647886488864988650886518865288653886548865588656886578865888659886608866188662886638866488665886668866788668886698867088671886728867388674886758867688677886788867988680886818868288683886848868588686886878868888689886908869188692886938869488695886968869788698886998870088701887028870388704887058870688707887088870988710887118871288713887148871588716887178871888719887208872188722887238872488725887268872788728887298873088731887328873388734887358873688737887388873988740887418874288743887448874588746887478874888749887508875188752887538875488755887568875788758887598876088761887628876388764887658876688767887688876988770887718877288773887748877588776887778877888779887808878188782887838878488785887868878788788887898879088791887928879388794887958879688797887988879988800888018880288803888048880588806888078880888809888108881188812888138881488815888168881788818888198882088821888228882388824888258882688827888288882988830888318883288833888348883588836888378883888839888408884188842888438884488845888468884788848888498885088851888528885388854888558885688857888588885988860888618886288863888648886588866888678886888869888708887188872888738887488875888768887788878888798888088881888828888388884888858888688887888888888988890888918889288893888948889588896888978889888899889008890188902889038890488905889068890788908889098891088911889128891388914889158891688917889188891988920889218892288923889248892588926889278892888929889308893188932889338893488935889368893788938889398894088941889428894388944889458894688947889488894988950889518895288953889548895588956889578895888959889608896188962889638896488965889668896788968889698897088971889728897388974889758897688977889788897988980889818898288983889848898588986889878898888989889908899188992889938899488995889968899788998889998900089001890028900389004890058900689007890088900989010890118901289013890148901589016890178901889019890208902189022890238902489025890268902789028890298903089031890328903389034890358903689037890388903989040890418904289043890448904589046890478904889049890508905189052890538905489055890568905789058890598906089061890628906389064890658906689067890688906989070890718907289073890748907589076890778907889079890808908189082890838908489085890868908789088890898909089091890928909389094890958909689097890988909989100891018910289103891048910589106891078910889109891108911189112891138911489115891168911789118891198912089121891228912389124891258912689127891288912989130891318913289133891348913589136891378913889139891408914189142891438914489145891468914789148891498915089151891528915389154891558915689157891588915989160891618916289163891648916589166891678916889169891708917189172891738917489175891768917789178891798918089181891828918389184891858918689187891888918989190891918919289193891948919589196891978919889199892008920189202892038920489205892068920789208892098921089211892128921389214892158921689217892188921989220892218922289223892248922589226892278922889229892308923189232892338923489235892368923789238892398924089241892428924389244892458924689247892488924989250892518925289253892548925589256892578925889259892608926189262892638926489265892668926789268892698927089271892728927389274892758927689277892788927989280892818928289283892848928589286892878928889289892908929189292892938929489295892968929789298892998930089301893028930389304893058930689307893088930989310893118931289313893148931589316893178931889319893208932189322893238932489325893268932789328893298933089331893328933389334893358933689337893388933989340893418934289343893448934589346893478934889349893508935189352893538935489355893568935789358893598936089361893628936389364893658936689367893688936989370893718937289373893748937589376893778937889379893808938189382893838938489385893868938789388893898939089391893928939389394893958939689397893988939989400894018940289403894048940589406894078940889409894108941189412894138941489415894168941789418894198942089421894228942389424894258942689427894288942989430894318943289433894348943589436894378943889439894408944189442894438944489445894468944789448894498945089451894528945389454894558945689457894588945989460894618946289463894648946589466894678946889469894708947189472894738947489475894768947789478894798948089481894828948389484894858948689487894888948989490894918949289493894948949589496894978949889499895008950189502895038950489505895068950789508895098951089511895128951389514895158951689517895188951989520895218952289523895248952589526895278952889529895308953189532895338953489535895368953789538895398954089541895428954389544895458954689547895488954989550895518955289553895548955589556895578955889559895608956189562895638956489565895668956789568895698957089571895728957389574895758957689577895788957989580895818958289583895848958589586895878958889589895908959189592895938959489595895968959789598895998960089601896028960389604896058960689607896088960989610896118961289613896148961589616896178961889619896208962189622896238962489625896268962789628896298963089631896328963389634896358963689637896388963989640896418964289643896448964589646896478964889649896508965189652896538965489655896568965789658896598966089661896628966389664896658966689667896688966989670896718967289673896748967589676896778967889679896808968189682896838968489685896868968789688896898969089691896928969389694896958969689697896988969989700897018970289703897048970589706897078970889709897108971189712897138971489715897168971789718897198972089721897228972389724897258972689727897288972989730897318973289733897348973589736897378973889739897408974189742897438974489745897468974789748897498975089751897528975389754897558975689757897588975989760897618976289763897648976589766897678976889769897708977189772897738977489775897768977789778897798978089781897828978389784897858978689787897888978989790897918979289793897948979589796897978979889799898008980189802898038980489805898068980789808898098981089811898128981389814898158981689817898188981989820898218982289823898248982589826898278982889829898308983189832898338983489835898368983789838898398984089841898428984389844898458984689847898488984989850898518985289853898548985589856898578985889859898608986189862898638986489865898668986789868898698987089871898728987389874898758987689877898788987989880898818988289883898848988589886898878988889889898908989189892898938989489895898968989789898898998990089901899028990389904899058990689907899088990989910899118991289913899148991589916899178991889919899208992189922899238992489925899268992789928899298993089931899328993389934899358993689937899388993989940899418994289943899448994589946899478994889949899508995189952899538995489955899568995789958899598996089961899628996389964899658996689967899688996989970899718997289973899748997589976899778997889979899808998189982899838998489985899868998789988899898999089991899928999389994899958999689997899988999990000900019000290003900049000590006900079000890009900109001190012900139001490015900169001790018900199002090021900229002390024900259002690027900289002990030900319003290033900349003590036900379003890039900409004190042900439004490045900469004790048900499005090051900529005390054900559005690057900589005990060900619006290063900649006590066900679006890069900709007190072900739007490075900769007790078900799008090081900829008390084900859008690087900889008990090900919009290093900949009590096900979009890099901009010190102901039010490105901069010790108901099011090111901129011390114901159011690117901189011990120901219012290123901249012590126901279012890129901309013190132901339013490135901369013790138901399014090141901429014390144901459014690147901489014990150901519015290153901549015590156901579015890159901609016190162901639016490165901669016790168901699017090171901729017390174901759017690177901789017990180901819018290183901849018590186901879018890189901909019190192901939019490195901969019790198901999020090201902029020390204902059020690207902089020990210902119021290213902149021590216902179021890219902209022190222902239022490225902269022790228902299023090231902329023390234902359023690237902389023990240902419024290243902449024590246902479024890249902509025190252902539025490255902569025790258902599026090261902629026390264902659026690267902689026990270902719027290273902749027590276902779027890279902809028190282902839028490285902869028790288902899029090291902929029390294902959029690297902989029990300903019030290303903049030590306903079030890309903109031190312903139031490315903169031790318903199032090321903229032390324903259032690327903289032990330903319033290333903349033590336903379033890339903409034190342903439034490345903469034790348903499035090351903529035390354903559035690357903589035990360903619036290363903649036590366903679036890369903709037190372903739037490375903769037790378903799038090381903829038390384903859038690387903889038990390903919039290393903949039590396903979039890399904009040190402904039040490405904069040790408904099041090411904129041390414904159041690417904189041990420904219042290423904249042590426904279042890429904309043190432904339043490435904369043790438904399044090441904429044390444904459044690447904489044990450904519045290453904549045590456904579045890459904609046190462904639046490465904669046790468904699047090471904729047390474904759047690477904789047990480904819048290483904849048590486904879048890489904909049190492904939049490495904969049790498904999050090501905029050390504905059050690507905089050990510905119051290513905149051590516905179051890519905209052190522905239052490525905269052790528905299053090531905329053390534905359053690537905389053990540905419054290543905449054590546905479054890549905509055190552905539055490555905569055790558905599056090561905629056390564905659056690567905689056990570905719057290573905749057590576905779057890579905809058190582905839058490585905869058790588905899059090591905929059390594905959059690597905989059990600906019060290603906049060590606906079060890609906109061190612906139061490615906169061790618906199062090621906229062390624906259062690627906289062990630906319063290633906349063590636906379063890639906409064190642906439064490645906469064790648906499065090651906529065390654906559065690657906589065990660906619066290663906649066590666906679066890669906709067190672906739067490675906769067790678906799068090681906829068390684906859068690687906889068990690906919069290693906949069590696906979069890699907009070190702907039070490705907069070790708907099071090711907129071390714907159071690717907189071990720907219072290723907249072590726907279072890729907309073190732907339073490735907369073790738907399074090741907429074390744907459074690747907489074990750907519075290753907549075590756907579075890759907609076190762907639076490765907669076790768907699077090771907729077390774907759077690777907789077990780907819078290783907849078590786907879078890789907909079190792907939079490795907969079790798907999080090801908029080390804908059080690807908089080990810908119081290813908149081590816908179081890819908209082190822908239082490825908269082790828908299083090831908329083390834908359083690837908389083990840908419084290843908449084590846908479084890849908509085190852908539085490855908569085790858908599086090861908629086390864908659086690867908689086990870908719087290873908749087590876908779087890879908809088190882908839088490885908869088790888908899089090891908929089390894908959089690897908989089990900909019090290903909049090590906909079090890909909109091190912909139091490915909169091790918909199092090921909229092390924909259092690927909289092990930909319093290933909349093590936909379093890939909409094190942909439094490945909469094790948909499095090951909529095390954909559095690957909589095990960909619096290963909649096590966909679096890969909709097190972909739097490975909769097790978909799098090981909829098390984909859098690987909889098990990909919099290993909949099590996909979099890999910009100191002910039100491005910069100791008910099101091011910129101391014910159101691017910189101991020910219102291023910249102591026910279102891029910309103191032910339103491035910369103791038910399104091041910429104391044910459104691047910489104991050910519105291053910549105591056910579105891059910609106191062910639106491065910669106791068910699107091071910729107391074910759107691077910789107991080910819108291083910849108591086910879108891089910909109191092910939109491095910969109791098910999110091101911029110391104911059110691107911089110991110911119111291113911149111591116911179111891119911209112191122911239112491125911269112791128911299113091131911329113391134911359113691137911389113991140911419114291143911449114591146911479114891149911509115191152911539115491155911569115791158911599116091161911629116391164911659116691167911689116991170911719117291173911749117591176911779117891179911809118191182911839118491185911869118791188911899119091191911929119391194911959119691197911989119991200912019120291203912049120591206912079120891209912109121191212912139121491215912169121791218912199122091221912229122391224912259122691227912289122991230912319123291233912349123591236912379123891239912409124191242912439124491245912469124791248912499125091251912529125391254912559125691257912589125991260912619126291263912649126591266912679126891269912709127191272912739127491275912769127791278912799128091281912829128391284912859128691287912889128991290912919129291293912949129591296912979129891299913009130191302913039130491305913069130791308913099131091311913129131391314913159131691317913189131991320913219132291323913249132591326913279132891329913309133191332913339133491335913369133791338913399134091341913429134391344913459134691347913489134991350913519135291353913549135591356913579135891359913609136191362913639136491365913669136791368913699137091371913729137391374913759137691377913789137991380913819138291383913849138591386913879138891389913909139191392913939139491395913969139791398913999140091401914029140391404914059140691407914089140991410914119141291413914149141591416914179141891419914209142191422914239142491425914269142791428914299143091431914329143391434914359143691437914389143991440914419144291443914449144591446914479144891449914509145191452914539145491455914569145791458914599146091461914629146391464914659146691467914689146991470914719147291473914749147591476914779147891479914809148191482914839148491485914869148791488914899149091491914929149391494914959149691497914989149991500915019150291503915049150591506915079150891509915109151191512915139151491515915169151791518915199152091521915229152391524915259152691527915289152991530915319153291533915349153591536915379153891539915409154191542915439154491545915469154791548915499155091551915529155391554915559155691557915589155991560915619156291563915649156591566915679156891569915709157191572915739157491575915769157791578915799158091581915829158391584915859158691587915889158991590915919159291593915949159591596915979159891599916009160191602916039160491605916069160791608916099161091611916129161391614916159161691617916189161991620916219162291623916249162591626916279162891629916309163191632916339163491635916369163791638916399164091641916429164391644916459164691647916489164991650916519165291653916549165591656916579165891659916609166191662916639166491665916669166791668916699167091671916729167391674916759167691677916789167991680916819168291683916849168591686916879168891689916909169191692916939169491695916969169791698916999170091701917029170391704917059170691707917089170991710917119171291713917149171591716917179171891719917209172191722917239172491725917269172791728917299173091731917329173391734917359173691737917389173991740917419174291743917449174591746917479174891749917509175191752917539175491755917569175791758917599176091761917629176391764917659176691767917689176991770917719177291773917749177591776917779177891779917809178191782917839178491785917869178791788917899179091791917929179391794917959179691797917989179991800918019180291803918049180591806918079180891809918109181191812918139181491815918169181791818918199182091821918229182391824918259182691827918289182991830918319183291833918349183591836918379183891839918409184191842918439184491845918469184791848918499185091851918529185391854918559185691857918589185991860918619186291863918649186591866918679186891869918709187191872918739187491875918769187791878918799188091881918829188391884918859188691887918889188991890918919189291893918949189591896918979189891899919009190191902919039190491905919069190791908919099191091911919129191391914919159191691917919189191991920919219192291923919249192591926919279192891929919309193191932919339193491935919369193791938919399194091941919429194391944919459194691947919489194991950919519195291953919549195591956919579195891959919609196191962919639196491965919669196791968919699197091971919729197391974919759197691977919789197991980919819198291983919849198591986919879198891989919909199191992919939199491995919969199791998919999200092001920029200392004920059200692007920089200992010920119201292013920149201592016920179201892019920209202192022920239202492025920269202792028920299203092031920329203392034920359203692037920389203992040920419204292043920449204592046920479204892049920509205192052920539205492055920569205792058920599206092061920629206392064920659206692067920689206992070920719207292073920749207592076920779207892079920809208192082920839208492085920869208792088920899209092091920929209392094920959209692097920989209992100921019210292103921049210592106921079210892109921109211192112921139211492115921169211792118921199212092121921229212392124921259212692127921289212992130921319213292133921349213592136921379213892139921409214192142921439214492145921469214792148921499215092151921529215392154921559215692157921589215992160921619216292163921649216592166921679216892169921709217192172921739217492175921769217792178921799218092181921829218392184921859218692187921889218992190921919219292193921949219592196921979219892199922009220192202922039220492205922069220792208922099221092211922129221392214922159221692217922189221992220922219222292223922249222592226922279222892229922309223192232922339223492235922369223792238922399224092241922429224392244922459224692247922489224992250922519225292253922549225592256922579225892259922609226192262922639226492265922669226792268922699227092271922729227392274922759227692277922789227992280922819228292283922849228592286922879228892289922909229192292922939229492295922969229792298922999230092301923029230392304923059230692307923089230992310923119231292313923149231592316923179231892319923209232192322923239232492325923269232792328923299233092331923329233392334923359233692337923389233992340923419234292343923449234592346923479234892349923509235192352923539235492355923569235792358923599236092361923629236392364923659236692367923689236992370923719237292373923749237592376923779237892379923809238192382923839238492385923869238792388923899239092391923929239392394923959239692397923989239992400924019240292403924049240592406924079240892409924109241192412924139241492415924169241792418924199242092421924229242392424924259242692427924289242992430924319243292433924349243592436924379243892439924409244192442924439244492445924469244792448924499245092451924529245392454924559245692457924589245992460924619246292463924649246592466924679246892469924709247192472924739247492475924769247792478924799248092481924829248392484924859248692487924889248992490924919249292493924949249592496924979249892499925009250192502925039250492505925069250792508925099251092511925129251392514925159251692517925189251992520925219252292523925249252592526925279252892529925309253192532925339253492535925369253792538925399254092541925429254392544925459254692547925489254992550925519255292553925549255592556925579255892559925609256192562925639256492565925669256792568925699257092571925729257392574925759257692577925789257992580925819258292583925849258592586925879258892589925909259192592925939259492595925969259792598925999260092601926029260392604926059260692607926089260992610926119261292613926149261592616926179261892619926209262192622926239262492625926269262792628926299263092631926329263392634926359263692637926389263992640926419264292643926449264592646926479264892649926509265192652926539265492655926569265792658926599266092661926629266392664926659266692667926689266992670926719267292673926749267592676926779267892679926809268192682926839268492685926869268792688926899269092691926929269392694926959269692697926989269992700927019270292703927049270592706927079270892709927109271192712927139271492715927169271792718927199272092721927229272392724927259272692727927289272992730927319273292733927349273592736927379273892739927409274192742927439274492745927469274792748927499275092751927529275392754927559275692757927589275992760927619276292763927649276592766927679276892769927709277192772927739277492775927769277792778927799278092781927829278392784927859278692787927889278992790927919279292793927949279592796927979279892799928009280192802928039280492805928069280792808928099281092811928129281392814928159281692817928189281992820928219282292823928249282592826928279282892829928309283192832928339283492835928369283792838928399284092841928429284392844928459284692847928489284992850928519285292853928549285592856928579285892859928609286192862928639286492865928669286792868928699287092871928729287392874928759287692877928789287992880928819288292883928849288592886928879288892889928909289192892928939289492895928969289792898928999290092901929029290392904929059290692907929089290992910929119291292913929149291592916929179291892919929209292192922929239292492925929269292792928929299293092931929329293392934929359293692937929389293992940929419294292943929449294592946929479294892949929509295192952929539295492955929569295792958929599296092961929629296392964929659296692967929689296992970929719297292973929749297592976929779297892979929809298192982929839298492985929869298792988929899299092991929929299392994929959299692997929989299993000930019300293003930049300593006930079300893009930109301193012930139301493015930169301793018930199302093021930229302393024930259302693027930289302993030930319303293033930349303593036930379303893039930409304193042930439304493045930469304793048930499305093051930529305393054930559305693057930589305993060930619306293063930649306593066930679306893069930709307193072930739307493075930769307793078930799308093081930829308393084930859308693087930889308993090930919309293093930949309593096930979309893099931009310193102931039310493105931069310793108931099311093111931129311393114931159311693117931189311993120931219312293123931249312593126931279312893129931309313193132931339313493135931369313793138931399314093141931429314393144931459314693147931489314993150931519315293153931549315593156931579315893159931609316193162931639316493165931669316793168931699317093171931729317393174931759317693177931789317993180931819318293183931849318593186931879318893189931909319193192931939319493195931969319793198931999320093201932029320393204932059320693207932089320993210932119321293213932149321593216932179321893219932209322193222932239322493225932269322793228932299323093231932329323393234932359323693237932389323993240932419324293243932449324593246932479324893249932509325193252932539325493255932569325793258932599326093261932629326393264932659326693267932689326993270932719327293273932749327593276932779327893279932809328193282932839328493285932869328793288932899329093291932929329393294932959329693297932989329993300933019330293303933049330593306933079330893309933109331193312933139331493315933169331793318933199332093321933229332393324933259332693327933289332993330933319333293333933349333593336933379333893339933409334193342933439334493345933469334793348933499335093351933529335393354933559335693357933589335993360933619336293363933649336593366933679336893369933709337193372933739337493375933769337793378933799338093381933829338393384933859338693387933889338993390933919339293393933949339593396933979339893399934009340193402934039340493405934069340793408934099341093411934129341393414934159341693417934189341993420934219342293423934249342593426934279342893429934309343193432934339343493435934369343793438934399344093441934429344393444934459344693447934489344993450934519345293453934549345593456934579345893459934609346193462934639346493465934669346793468934699347093471934729347393474934759347693477934789347993480934819348293483934849348593486934879348893489934909349193492934939349493495934969349793498934999350093501935029350393504935059350693507935089350993510935119351293513935149351593516935179351893519935209352193522935239352493525935269352793528935299353093531935329353393534935359353693537935389353993540935419354293543935449354593546935479354893549935509355193552935539355493555935569355793558935599356093561935629356393564935659356693567935689356993570935719357293573935749357593576935779357893579935809358193582935839358493585935869358793588935899359093591935929359393594935959359693597935989359993600936019360293603936049360593606936079360893609936109361193612936139361493615936169361793618936199362093621936229362393624936259362693627936289362993630936319363293633936349363593636936379363893639936409364193642936439364493645936469364793648936499365093651936529365393654936559365693657936589365993660936619366293663936649366593666936679366893669936709367193672936739367493675936769367793678936799368093681936829368393684936859368693687936889368993690936919369293693936949369593696936979369893699937009370193702937039370493705937069370793708937099371093711937129371393714937159371693717937189371993720937219372293723937249372593726937279372893729937309373193732937339373493735937369373793738937399374093741937429374393744937459374693747937489374993750937519375293753937549375593756937579375893759937609376193762937639376493765937669376793768937699377093771937729377393774937759377693777937789377993780937819378293783937849378593786937879378893789937909379193792937939379493795937969379793798937999380093801938029380393804938059380693807938089380993810938119381293813938149381593816938179381893819938209382193822938239382493825938269382793828938299383093831938329383393834938359383693837938389383993840938419384293843938449384593846938479384893849938509385193852938539385493855938569385793858938599386093861938629386393864938659386693867938689386993870938719387293873938749387593876938779387893879938809388193882938839388493885938869388793888938899389093891938929389393894938959389693897938989389993900939019390293903939049390593906939079390893909939109391193912939139391493915939169391793918939199392093921939229392393924939259392693927939289392993930939319393293933939349393593936939379393893939939409394193942939439394493945939469394793948939499395093951939529395393954939559395693957939589395993960939619396293963939649396593966939679396893969939709397193972939739397493975939769397793978939799398093981939829398393984939859398693987939889398993990939919399293993939949399593996939979399893999940009400194002940039400494005940069400794008940099401094011940129401394014940159401694017940189401994020940219402294023940249402594026940279402894029940309403194032940339403494035940369403794038940399404094041940429404394044940459404694047940489404994050940519405294053940549405594056940579405894059940609406194062940639406494065940669406794068940699407094071940729407394074940759407694077940789407994080940819408294083940849408594086940879408894089940909409194092940939409494095940969409794098940999410094101941029410394104941059410694107941089410994110941119411294113941149411594116941179411894119941209412194122941239412494125941269412794128941299413094131941329413394134941359413694137941389413994140941419414294143941449414594146941479414894149941509415194152941539415494155941569415794158941599416094161941629416394164941659416694167941689416994170941719417294173941749417594176941779417894179941809418194182941839418494185941869418794188941899419094191941929419394194941959419694197941989419994200942019420294203942049420594206942079420894209942109421194212942139421494215942169421794218942199422094221942229422394224942259422694227942289422994230942319423294233942349423594236942379423894239942409424194242942439424494245942469424794248942499425094251942529425394254942559425694257942589425994260942619426294263942649426594266942679426894269942709427194272942739427494275942769427794278942799428094281942829428394284942859428694287942889428994290942919429294293942949429594296942979429894299943009430194302943039430494305943069430794308943099431094311943129431394314943159431694317943189431994320943219432294323943249432594326943279432894329943309433194332943339433494335943369433794338943399434094341943429434394344943459434694347943489434994350943519435294353943549435594356943579435894359943609436194362943639436494365943669436794368943699437094371943729437394374943759437694377943789437994380943819438294383943849438594386943879438894389943909439194392943939439494395943969439794398943999440094401944029440394404944059440694407944089440994410944119441294413944149441594416944179441894419944209442194422944239442494425944269442794428944299443094431944329443394434944359443694437944389443994440944419444294443944449444594446944479444894449944509445194452944539445494455944569445794458944599446094461944629446394464944659446694467944689446994470944719447294473944749447594476944779447894479944809448194482944839448494485944869448794488944899449094491944929449394494944959449694497944989449994500945019450294503945049450594506945079450894509945109451194512945139451494515945169451794518945199452094521945229452394524945259452694527945289452994530945319453294533945349453594536945379453894539945409454194542945439454494545945469454794548945499455094551945529455394554945559455694557945589455994560945619456294563945649456594566945679456894569945709457194572945739457494575945769457794578945799458094581945829458394584945859458694587945889458994590945919459294593945949459594596945979459894599946009460194602946039460494605946069460794608946099461094611946129461394614946159461694617946189461994620946219462294623946249462594626946279462894629946309463194632946339463494635946369463794638946399464094641946429464394644946459464694647946489464994650946519465294653946549465594656946579465894659946609466194662946639466494665946669466794668946699467094671946729467394674946759467694677946789467994680946819468294683946849468594686946879468894689946909469194692946939469494695946969469794698946999470094701947029470394704947059470694707947089470994710947119471294713947149471594716947179471894719947209472194722947239472494725947269472794728947299473094731947329473394734947359473694737947389473994740947419474294743947449474594746947479474894749947509475194752947539475494755947569475794758947599476094761947629476394764947659476694767947689476994770947719477294773947749477594776947779477894779947809478194782947839478494785947869478794788947899479094791947929479394794947959479694797947989479994800948019480294803948049480594806948079480894809948109481194812948139481494815948169481794818948199482094821948229482394824948259482694827948289482994830948319483294833948349483594836948379483894839948409484194842948439484494845948469484794848948499485094851948529485394854948559485694857948589485994860948619486294863948649486594866948679486894869948709487194872948739487494875948769487794878948799488094881948829488394884948859488694887948889488994890948919489294893948949489594896948979489894899949009490194902949039490494905949069490794908949099491094911949129491394914949159491694917949189491994920949219492294923949249492594926949279492894929949309493194932949339493494935949369493794938949399494094941949429494394944949459494694947949489494994950949519495294953949549495594956949579495894959949609496194962949639496494965949669496794968949699497094971949729497394974949759497694977949789497994980949819498294983949849498594986949879498894989949909499194992949939499494995949969499794998949999500095001950029500395004950059500695007950089500995010950119501295013950149501595016950179501895019950209502195022950239502495025950269502795028950299503095031950329503395034950359503695037950389503995040950419504295043950449504595046950479504895049950509505195052950539505495055950569505795058950599506095061950629506395064950659506695067950689506995070950719507295073950749507595076950779507895079950809508195082950839508495085950869508795088950899509095091950929509395094950959509695097950989509995100951019510295103951049510595106951079510895109951109511195112951139511495115951169511795118951199512095121951229512395124951259512695127951289512995130951319513295133951349513595136951379513895139951409514195142951439514495145951469514795148951499515095151951529515395154951559515695157951589515995160951619516295163951649516595166951679516895169951709517195172951739517495175951769517795178951799518095181951829518395184951859518695187951889518995190951919519295193951949519595196951979519895199952009520195202952039520495205952069520795208952099521095211952129521395214952159521695217952189521995220952219522295223952249522595226952279522895229952309523195232952339523495235952369523795238952399524095241952429524395244952459524695247952489524995250952519525295253952549525595256952579525895259952609526195262952639526495265952669526795268952699527095271952729527395274952759527695277952789527995280952819528295283952849528595286952879528895289952909529195292952939529495295952969529795298952999530095301953029530395304953059530695307953089530995310953119531295313953149531595316953179531895319953209532195322953239532495325953269532795328953299533095331953329533395334953359533695337953389533995340953419534295343953449534595346953479534895349953509535195352953539535495355953569535795358953599536095361953629536395364953659536695367953689536995370953719537295373953749537595376953779537895379953809538195382953839538495385953869538795388953899539095391953929539395394953959539695397953989539995400954019540295403954049540595406954079540895409954109541195412954139541495415954169541795418954199542095421954229542395424954259542695427954289542995430954319543295433954349543595436954379543895439954409544195442954439544495445954469544795448954499545095451954529545395454954559545695457954589545995460954619546295463954649546595466954679546895469954709547195472954739547495475954769547795478954799548095481954829548395484954859548695487954889548995490954919549295493954949549595496954979549895499955009550195502955039550495505955069550795508955099551095511955129551395514955159551695517955189551995520955219552295523955249552595526955279552895529955309553195532955339553495535955369553795538955399554095541955429554395544955459554695547955489554995550955519555295553955549555595556955579555895559955609556195562955639556495565955669556795568955699557095571955729557395574955759557695577955789557995580955819558295583955849558595586955879558895589955909559195592955939559495595955969559795598955999560095601956029560395604956059560695607956089560995610956119561295613956149561595616956179561895619956209562195622956239562495625956269562795628956299563095631956329563395634956359563695637956389563995640956419564295643956449564595646956479564895649956509565195652956539565495655956569565795658956599566095661956629566395664956659566695667956689566995670956719567295673956749567595676956779567895679956809568195682956839568495685956869568795688956899569095691956929569395694956959569695697956989569995700957019570295703957049570595706957079570895709957109571195712957139571495715957169571795718957199572095721957229572395724957259572695727957289572995730957319573295733957349573595736957379573895739957409574195742957439574495745957469574795748957499575095751957529575395754957559575695757957589575995760957619576295763957649576595766957679576895769957709577195772957739577495775957769577795778957799578095781957829578395784957859578695787957889578995790957919579295793957949579595796957979579895799958009580195802958039580495805958069580795808958099581095811958129581395814958159581695817958189581995820958219582295823958249582595826958279582895829958309583195832958339583495835958369583795838958399584095841958429584395844958459584695847958489584995850958519585295853958549585595856958579585895859958609586195862958639586495865958669586795868958699587095871958729587395874958759587695877958789587995880958819588295883958849588595886958879588895889958909589195892958939589495895958969589795898958999590095901959029590395904959059590695907959089590995910959119591295913959149591595916959179591895919959209592195922959239592495925959269592795928959299593095931959329593395934959359593695937959389593995940959419594295943959449594595946959479594895949959509595195952959539595495955959569595795958959599596095961959629596395964959659596695967959689596995970959719597295973959749597595976959779597895979959809598195982959839598495985959869598795988959899599095991959929599395994959959599695997959989599996000960019600296003960049600596006960079600896009960109601196012960139601496015960169601796018960199602096021960229602396024960259602696027960289602996030960319603296033960349603596036960379603896039960409604196042960439604496045960469604796048960499605096051960529605396054960559605696057960589605996060960619606296063960649606596066960679606896069960709607196072960739607496075960769607796078960799608096081960829608396084960859608696087960889608996090960919609296093960949609596096960979609896099961009610196102961039610496105961069610796108961099611096111961129611396114961159611696117961189611996120961219612296123961249612596126961279612896129961309613196132961339613496135961369613796138961399614096141961429614396144961459614696147961489614996150961519615296153961549615596156961579615896159961609616196162961639616496165961669616796168961699617096171961729617396174961759617696177961789617996180961819618296183961849618596186961879618896189961909619196192961939619496195961969619796198961999620096201962029620396204962059620696207962089620996210962119621296213962149621596216962179621896219962209622196222962239622496225962269622796228962299623096231962329623396234962359623696237962389623996240962419624296243962449624596246962479624896249962509625196252962539625496255962569625796258962599626096261962629626396264962659626696267962689626996270962719627296273962749627596276962779627896279962809628196282962839628496285962869628796288962899629096291962929629396294962959629696297962989629996300963019630296303963049630596306963079630896309963109631196312963139631496315963169631796318963199632096321963229632396324963259632696327963289632996330963319633296333963349633596336963379633896339963409634196342963439634496345963469634796348963499635096351963529635396354963559635696357963589635996360963619636296363963649636596366963679636896369963709637196372963739637496375963769637796378963799638096381963829638396384963859638696387963889638996390963919639296393963949639596396963979639896399964009640196402964039640496405964069640796408964099641096411964129641396414964159641696417964189641996420964219642296423964249642596426964279642896429964309643196432964339643496435964369643796438964399644096441964429644396444964459644696447964489644996450964519645296453964549645596456964579645896459964609646196462964639646496465964669646796468964699647096471964729647396474964759647696477964789647996480964819648296483964849648596486964879648896489964909649196492964939649496495964969649796498964999650096501965029650396504965059650696507965089650996510965119651296513965149651596516965179651896519965209652196522965239652496525965269652796528965299653096531965329653396534965359653696537965389653996540965419654296543965449654596546965479654896549965509655196552965539655496555965569655796558965599656096561965629656396564965659656696567965689656996570965719657296573965749657596576965779657896579965809658196582965839658496585965869658796588965899659096591965929659396594965959659696597965989659996600966019660296603966049660596606966079660896609966109661196612966139661496615966169661796618966199662096621966229662396624966259662696627966289662996630966319663296633966349663596636966379663896639966409664196642966439664496645966469664796648966499665096651966529665396654966559665696657966589665996660966619666296663966649666596666966679666896669966709667196672966739667496675966769667796678966799668096681966829668396684966859668696687966889668996690966919669296693966949669596696966979669896699967009670196702967039670496705967069670796708967099671096711967129671396714967159671696717967189671996720967219672296723967249672596726967279672896729967309673196732967339673496735967369673796738967399674096741967429674396744967459674696747967489674996750967519675296753967549675596756967579675896759967609676196762967639676496765967669676796768967699677096771967729677396774967759677696777967789677996780967819678296783967849678596786967879678896789967909679196792967939679496795967969679796798967999680096801968029680396804968059680696807968089680996810968119681296813968149681596816968179681896819968209682196822968239682496825968269682796828968299683096831968329683396834968359683696837968389683996840968419684296843968449684596846968479684896849968509685196852968539685496855968569685796858968599686096861968629686396864968659686696867968689686996870968719687296873968749687596876968779687896879968809688196882968839688496885968869688796888968899689096891968929689396894968959689696897968989689996900969019690296903969049690596906969079690896909969109691196912969139691496915969169691796918969199692096921969229692396924969259692696927969289692996930969319693296933969349693596936969379693896939969409694196942969439694496945969469694796948969499695096951969529695396954969559695696957969589695996960969619696296963969649696596966969679696896969969709697196972969739697496975969769697796978969799698096981969829698396984969859698696987969889698996990969919699296993969949699596996969979699896999970009700197002970039700497005970069700797008970099701097011970129701397014970159701697017970189701997020970219702297023970249702597026970279702897029970309703197032970339703497035970369703797038970399704097041970429704397044970459704697047970489704997050970519705297053970549705597056970579705897059970609706197062970639706497065970669706797068970699707097071970729707397074970759707697077970789707997080970819708297083970849708597086970879708897089970909709197092970939709497095970969709797098970999710097101971029710397104971059710697107971089710997110971119711297113971149711597116971179711897119971209712197122971239712497125971269712797128971299713097131971329713397134971359713697137971389713997140971419714297143971449714597146971479714897149971509715197152971539715497155971569715797158971599716097161971629716397164971659716697167971689716997170971719717297173971749717597176971779717897179971809718197182971839718497185971869718797188971899719097191971929719397194971959719697197971989719997200972019720297203972049720597206972079720897209972109721197212972139721497215972169721797218972199722097221972229722397224972259722697227972289722997230972319723297233972349723597236972379723897239972409724197242972439724497245972469724797248972499725097251972529725397254972559725697257972589725997260972619726297263972649726597266972679726897269972709727197272972739727497275972769727797278972799728097281972829728397284972859728697287972889728997290972919729297293972949729597296972979729897299973009730197302973039730497305973069730797308973099731097311973129731397314973159731697317973189731997320973219732297323973249732597326973279732897329973309733197332973339733497335973369733797338973399734097341973429734397344973459734697347973489734997350973519735297353973549735597356973579735897359973609736197362973639736497365973669736797368973699737097371973729737397374973759737697377973789737997380973819738297383973849738597386973879738897389973909739197392973939739497395973969739797398973999740097401974029740397404974059740697407974089740997410974119741297413974149741597416974179741897419974209742197422974239742497425974269742797428974299743097431974329743397434974359743697437974389743997440974419744297443974449744597446974479744897449974509745197452974539745497455974569745797458974599746097461974629746397464974659746697467974689746997470974719747297473974749747597476974779747897479974809748197482974839748497485974869748797488974899749097491974929749397494974959749697497974989749997500975019750297503975049750597506975079750897509975109751197512975139751497515975169751797518975199752097521975229752397524975259752697527975289752997530975319753297533975349753597536975379753897539975409754197542975439754497545975469754797548975499755097551975529755397554975559755697557975589755997560975619756297563975649756597566975679756897569975709757197572975739757497575975769757797578975799758097581975829758397584975859758697587975889758997590975919759297593975949759597596975979759897599976009760197602976039760497605976069760797608976099761097611976129761397614976159761697617976189761997620976219762297623976249762597626976279762897629976309763197632976339763497635976369763797638976399764097641976429764397644976459764697647976489764997650976519765297653976549765597656976579765897659976609766197662976639766497665976669766797668976699767097671976729767397674976759767697677976789767997680976819768297683976849768597686976879768897689976909769197692976939769497695976969769797698976999770097701977029770397704977059770697707977089770997710977119771297713977149771597716977179771897719977209772197722977239772497725977269772797728977299773097731977329773397734977359773697737977389773997740977419774297743977449774597746977479774897749977509775197752977539775497755977569775797758977599776097761977629776397764977659776697767977689776997770977719777297773977749777597776977779777897779977809778197782977839778497785977869778797788977899779097791977929779397794977959779697797977989779997800978019780297803978049780597806978079780897809978109781197812978139781497815978169781797818978199782097821978229782397824978259782697827978289782997830978319783297833978349783597836978379783897839978409784197842978439784497845978469784797848978499785097851978529785397854978559785697857978589785997860978619786297863978649786597866978679786897869978709787197872978739787497875978769787797878978799788097881978829788397884978859788697887978889788997890978919789297893978949789597896978979789897899979009790197902979039790497905979069790797908979099791097911979129791397914979159791697917979189791997920979219792297923979249792597926979279792897929979309793197932979339793497935979369793797938979399794097941979429794397944979459794697947979489794997950979519795297953979549795597956979579795897959979609796197962979639796497965979669796797968979699797097971979729797397974979759797697977979789797997980979819798297983979849798597986979879798897989979909799197992979939799497995979969799797998979999800098001980029800398004980059800698007980089800998010980119801298013980149801598016980179801898019980209802198022980239802498025980269802798028980299803098031980329803398034980359803698037980389803998040980419804298043980449804598046980479804898049980509805198052980539805498055980569805798058980599806098061980629806398064980659806698067980689806998070980719807298073980749807598076980779807898079980809808198082980839808498085980869808798088980899809098091980929809398094980959809698097980989809998100981019810298103981049810598106981079810898109981109811198112981139811498115981169811798118981199812098121981229812398124981259812698127981289812998130981319813298133981349813598136981379813898139981409814198142981439814498145981469814798148981499815098151981529815398154981559815698157981589815998160981619816298163981649816598166981679816898169981709817198172981739817498175981769817798178981799818098181981829818398184981859818698187981889818998190981919819298193981949819598196981979819898199982009820198202982039820498205982069820798208982099821098211982129821398214982159821698217982189821998220982219822298223982249822598226982279822898229982309823198232982339823498235982369823798238982399824098241982429824398244982459824698247982489824998250982519825298253982549825598256982579825898259982609826198262982639826498265982669826798268982699827098271982729827398274982759827698277982789827998280982819828298283982849828598286982879828898289982909829198292982939829498295982969829798298982999830098301983029830398304983059830698307983089830998310983119831298313983149831598316983179831898319983209832198322983239832498325983269832798328983299833098331983329833398334983359833698337983389833998340983419834298343983449834598346983479834898349983509835198352983539835498355983569835798358983599836098361983629836398364983659836698367983689836998370983719837298373983749837598376983779837898379983809838198382983839838498385983869838798388983899839098391983929839398394983959839698397983989839998400984019840298403984049840598406984079840898409984109841198412984139841498415984169841798418984199842098421984229842398424984259842698427984289842998430984319843298433984349843598436984379843898439984409844198442984439844498445984469844798448984499845098451984529845398454984559845698457984589845998460984619846298463984649846598466984679846898469984709847198472984739847498475984769847798478984799848098481984829848398484984859848698487984889848998490984919849298493984949849598496984979849898499985009850198502985039850498505985069850798508985099851098511985129851398514985159851698517985189851998520985219852298523985249852598526985279852898529985309853198532985339853498535985369853798538985399854098541985429854398544985459854698547985489854998550985519855298553985549855598556985579855898559985609856198562985639856498565985669856798568985699857098571985729857398574985759857698577985789857998580985819858298583985849858598586985879858898589985909859198592985939859498595985969859798598985999860098601986029860398604986059860698607986089860998610986119861298613986149861598616986179861898619986209862198622986239862498625986269862798628986299863098631986329863398634986359863698637986389863998640986419864298643986449864598646986479864898649986509865198652986539865498655986569865798658986599866098661986629866398664986659866698667986689866998670986719867298673986749867598676986779867898679986809868198682986839868498685986869868798688986899869098691986929869398694986959869698697986989869998700987019870298703987049870598706987079870898709987109871198712987139871498715987169871798718987199872098721987229872398724987259872698727987289872998730987319873298733987349873598736987379873898739987409874198742987439874498745987469874798748987499875098751987529875398754987559875698757987589875998760987619876298763987649876598766987679876898769987709877198772987739877498775987769877798778987799878098781987829878398784987859878698787987889878998790987919879298793987949879598796987979879898799988009880198802988039880498805988069880798808988099881098811988129881398814988159881698817988189881998820988219882298823988249882598826988279882898829988309883198832988339883498835988369883798838988399884098841988429884398844988459884698847988489884998850988519885298853988549885598856988579885898859988609886198862988639886498865988669886798868988699887098871988729887398874988759887698877988789887998880988819888298883988849888598886988879888898889988909889198892988939889498895988969889798898988999890098901989029890398904989059890698907989089890998910989119891298913
  1. <?php
  2. error_reporting(1803);
  3. if (function_exists('mb_internal_encoding')) {
  4. mb_internal_encoding('ASCII');
  5. }
  6. if (!class_exists('PHP_Archive')) {/**
  7. * PHP_Archive Class (implements .phar)
  8. *
  9. * @package PHP_Archive
  10. * @category PHP
  11. */
  12. /**
  13. * PHP_Archive Class (implements .phar)
  14. *
  15. * PHAR files a singular archive from which an entire application can run.
  16. * To use it, simply package it using {@see PHP_Archive_Creator} and use phar://
  17. * URIs to your includes. i.e. require_once 'phar://config.php' will include config.php
  18. * from the root of the PHAR file.
  19. *
  20. * Gz code borrowed from the excellent File_Archive package by Vincent Lascaux.
  21. *
  22. * @copyright Copyright David Shafik and Synaptic Media 2004. All rights reserved.
  23. * @author Davey Shafik <davey@synapticmedia.net>
  24. * @author Greg Beaver <cellog@php.net>
  25. * @link http://www.synapticmedia.net Synaptic Media
  26. * @version Id$
  27. * @package PHP_Archive
  28. * @category PHP
  29. */
  30. class PHP_Archive
  31. {
  32. const GZ = 0x00001000;
  33. const BZ2 = 0x00002000;
  34. const SIG = 0x00010000;
  35. const SHA1 = 0x0002;
  36. const MD5 = 0x0001;
  37. const SHA256 = 0x0003;
  38. const SHA512 = 0x0004;
  39. const OPENSSL = 0x0010;
  40. /**
  41. * Whether this archive is compressed with zlib
  42. *
  43. * @var bool
  44. */
  45. private $_compressed;
  46. /**
  47. * @var string Real path to the .phar archive
  48. */
  49. private $_archiveName = null;
  50. /**
  51. * Current file name in the phar
  52. * @var string
  53. */
  54. protected $currentFilename = null;
  55. /**
  56. * Length of current file in the phar
  57. * @var string
  58. */
  59. protected $internalFileLength = null;
  60. /**
  61. * true if the current file is an empty directory
  62. * @var string
  63. */
  64. protected $isDir = false;
  65. /**
  66. * Current file statistics (size, creation date, etc.)
  67. * @var string
  68. */
  69. protected $currentStat = null;
  70. /**
  71. * @var resource|null Pointer to open .phar
  72. */
  73. protected $fp = null;
  74. /**
  75. * @var int Current Position of the pointer
  76. */
  77. protected $position = 0;
  78. /**
  79. * Map actual realpath of phars to meta-data about the phar
  80. *
  81. * Data is indexed by the alias that is used by internal files. In other
  82. * words, if a file is included via:
  83. * <code>
  84. * require_once 'phar://PEAR.phar/PEAR/Installer.php';
  85. * </code>
  86. * then the alias is "PEAR.phar"
  87. *
  88. * Information stored is a boolean indicating whether this .phar is compressed
  89. * with zlib, another for bzip2, phar-specific meta-data, and
  90. * the precise offset of internal files
  91. * within the .phar, used with the {@link $_manifest} to load actual file contents
  92. * @var array
  93. */
  94. private static $_pharMapping = array();
  95. /**
  96. * Map real file paths to alias used
  97. *
  98. * @var array
  99. */
  100. private static $_pharFiles = array();
  101. /**
  102. * File listing for the .phar
  103. *
  104. * The manifest is indexed per phar.
  105. *
  106. * Files within the .phar are indexed by their relative path within the
  107. * .phar. Each file has this information in its internal array
  108. *
  109. * - 0 = uncompressed file size
  110. * - 1 = timestamp of when file was added to phar
  111. * - 2 = offset of file within phar relative to internal file's start
  112. * - 3 = compressed file size (actual size in the phar)
  113. * @var array
  114. */
  115. private static $_manifest = array();
  116. /**
  117. * Absolute offset of internal files within the .phar, indexed by absolute
  118. * path to the .phar
  119. *
  120. * @var array
  121. */
  122. private static $_fileStart = array();
  123. /**
  124. * file name of the phar
  125. *
  126. * @var string
  127. */
  128. private $_basename;
  129. /**
  130. * Default MIME types used for the web front controller
  131. *
  132. * @var array
  133. */
  134. public static $defaultmimes = array(
  135. 'aif' => 'audio/x-aiff',
  136. 'aiff' => 'audio/x-aiff',
  137. 'arc' => 'application/octet-stream',
  138. 'arj' => 'application/octet-stream',
  139. 'art' => 'image/x-jg',
  140. 'asf' => 'video/x-ms-asf',
  141. 'asx' => 'video/x-ms-asf',
  142. 'avi' => 'video/avi',
  143. 'bin' => 'application/octet-stream',
  144. 'bm' => 'image/bmp',
  145. 'bmp' => 'image/bmp',
  146. 'bz2' => 'application/x-bzip2',
  147. 'css' => 'text/css',
  148. 'doc' => 'application/msword',
  149. 'dot' => 'application/msword',
  150. 'dv' => 'video/x-dv',
  151. 'dvi' => 'application/x-dvi',
  152. 'eps' => 'application/postscript',
  153. 'exe' => 'application/octet-stream',
  154. 'gif' => 'image/gif',
  155. 'gz' => 'application/x-gzip',
  156. 'gzip' => 'application/x-gzip',
  157. 'htm' => 'text/html',
  158. 'html' => 'text/html',
  159. 'ico' => 'image/x-icon',
  160. 'jpe' => 'image/jpeg',
  161. 'jpg' => 'image/jpeg',
  162. 'jpeg' => 'image/jpeg',
  163. 'js' => 'application/x-javascript',
  164. 'log' => 'text/plain',
  165. 'mid' => 'audio/x-midi',
  166. 'mov' => 'video/quicktime',
  167. 'mp2' => 'audio/mpeg',
  168. 'mp3' => 'audio/mpeg3',
  169. 'mpg' => 'audio/mpeg',
  170. 'pdf' => 'aplication/pdf',
  171. 'png' => 'image/png',
  172. 'rtf' => 'application/rtf',
  173. 'tif' => 'image/tiff',
  174. 'tiff' => 'image/tiff',
  175. 'txt' => 'text/plain',
  176. 'xml' => 'text/xml',
  177. );
  178. public static $defaultphp = array(
  179. 'php' => true
  180. );
  181. public static $defaultphps = array(
  182. 'phps' => true
  183. );
  184. public static $deny = array('/.+\.inc$/');
  185. public static function viewSource($archive, $file)
  186. {
  187. // security, idea borrowed from PHK
  188. if (!file_exists($archive . '.introspect')) {
  189. header("HTTP/1.0 404 Not Found");
  190. return false;
  191. }
  192. if (self::_fileExists($archive, $_GET['viewsource'])) {
  193. $source = highlight_file('phar://go-pear.phar/' .
  194. $_GET['viewsource'], true);
  195. header('Content-Type: text/html');
  196. header('Content-Length: ' . strlen($source));
  197. echo '<html><head><title>Source of ',
  198. htmlspecialchars($_GET['viewsource']), '</title></head>';
  199. echo '<body><h1>Source of ',
  200. htmlspecialchars($_GET['viewsource']), '</h1>';
  201. if (isset($_GET['introspect'])) {
  202. echo '<a href="', htmlspecialchars($_SERVER['PHP_SELF']),
  203. '?introspect=', urlencode(htmlspecialchars($_GET['introspect'])),
  204. '">Return to ', htmlspecialchars($_GET['introspect']), '</a><br />';
  205. }
  206. echo $source;
  207. return false;
  208. } else {
  209. header("HTTP/1.0 404 Not Found");
  210. return false;
  211. }
  212. }
  213. public static function introspect($archive, $dir)
  214. {
  215. // security, idea borrowed from PHK
  216. if (!file_exists($archive . '.introspect')) {
  217. header("HTTP/1.0 404 Not Found");
  218. return false;
  219. }
  220. if (!$dir) {
  221. $dir = '/';
  222. }
  223. $dir = self::processFile($dir);
  224. if ($dir[0] != '/') {
  225. $dir = '/' . $dir;
  226. }
  227. try {
  228. $self = htmlspecialchars($_SERVER['PHP_SELF']);
  229. $iterate = new DirectoryIterator('phar://go-pear.phar' . $dir);
  230. echo '<html><head><title>Introspect ', htmlspecialchars($dir),
  231. '</title></head><body><h1>Introspect ', htmlspecialchars($dir),
  232. '</h1><ul>';
  233. if ($dir != '/') {
  234. echo '<li><a href="', $self, '?introspect=',
  235. htmlspecialchars(dirname($dir)), '">..</a></li>';
  236. }
  237. foreach ($iterate as $entry) {
  238. if ($entry->isDot()) continue;
  239. $name = self::processFile($entry->getPathname());
  240. $name = str_replace('phar://go-pear.phar/', '', $name);
  241. if ($entry->isDir()) {
  242. echo '<li><a href="', $self, '?introspect=',
  243. urlencode(htmlspecialchars($name)),
  244. '">',
  245. htmlspecialchars($entry->getFilename()), '/</a> [directory]</li>';
  246. } else {
  247. echo '<li><a href="', $self, '?introspect=',
  248. urlencode(htmlspecialchars($dir)), '&viewsource=',
  249. urlencode(htmlspecialchars($name)),
  250. '">',
  251. htmlspecialchars($entry->getFilename()), '</a></li>';
  252. }
  253. }
  254. return false;
  255. } catch (Exception $e) {
  256. echo '<html><head><title>Directory not found: ',
  257. htmlspecialchars($dir), '</title></head>',
  258. '<body><h1>Directory not found: ', htmlspecialchars($dir), '</h1>',
  259. '<p>Try <a href="', htmlspecialchars($_SERVER['PHP_SELF']), '?introspect=/">',
  260. 'This link</a></p></body></html>';
  261. return false;
  262. }
  263. }
  264. public static function webFrontController($initfile)
  265. {
  266. if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
  267. $uri = parse_url($_SERVER['REQUEST_URI']);
  268. $archive = realpath($_SERVER['SCRIPT_FILENAME']);
  269. $subpath = str_replace('/' . basename($archive), '', $uri['path']);
  270. if (!$subpath || $subpath == '/') {
  271. if (isset($_GET['viewsource'])) {
  272. return self::viewSource($archive, $_GET['viewsource']);
  273. }
  274. if (isset($_GET['introspect'])) {
  275. return self::introspect($archive, $_GET['introspect']);
  276. }
  277. $subpath = '/' . $initfile;
  278. }
  279. if (!self::_fileExists($archive, substr($subpath, 1))) {
  280. header("HTTP/1.0 404 Not Found");
  281. return false;
  282. }
  283. foreach (self::$deny as $pattern) {
  284. if (preg_match($pattern, $subpath)) {
  285. header("HTTP/1.0 404 Not Found");
  286. return false;
  287. }
  288. }
  289. $inf = pathinfo(basename($subpath));
  290. if (!isset($inf['extension'])) {
  291. header('Content-Type: text/plain');
  292. header('Content-Length: ' .
  293. self::_filesize($archive, substr($subpath, 1)));
  294. readfile('phar://go-pear.phar' . $subpath);
  295. return false;
  296. }
  297. if (isset(self::$defaultphp[$inf['extension']])) {
  298. include 'phar://go-pear.phar' . $subpath;
  299. return false;
  300. }
  301. if (isset(self::$defaultmimes[$inf['extension']])) {
  302. header('Content-Type: ' . self::$defaultmimes[$inf['extension']]);
  303. header('Content-Length: ' .
  304. self::_filesize($archive, substr($subpath, 1)));
  305. readfile('phar://go-pear.phar' . $subpath);
  306. return false;
  307. }
  308. if (isset(self::$defaultphps[$inf['extension']])) {
  309. header('Content-Type: text/html');
  310. $c = highlight_file('phar://go-pear.phar' . $subpath, true);
  311. header('Content-Length: ' . strlen($c));
  312. echo $c;
  313. return false;
  314. }
  315. header('Content-Type: text/plain');
  316. header('Content-Length: ' .
  317. self::_filesize($archive, substr($subpath, 1)));
  318. readfile('phar://go-pear.phar' . $subpath);
  319. }
  320. }
  321. /**
  322. * Detect end of stub
  323. *
  324. * @param string $buffer stub past '__HALT_'.'COMPILER();'
  325. * @return end of stub, prior to length of manifest.
  326. */
  327. private static final function _endOfStubLength($buffer)
  328. {
  329. $pos = 0;
  330. if (!strlen($buffer)) {
  331. return $pos;
  332. }
  333. if (($buffer[0] == ' ' || $buffer[0] == "\n") && @substr($buffer, 1, 2) == '')
  334. {
  335. $pos += 3;
  336. if ($buffer[$pos] == "\r" && $buffer[$pos+1] == "\n") {
  337. $pos += 2;
  338. }
  339. else if ($buffer[$pos] == "\n") {
  340. $pos += 1;
  341. }
  342. }
  343. return $pos;
  344. }
  345. /**
  346. * Allows loading an external Phar archive without include()ing it
  347. *
  348. * @param string $file phar package to load
  349. * @param string $alias alias to use
  350. * @throws Exception
  351. */
  352. public static final function loadPhar($file, $alias = NULL)
  353. {
  354. $file = realpath($file);
  355. if ($file) {
  356. $fp = fopen($file, 'rb');
  357. $buffer = '';
  358. while (!feof($fp)) {
  359. $buffer .= fread($fp, 8192);
  360. // don't break phars
  361. if ($pos = strpos($buffer, '__HALT_COMPI' . 'LER();')) {
  362. $buffer .= fread($fp, 5);
  363. fclose($fp);
  364. $pos += 18;
  365. $pos += self::_endOfStubLength(substr($buffer, $pos));
  366. return self::_mapPhar($file, $pos, $alias);
  367. }
  368. }
  369. fclose($fp);
  370. }
  371. }
  372. /**
  373. * Map a full real file path to an alias used to refer to the .phar
  374. *
  375. * This function can only be called from the initialization of the .phar itself.
  376. * Any attempt to call from outside the .phar or to re-alias the .phar will fail
  377. * as a security measure.
  378. * @param string $alias
  379. * @param int $dataoffset the value of 43879
  380. */
  381. public static final function mapPhar($alias = NULL, $dataoffset = NULL)
  382. {
  383. try {
  384. $trace = debug_backtrace();
  385. $file = $trace[0]['file'];
  386. // this ensures that this is safe
  387. if (!in_array($file, get_included_files())) {
  388. die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' .
  389. 'the phar that initiates it');
  390. }
  391. $file = realpath($file);
  392. if (!isset($dataoffset)) {
  393. $dataoffset = constant('__COMPILER_HALT_OFFSET'.'__');
  394. $fp = fopen($file, 'rb');
  395. fseek($fp, $dataoffset, SEEK_SET);
  396. $dataoffset = $dataoffset + self::_endOfStubLength(fread($fp, 5));
  397. fclose($fp);
  398. }
  399. self::_mapPhar($file, $dataoffset);
  400. } catch (Exception $e) {
  401. die($e->getMessage());
  402. }
  403. }
  404. /**
  405. * Sub-function, allows recovery from errors
  406. *
  407. * @param unknown_type $file
  408. * @param unknown_type $dataoffset
  409. */
  410. private static function _mapPhar($file, $dataoffset, $alias = NULL)
  411. {
  412. $file = realpath($file);
  413. if (isset(self::$_manifest[$file])) {
  414. return;
  415. }
  416. if (!is_array(self::$_pharMapping)) {
  417. self::$_pharMapping = array();
  418. }
  419. $fp = fopen($file, 'rb');
  420. // seek to __HALT_COMPILER_OFFSET__
  421. fseek($fp, $dataoffset);
  422. $manifest_length = unpack('Vlen', fread($fp, 4));
  423. $manifest = '';
  424. $last = '1';
  425. while (strlen($last) && strlen($manifest) < $manifest_length['len']) {
  426. $read = 8192;
  427. if ($manifest_length['len'] - strlen($manifest) < 8192) {
  428. $read = $manifest_length['len'] - strlen($manifest);
  429. }
  430. $last = fread($fp, $read);
  431. $manifest .= $last;
  432. }
  433. if (strlen($manifest) < $manifest_length['len']) {
  434. throw new Exception('ERROR: manifest length read was "' .
  435. strlen($manifest) .'" should be "' .
  436. $manifest_length['len'] . '"');
  437. }
  438. $info = self::_unserializeManifest($manifest);
  439. if ($info['alias']) {
  440. $alias = $info['alias'];
  441. $explicit = true;
  442. } else {
  443. if (!isset($alias)) {
  444. $alias = $file;
  445. }
  446. $explicit = false;
  447. }
  448. self::$_manifest[$file] = $info['manifest'];
  449. $compressed = $info['compressed'];
  450. self::$_fileStart[$file] = ftell($fp);
  451. fclose($fp);
  452. if ($compressed & 0x00001000) {
  453. if (!function_exists('gzinflate')) {
  454. throw new Exception('Error: zlib extension is not enabled - gzinflate() function needed' .
  455. ' for compressed .phars');
  456. }
  457. }
  458. if ($compressed & 0x00002000) {
  459. if (!function_exists('bzdecompress')) {
  460. throw new Exception('Error: bzip2 extension is not enabled - bzdecompress() function needed' .
  461. ' for compressed .phars');
  462. }
  463. }
  464. if (isset(self::$_pharMapping[$alias])) {
  465. throw new Exception('ERROR: PHP_Archive::mapPhar has already been called for alias "' .
  466. $alias . '" cannot re-alias to "' . $file . '"');
  467. }
  468. self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset, $explicit,
  469. $info['metadata']);
  470. self::$_pharFiles[$file] = $alias;
  471. }
  472. /**
  473. * extract the manifest into an internal array
  474. *
  475. * @param string $manifest
  476. * @return false|array
  477. */
  478. private static function _unserializeManifest($manifest)
  479. {
  480. // retrieve the number of files in the manifest
  481. $info = unpack('V', substr($manifest, 0, 4));
  482. $apiver = substr($manifest, 4, 2);
  483. $apiver = bin2hex($apiver);
  484. $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]);
  485. $majorcompat = hexdec($apiver[0]);
  486. $calcapi = explode('.', self::APIVersion());
  487. if ($calcapi[0] != $majorcompat) {
  488. throw new Exception('Phar is incompatible API version ' . $apiver_dots . ', but ' .
  489. 'PHP_Archive is API version '.self::APIVersion());
  490. }
  491. if ($calcapi[0] === '0') {
  492. if (self::APIVersion() != $apiver_dots) {
  493. throw new Exception('Phar is API version ' . $apiver_dots .
  494. ', but PHP_Archive is API version '.self::APIVersion(), E_USER_ERROR);
  495. }
  496. }
  497. $flags = unpack('V', substr($manifest, 6, 4));
  498. $ret = array('compressed' => $flags[1] & 0x00003000);
  499. // signature is not verified by default in PHP_Archive, phar is better
  500. $ret['hassignature'] = $flags & 0x00010000;
  501. $aliaslen = unpack('V', substr($manifest, 10, 4));
  502. if ($aliaslen) {
  503. $ret['alias'] = substr($manifest, 14, $aliaslen[1]);
  504. } else {
  505. $ret['alias'] = false;
  506. }
  507. $manifest = substr($manifest, 14 + $aliaslen[1]);
  508. $metadatalen = unpack('V', substr($manifest, 0, 4));
  509. if ($metadatalen[1]) {
  510. $ret['metadata'] = unserialize(substr($manifest, 4, $metadatalen[1]));
  511. $manifest = substr($manifest, 4 + $metadatalen[1]);
  512. } else {
  513. $ret['metadata'] = null;
  514. $manifest = substr($manifest, 4);
  515. }
  516. $offset = 0;
  517. $start = 0;
  518. for ($i = 0; $i < $info[1]; $i++) {
  519. // length of the file name
  520. $len = unpack('V', substr($manifest, $start, 4));
  521. $start += 4;
  522. // file name
  523. $savepath = substr($manifest, $start, $len[1]);
  524. $start += $len[1];
  525. // retrieve manifest data:
  526. // 0 = uncompressed file size
  527. // 1 = timestamp of when file was added to phar
  528. // 2 = compressed filesize
  529. // 3 = crc32
  530. // 4 = flags
  531. // 5 = metadata length
  532. $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($manifest, $start, 24)));
  533. $ret['manifest'][$savepath][3] = sprintf('%u', $ret['manifest'][$savepath][3]
  534. & 0xffffffff);
  535. if ($ret['manifest'][$savepath][5]) {
  536. $ret['manifest'][$savepath][6] = unserialize(substr($manifest, $start + 24,
  537. $ret['manifest'][$savepath][5]));
  538. } else {
  539. $ret['manifest'][$savepath][6] = null;
  540. }
  541. $ret['manifest'][$savepath][7] = $offset;
  542. $offset += $ret['manifest'][$savepath][2];
  543. $start += 24 + $ret['manifest'][$savepath][5];
  544. }
  545. return $ret;
  546. }
  547. /**
  548. * @param string
  549. */
  550. private static function processFile($path)
  551. {
  552. if ($path == '.') {
  553. return '';
  554. }
  555. $std = str_replace("\\", "/", $path);
  556. while ($std != ($std = preg_replace("/[^\/:?]+\/\.\.\//", "", $std))) ;
  557. $std = str_replace("/./", "", $std);
  558. if (strlen($std) > 1 && $std[0] == '/') {
  559. $std = substr($std, 1);
  560. }
  561. if (strncmp($std, "./", 2) == 0) {
  562. return substr($std, 2);
  563. } else {
  564. return $std;
  565. }
  566. }
  567. /**
  568. * Seek in the master archive to a matching file or directory
  569. * @param string
  570. */
  571. protected function selectFile($path, $allowdirs = true)
  572. {
  573. $std = self::processFile($path);
  574. if (isset(self::$_manifest[$this->_archiveName][$path])) {
  575. if ($path[strlen($path)-1] == '/') {
  576. // directory
  577. if (!$allowdirs) {
  578. return 'Error: "' . $path . '" is a directory in phar "' . $this->_basename . '"';
  579. }
  580. $this->_setCurrentFile($path, true);
  581. } else {
  582. $this->_setCurrentFile($path);
  583. }
  584. return true;
  585. }
  586. if (!$allowdirs) {
  587. return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"';
  588. }
  589. foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
  590. if (empty($std) ||
  591. //$std is a directory
  592. strncmp($std.'/', $path, strlen($std)+1) == 0) {
  593. $this->currentFilename = $this->internalFileLength = $this->currentStat = null;
  594. return true;
  595. }
  596. }
  597. return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"';
  598. }
  599. private function _setCurrentFile($path, $dir = false)
  600. {
  601. if ($dir) {
  602. $this->currentStat = array(
  603. 2 => 040777, // directory mode, readable by all, writeable by none
  604. 4 => 0, // uid
  605. 5 => 0, // gid
  606. 7 => 0, // size
  607. 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
  608. );
  609. $this->internalFileLength = 0;
  610. $this->isDir = true;
  611. } else {
  612. $this->currentStat = array(
  613. 2 => 0100444, // file mode, readable by all, writeable by none
  614. 4 => 0, // uid
  615. 5 => 0, // gid
  616. 7 => self::$_manifest[$this->_archiveName][$path][0], // size
  617. 9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
  618. );
  619. $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2];
  620. $this->isDir = false;
  621. }
  622. $this->currentFilename = $path;
  623. // seek to offset of file header within the .phar
  624. if (is_resource(@$this->fp)) {
  625. fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][7]);
  626. }
  627. }
  628. private static function _fileExists($archive, $path)
  629. {
  630. return isset(self::$_manifest[$archive]) &&
  631. isset(self::$_manifest[$archive][$path]);
  632. }
  633. private static function _filesize($archive, $path)
  634. {
  635. return self::$_manifest[$archive][$path][0];
  636. }
  637. /**
  638. * Seek to a file within the master archive, and extract its contents
  639. * @param string
  640. * @return array|string an array containing an error message string is returned
  641. * upon error, otherwise the file contents are returned
  642. */
  643. public function extractFile($path)
  644. {
  645. $this->fp = @fopen($this->_archiveName, "rb");
  646. if (!$this->fp) {
  647. return array('Error: cannot open phar "' . $this->_archiveName . '"');
  648. }
  649. if (($e = $this->selectFile($path, false)) === true) {
  650. $data = '';
  651. $count = $this->internalFileLength;
  652. while ($count) {
  653. if ($count < 8192) {
  654. $data .= @fread($this->fp, $count);
  655. $count = 0;
  656. } else {
  657. $count -= 8192;
  658. $data .= @fread($this->fp, 8192);
  659. }
  660. }
  661. @fclose($this->fp);
  662. if (self::$_manifest[$this->_archiveName][$path][4] & self::GZ) {
  663. $data = gzinflate($data);
  664. } elseif (self::$_manifest[$this->_archiveName][$path][4] & self::BZ2) {
  665. $data = bzdecompress($data);
  666. }
  667. if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) {
  668. if (strlen($data) != $this->currentStat[7]) {
  669. return array("Not valid internal .phar file (size error {$size} != " .
  670. $this->currentStat[7] . ")");
  671. }
  672. if (self::$_manifest[$this->_archiveName][$path][3] != sprintf("%u", crc32($data) & 0xffffffff)) {
  673. return array("Not valid internal .phar file (checksum error)");
  674. }
  675. self::$_manifest[$this->_archiveName][$path]['ok'] = true;
  676. }
  677. return $data;
  678. } else {
  679. @fclose($this->fp);
  680. return array($e);
  681. }
  682. }
  683. /**
  684. * Parse urls like phar:///fullpath/to/my.phar/file.txt
  685. *
  686. * @param string $file
  687. * @return false|array
  688. */
  689. static protected function parseUrl($file)
  690. {
  691. if (substr($file, 0, 7) != 'phar://') {
  692. return false;
  693. }
  694. $file = substr($file, 7);
  695. $ret = array('scheme' => 'phar');
  696. $pos_p = strpos($file, '.phar.php');
  697. $pos_z = strpos($file, '.phar.gz');
  698. $pos_b = strpos($file, '.phar.bz2');
  699. if ($pos_p) {
  700. if ($pos_z) {
  701. return false;
  702. }
  703. $ret['host'] = substr($file, 0, $pos_p + strlen('.phar.php'));
  704. $ret['path'] = substr($file, strlen($ret['host']));
  705. } elseif ($pos_z) {
  706. $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.gz'));
  707. $ret['path'] = substr($file, strlen($ret['host']));
  708. } elseif ($pos_b) {
  709. $ret['host'] = substr($file, 0, $pos_z + strlen('.phar.bz2'));
  710. $ret['path'] = substr($file, strlen($ret['host']));
  711. } elseif (($pos_p = strpos($file, ".phar")) !== false) {
  712. $ret['host'] = substr($file, 0, $pos_p + strlen('.phar'));
  713. $ret['path'] = substr($file, strlen($ret['host']));
  714. } else {
  715. return false;
  716. }
  717. if (!$ret['path']) {
  718. $ret['path'] = '/';
  719. }
  720. return $ret;
  721. }
  722. /**
  723. * Locate the .phar archive in the include_path and detect the file to open within
  724. * the archive.
  725. *
  726. * Possible parameters are phar://pharname.phar/filename_within_phar.ext
  727. * @param string a file within the archive
  728. * @return string the filename within the .phar to retrieve
  729. */
  730. public function initializeStream($file)
  731. {
  732. $file = self::processFile($file);
  733. $info = @parse_url($file);
  734. if (!$info) {
  735. $info = self::parseUrl($file);
  736. }
  737. if (!$info) {
  738. return false;
  739. }
  740. if (!isset($info['host'])) {
  741. // malformed internal file
  742. return false;
  743. }
  744. if (!isset(self::$_pharFiles[$info['host']]) &&
  745. !isset(self::$_pharMapping[$info['host']])) {
  746. try {
  747. self::loadPhar($info['host']);
  748. // use alias from here out
  749. $info['host'] = self::$_pharFiles[$info['host']];
  750. } catch (Exception $e) {
  751. return false;
  752. }
  753. }
  754. if (!isset($info['path'])) {
  755. return false;
  756. } elseif (strlen($info['path']) > 1) {
  757. $info['path'] = substr($info['path'], 1);
  758. }
  759. if (isset(self::$_pharMapping[$info['host']])) {
  760. $this->_basename = $info['host'];
  761. $this->_archiveName = self::$_pharMapping[$info['host']][0];
  762. $this->_compressed = self::$_pharMapping[$info['host']][1];
  763. } elseif (isset(self::$_pharFiles[$info['host']])) {
  764. $this->_archiveName = $info['host'];
  765. $this->_basename = self::$_pharFiles[$info['host']];
  766. $this->_compressed = self::$_pharMapping[$this->_basename][1];
  767. }
  768. $file = $info['path'];
  769. return $file;
  770. }
  771. /**
  772. * Open the requested file - PHP streams API
  773. *
  774. * @param string $file String provided by the Stream wrapper
  775. * @access private
  776. */
  777. public function stream_open($file)
  778. {
  779. return $this->_streamOpen($file);
  780. }
  781. /**
  782. * @param string filename to opne, or directory name
  783. * @param bool if true, a directory will be matched, otherwise only files
  784. * will be matched
  785. * @uses trigger_error()
  786. * @return bool success of opening
  787. * @access private
  788. */
  789. private function _streamOpen($file, $searchForDir = false)
  790. {
  791. $path = $this->initializeStream($file);
  792. if (!$path) {
  793. trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
  794. }
  795. if (is_array($this->file = $this->extractFile($path))) {
  796. trigger_error($this->file[0], E_USER_ERROR);
  797. return false;
  798. }
  799. if ($path != $this->currentFilename) {
  800. if (!$searchForDir) {
  801. trigger_error("Cannot open '$file', is a directory", E_USER_ERROR);
  802. return false;
  803. } else {
  804. $this->file = '';
  805. return true;
  806. }
  807. }
  808. if (!is_null($this->file) && $this->file !== false) {
  809. return true;
  810. } else {
  811. return false;
  812. }
  813. }
  814. /**
  815. * Read the data - PHP streams API
  816. *
  817. * @param int
  818. * @access private
  819. */
  820. public function stream_read($count)
  821. {
  822. $ret = substr($this->file, $this->position, $count);
  823. $this->position += strlen($ret);
  824. return $ret;
  825. }
  826. /**
  827. * Whether we've hit the end of the file - PHP streams API
  828. * @access private
  829. */
  830. function stream_eof()
  831. {
  832. return $this->position >= $this->currentStat[7];
  833. }
  834. /**
  835. * For seeking the stream - PHP streams API
  836. * @param int
  837. * @param SEEK_SET|SEEK_CUR|SEEK_END
  838. * @access private
  839. */
  840. public function stream_seek($pos, $whence)
  841. {
  842. switch ($whence) {
  843. case SEEK_SET:
  844. if ($pos < 0) {
  845. return false;
  846. }
  847. $this->position = $pos;
  848. break;
  849. case SEEK_CUR:
  850. if ($pos + $this->currentStat[7] < 0) {
  851. return false;
  852. }
  853. $this->position += $pos;
  854. break;
  855. case SEEK_END:
  856. if ($pos + $this->currentStat[7] < 0) {
  857. return false;
  858. }
  859. $this->position = $pos + $this->currentStat[7];
  860. break;
  861. default:
  862. return false;
  863. }
  864. return true;
  865. }
  866. /**
  867. * The current position in the stream - PHP streams API
  868. * @access private
  869. */
  870. public function stream_tell()
  871. {
  872. return $this->position;
  873. }
  874. /**
  875. * The result of an fstat call, returns mod time from creation, and file size -
  876. * PHP streams API
  877. * @uses _stream_stat()
  878. * @access private
  879. */
  880. public function stream_stat()
  881. {
  882. return $this->_stream_stat();
  883. }
  884. /**
  885. * Retrieve statistics on a file or directory within the .phar
  886. * @param string file/directory to stat
  887. * @access private
  888. */
  889. public function _stream_stat($file = null)
  890. {
  891. $std = $file ? self::processFile($file) : $this->currentFilename;
  892. if ($file) {
  893. if (isset(self::$_manifest[$this->_archiveName][$file])) {
  894. $this->_setCurrentFile($file);
  895. $isdir = false;
  896. } else {
  897. do {
  898. $isdir = false;
  899. if ($file == '/') {
  900. break;
  901. }
  902. foreach (self::$_manifest[$this->_archiveName] as $path => $info) {
  903. if (strpos($path, $file) === 0) {
  904. if (strlen($path) > strlen($file) &&
  905. $path[strlen($file)] == '/') {
  906. break 2;
  907. }
  908. }
  909. }
  910. // no files exist and no directories match this string
  911. return false;
  912. } while (false);
  913. $isdir = true;
  914. }
  915. } else {
  916. $isdir = false; // open streams must be files
  917. }
  918. $mode = $isdir ? 0040444 : 0100444;
  919. // 040000 = dir, 010000 = file
  920. // everything is readable, nothing is writeable
  921. return array(
  922. 0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices
  923. 'dev' => 0, 'ino' => 0,
  924. 'mode' => $mode,
  925. 'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0,
  926. 'size' => $this->currentStat ? $this->currentStat[7] : 0,
  927. 'atime' => $this->currentStat ? $this->currentStat[9] : 0,
  928. 'mtime' => $this->currentStat ? $this->currentStat[9] : 0,
  929. 'ctime' => $this->currentStat ? $this->currentStat[9] : 0,
  930. );
  931. }
  932. /**
  933. * Stat a closed file or directory - PHP streams API
  934. * @param string
  935. * @param int
  936. * @access private
  937. */
  938. public function url_stat($url, $flags)
  939. {
  940. $path = $this->initializeStream($url);
  941. return $this->_stream_stat($path);
  942. }
  943. /**
  944. * Set a stream option - PHP stream API
  945. * @param int
  946. * @param int
  947. * @param int
  948. * @access private
  949. */
  950. public function stream_set_option($option, $arg1, $arg2)
  951. {
  952. // Simply ignore set options.
  953. return false;
  954. }
  955. /**
  956. * Open a directory in the .phar for reading - PHP streams API
  957. * @param string directory name
  958. * @access private
  959. */
  960. public function dir_opendir($path)
  961. {
  962. $info = @parse_url($path);
  963. if (!$info) {
  964. $info = self::parseUrl($path);
  965. if (!$info) {
  966. trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
  967. E_USER_ERROR);
  968. return false;
  969. }
  970. }
  971. $path = !empty($info['path']) ?
  972. $info['host'] . $info['path'] : $info['host'] . '/';
  973. $path = $this->initializeStream('phar://' . $path);
  974. if (isset(self::$_manifest[$this->_archiveName][$path])) {
  975. trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
  976. E_USER_ERROR);
  977. return false;
  978. }
  979. if ($path == false) {
  980. trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
  981. return false;
  982. }
  983. $this->fp = @fopen($this->_archiveName, "rb");
  984. if (!$this->fp) {
  985. trigger_error('Error: cannot open phar "' . $this->_archiveName . '"');
  986. return false;
  987. }
  988. $this->_dirFiles = array();
  989. foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
  990. if ($path == '/') {
  991. if (strpos($file, '/')) {
  992. $a = explode('/', $file);
  993. $this->_dirFiles[array_shift($a)] = true;
  994. } else {
  995. $this->_dirFiles[$file] = true;
  996. }
  997. } elseif (strpos($file, $path) === 0) {
  998. $fname = substr($file, strlen($path) + 1);
  999. if ($fname == '/' || $fname[strlen($fname)-1] == '/') {
  1000. continue; // empty directory
  1001. }
  1002. if (strpos($fname, '/')) {
  1003. // this is a directory
  1004. $a = explode('/', $fname);
  1005. $this->_dirFiles[array_shift($a)] = true;
  1006. } elseif ($file[strlen($path)] == '/') {
  1007. // this is a file
  1008. $this->_dirFiles[$fname] = true;
  1009. }
  1010. }
  1011. }
  1012. @fclose($this->fp);
  1013. if (!count($this->_dirFiles)) {
  1014. return false;
  1015. }
  1016. @uksort($this->_dirFiles, 'strnatcmp');
  1017. return true;
  1018. }
  1019. /**
  1020. * Read the next directory entry - PHP streams API
  1021. * @access private
  1022. */
  1023. public function dir_readdir()
  1024. {
  1025. $ret = key($this->_dirFiles);
  1026. @next($this->_dirFiles);
  1027. if (!$ret) {
  1028. return false;
  1029. }
  1030. return $ret;
  1031. }
  1032. /**
  1033. * Close a directory handle opened with opendir() - PHP streams API
  1034. * @access private
  1035. */
  1036. public function dir_closedir()
  1037. {
  1038. $this->_dirFiles = array();
  1039. return true;
  1040. }
  1041. /**
  1042. * Rewind to the first directory entry - PHP streams API
  1043. * @access private
  1044. */
  1045. public function dir_rewinddir()
  1046. {
  1047. @reset($this->_dirFiles);
  1048. return true;
  1049. }
  1050. /**
  1051. * API version of this class
  1052. * @return string
  1053. */
  1054. public static final function APIVersion()
  1055. {
  1056. return '1.1.0';
  1057. }
  1058. /**
  1059. * Retrieve Phar-specific metadata for a Phar archive
  1060. *
  1061. * @param string $phar full path to Phar archive, or alias
  1062. * @return null|mixed The value that was serialized for the Phar
  1063. * archive's metadata
  1064. * @throws Exception
  1065. */
  1066. public static function getPharMetadata($phar)
  1067. {
  1068. if (isset(self::$_pharFiles[$phar])) {
  1069. $phar = self::$_pharFiles[$phar];
  1070. }
  1071. if (!isset(self::$_pharMapping[$phar])) {
  1072. throw new Exception('Unknown Phar archive: "' . $phar . '"');
  1073. }
  1074. return self::$_pharMapping[$phar][4];
  1075. }
  1076. /**
  1077. * Retrieve File-specific metadata for a Phar archive file
  1078. *
  1079. * @param string $phar full path to Phar archive, or alias
  1080. * @param string $file relative path to file within Phar archive
  1081. * @return null|mixed The value that was serialized for the Phar
  1082. * archive's metadata
  1083. * @throws Exception
  1084. */
  1085. public static function getFileMetadata($phar, $file)
  1086. {
  1087. if (!isset(self::$_pharFiles[$phar])) {
  1088. if (!isset(self::$_pharMapping[$phar])) {
  1089. throw new Exception('Unknown Phar archive: "' . $phar . '"');
  1090. }
  1091. $phar = self::$_pharMapping[$phar][0];
  1092. }
  1093. if (!isset(self::$_manifest[$phar])) {
  1094. throw new Exception('Unknown Phar: "' . $phar . '"');
  1095. }
  1096. $file = self::processFile($file);
  1097. if (!isset(self::$_manifest[$phar][$file])) {
  1098. throw new Exception('Unknown file "' . $file . '" within Phar "'. $phar . '"');
  1099. }
  1100. return self::$_manifest[$phar][$file][6];
  1101. }
  1102. /**
  1103. * @return list of supported signature algorithmns.
  1104. */
  1105. public static function getSupportedSignatures()
  1106. {
  1107. $ret = array('MD5', 'SHA-1');
  1108. if (extension_loaded('hash')) {
  1109. $ret[] = 'SHA-256';
  1110. $ret[] = 'SHA-512';
  1111. }
  1112. if (extension_loaded('openssl')) {
  1113. $ret[] = 'OpenSSL';
  1114. }
  1115. return $ret;
  1116. }
  1117. }}
  1118. if (!class_exists('Phar')) {
  1119. PHP_Archive::mapPhar(null, 43879 );
  1120. } else {
  1121. try {
  1122. Phar::mapPhar();
  1123. } catch (Exception $e) {
  1124. echo $e->getMessage();
  1125. }
  1126. }
  1127. if (class_exists('PHP_Archive') && !in_array('phar', stream_get_wrappers())) {
  1128. stream_wrapper_register('phar', 'PHP_Archive');
  1129. }
  1130. @ini_set('memory_limit', -1);
  1131. if (extension_loaded('phar')) {if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
  1132. $uri = parse_url($_SERVER['REQUEST_URI']);
  1133. $archive = realpath($_SERVER['SCRIPT_FILENAME']);
  1134. $subpath = str_replace('/' . basename($archive), '', $uri['path']);
  1135. $mimetypes = array (
  1136. 'aif' => 'audio/x-aiff',
  1137. 'aiff' => 'audio/x-aiff',
  1138. 'arc' => 'application/octet-stream',
  1139. 'arj' => 'application/octet-stream',
  1140. 'art' => 'image/x-jg',
  1141. 'asf' => 'video/x-ms-asf',
  1142. 'asx' => 'video/x-ms-asf',
  1143. 'avi' => 'video/avi',
  1144. 'bin' => 'application/octet-stream',
  1145. 'bm' => 'image/bmp',
  1146. 'bmp' => 'image/bmp',
  1147. 'bz2' => 'application/x-bzip2',
  1148. 'css' => 'text/css',
  1149. 'doc' => 'application/msword',
  1150. 'dot' => 'application/msword',
  1151. 'dv' => 'video/x-dv',
  1152. 'dvi' => 'application/x-dvi',
  1153. 'eps' => 'application/postscript',
  1154. 'exe' => 'application/octet-stream',
  1155. 'gif' => 'image/gif',
  1156. 'gz' => 'application/x-gzip',
  1157. 'gzip' => 'application/x-gzip',
  1158. 'htm' => 'text/html',
  1159. 'html' => 'text/html',
  1160. 'ico' => 'image/x-icon',
  1161. 'jpe' => 'image/jpeg',
  1162. 'jpg' => 'image/jpeg',
  1163. 'jpeg' => 'image/jpeg',
  1164. 'js' => 'application/x-javascript',
  1165. 'log' => 'text/plain',
  1166. 'mid' => 'audio/x-midi',
  1167. 'mov' => 'video/quicktime',
  1168. 'mp2' => 'audio/mpeg',
  1169. 'mp3' => 'audio/mpeg3',
  1170. 'mpg' => 'audio/mpeg',
  1171. 'pdf' => 'aplication/pdf',
  1172. 'png' => 'image/png',
  1173. 'rtf' => 'application/rtf',
  1174. 'tif' => 'image/tiff',
  1175. 'tiff' => 'image/tiff',
  1176. 'txt' => 'text/plain',
  1177. 'xml' => 'text/xml',
  1178. );
  1179. $phpfiles = array (
  1180. 'php' => true,
  1181. );
  1182. $phpsfiles = array (
  1183. 'phps' => true,
  1184. );
  1185. $deny = array (
  1186. 0 => '/.+\\.inc$/',
  1187. );
  1188. $subpath = str_replace('/' . basename($archive), '', $uri['path']);
  1189. if (!$subpath || $subpath == '/') {
  1190. $subpath = '/PEAR.php';
  1191. }
  1192. if ($subpath[0] != '/') {
  1193. $subpath = '/' . $subpath;
  1194. }
  1195. if (!@file_exists('phar://' . $archive . $subpath)) {
  1196. header("HTTP/1.0 404 Not Found");
  1197. exit;
  1198. }
  1199. foreach ($deny as $pattern) {
  1200. if (preg_match($pattern, $subpath)) {
  1201. header("HTTP/1.0 404 Not Found");
  1202. exit;
  1203. }
  1204. }
  1205. $inf = pathinfo(basename($subpath));
  1206. if (!isset($inf['extension'])) {
  1207. header('Content-Type: text/plain');
  1208. header('Content-Length: ' . filesize('phar://' . $archive . $subpath));
  1209. readfile('phar://' . $archive . $subpath);
  1210. exit;
  1211. }
  1212. if (isset($phpfiles[$inf['extension']])) {
  1213. include 'phar://' . $archive . '/' . $subpath;
  1214. exit;
  1215. }
  1216. if (isset($mimetypes[$inf['extension']])) {
  1217. header('Content-Type: ' . $mimetypes[$inf['extension']]);
  1218. header('Content-Length: ' . filesize('phar://' . $archive . $subpath));
  1219. readfile('phar://' . $archive . $subpath);
  1220. exit;
  1221. }
  1222. if (isset($phpsfiles[$inf['extension']])) {
  1223. header('Content-Type: text/html');
  1224. $c = highlight_file('phar://' . $archive . $subpath, true);
  1225. header('Content-Length: ' . strlen($c));
  1226. echo $c;
  1227. exit;
  1228. }
  1229. header('Content-Type: text/plain');
  1230. header('Content-Length: ' . filesize('phar://' . $archive . '/' . $subpath));
  1231. readfile('phar://' . $archive . '/' . $subpath);
  1232. exit;
  1233. }} else {if (!empty($_SERVER['REQUEST_URI'])) {PHP_Archive::webFrontController('PEAR.php');exit;}}
  1234. require_once 'phar://go-pear.phar/index.php';
  1235. __HALT_COMPILER();h��F������� ���go-pear.phar�������Archive/Tar.php
  1236. N�e‰Õ]
  1237. N�–ÂB†m���������Console/Getopt.php\5��e‰Õ]\5��ŠÍ;@m������ ���index.php‹���e‰Õ]‹���A�#m������ ���OS/Guess.php¡*��e‰Õ]¡*��‹J–m���������PEAR.phpK���e‰Õ]K���½¶0m���������PEAR/ChannelFile.phpKÇ��e‰Õ]KÇ��ãh�m���������PEAR/ChannelFile/Parser.phpÞ��e‰Õ]Þ��â£p0m���������PEAR/Command.phpÖ0��e‰Õ]Ö0��¢}m���������PEAR/Command/Common.php/ ��e‰Õ]/ ��¯bœëm���������PEAR/Command/Install.phpŸÇ��e‰Õ]ŸÇ��¹ü/>m���������PEAR/Command/Install.xmló!��e‰Õ]ó!��jÇ¢m���������PEAR/Common.php\h��e‰Õ]\h��l�Pßm���������PEAR/Config.php�e‰Õ]�ƒÞnm���������PEAR/Dependency2.php‹Å��e‰Õ]‹Å��ÐŽÍøm���������PEAR/DependencyDB.phpj^��e‰Õ]j^��±T8xm���������PEAR/Downloader.php7�e‰Õ]7�ÞQãòm���������PEAR/Downloader/Package.php^*�e‰Õ]^*�ZlÃm���������PEAR/ErrorStack.php%„��e‰Õ]%„��õ�߇m���������PEAR/Frontend.php��e‰Õ]��2�Osm���������PEAR/Frontend/CLI.phpfd��e‰Õ]fd��µ U!m������+���PEAR/go-pear-tarballs/Archive_Tar-1.4.8.tar�è�e‰Õ]�è�'�”om������.���PEAR/go-pear-tarballs/Console_Getopt-1.4.3.tar�z��e‰Õ]�z��ÀUÚ/m������&���PEAR/go-pear-tarballs/PEAR-1.10.10.tar�H�e‰Õ]�H�Ñ>[ñm������0���PEAR/go-pear-tarballs/Structures_Graph-1.1.1.tar�6�e‰Õ]�6�ïŽjám������(���PEAR/go-pear-tarballs/XML_Util-1.4.3.tar�8�e‰Õ]�8�ükm���������PEAR/Installer.phpâ�e‰Õ]â�§Õ‘�m���������PEAR/Installer/Role.php��e‰Õ]��39�Öm���������PEAR/Installer/Role/Common.phpG��e‰Õ]G�� �éÂm���������PEAR/Installer/Role/Data.php��e‰Õ]��î98þm���������PEAR/Installer/Role/Data.xml’��e‰Õ]’��f�szm���������PEAR/Installer/Role/Doc.php ��e‰Õ] �� ¬m���������PEAR/Installer/Role/Doc.xml‘��e‰Õ]‘��h&P*m���������PEAR/Installer/Role/Php.php ��e‰Õ] ��ĉmcm���������PEAR/Installer/Role/Php.xml­��e‰Õ]­��z�q�m���������PEAR/Installer/Role/Script.php��e‰Õ]��Iodm���������PEAR/Installer/Role/Script.xml°��e‰Õ]°��@v§Ðm���������PEAR/Installer/Role/Test.php��e‰Õ]��¾"_pm���������PEAR/Installer/Role/Test.xml’��e‰Õ]’��B] m���������PEAR/PackageFile.phpc>��e‰Õ]c>��'‚‡=m������!���PEAR/PackageFile/Generator/v1.phpÅ��e‰Õ]Å��b˜ ²m������!���PEAR/PackageFile/Generator/v2.php‚��e‰Õ]‚��^ÇŒ}m���������PEAR/PackageFile/Parser/v1.php�@��e‰Õ]�@��@Ìu½m���������PEAR/PackageFile/Parser/v2.phpw ��e‰Õ]w ��MÖ½m���������PEAR/PackageFile/v1.phpþÅ��e‰Õ]þÅ��@Džåm���������PEAR/PackageFile/v2.php�e‰Õ]�=t’m������!���PEAR/PackageFile/v2/Validator.php€L�e‰Õ]€L�Zv,‡m���������PEAR/Proxy.php��e‰Õ]��Ã+™m���������PEAR/Registry.phpÌ)�e‰Õ]Ì)�‡m������ ���PEAR/REST.phpzA��e‰Õ]zA��M¸º©m���������PEAR/REST/10.phpÜ��e‰Õ]Ü��MãF)m���������PEAR/Start.phpÐ9��e‰Õ]Ð9��
  1238. õ®m���������PEAR/Start/CLI.phpHS��e‰Õ]HS��¥ÍáÃm���������PEAR/Task/Common.php8��e‰Õ]8��eì m���������PEAR/Task/Postinstallscript.phpª9��e‰Õ]ª9��&#¹Çm������"���PEAR/Task/Postinstallscript/rw.php5��e‰Õ]5��3'â¢m���������PEAR/Task/Replace.php��e‰Õ]��y¯ÒSm���������PEAR/Task/Replace/rw.php0��e‰Õ]0��±—¬˜m���������PEAR/Task/Unixeol.php ��e‰Õ] ��ƹíÖm���������PEAR/Task/Unixeol/rw.php5��e‰Õ]5��. _]m���������PEAR/Task/Windowseol.php ��e‰Õ] �� µ¢em���������PEAR/Task/Windowseol/rw.phpB��e‰Õ]B��µ,2$m���������PEAR/Validate.php'V��e‰Õ]'V��"¨³<m���������PEAR/Validator/PECL.phpR��e‰Õ]R��Ø�qÙm���������PEAR/XMLParser.php1��e‰Õ]1��ú8Ëm���������Structures/Graph.phpQ��e‰Õ]Q��4´T·m������,���Structures/Graph/Manipulator/AcyclicTest.phpÌ��e‰Õ]Ì�� Ò;ÿm������2���Structures/Graph/Manipulator/TopologicalSorter.phpØ��e‰Õ]Ø��3¤sm���������Structures/Graph/Node.phpR+��e‰Õ]R+��5~ém������
  1239. ���System.phpÀP��e‰Õ]ÀP��%Å´m������ ���XML/Util.phpž}��e‰Õ]ž}��`�äšm������<?php
  1240. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  1241. /**
  1242. * File::CSV
  1243. *
  1244. * PHP versions 4 and 5
  1245. *
  1246. * Copyright (c) 1997-2008,
  1247. * Vincent Blavet <vincent@phpconcept.net>
  1248. * All rights reserved.
  1249. *
  1250. * Redistribution and use in source and binary forms, with or without
  1251. * modification, are permitted provided that the following conditions are met:
  1252. *
  1253. * * Redistributions of source code must retain the above copyright notice,
  1254. * this list of conditions and the following disclaimer.
  1255. * * Redistributions in binary form must reproduce the above copyright
  1256. * notice, this list of conditions and the following disclaimer in the
  1257. * documentation and/or other materials provided with the distribution.
  1258. *
  1259. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  1260. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1261. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  1262. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  1263. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  1264. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  1265. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  1266. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  1267. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  1268. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1269. *
  1270. * @category File_Formats
  1271. * @package Archive_Tar
  1272. * @author Vincent Blavet <vincent@phpconcept.net>
  1273. * @copyright 1997-2010 The Authors
  1274. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  1275. * @version CVS: $Id$
  1276. * @link http://pear.php.net/package/Archive_Tar
  1277. */
  1278. // If the PEAR class cannot be loaded via the autoloader,
  1279. // then try to require_once it from the PHP include path.
  1280. if (!class_exists('PEAR')) {
  1281. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  1282. }
  1283. define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  1284. define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
  1285. if (!function_exists('gzopen') && function_exists('gzopen64')) {
  1286. function gzopen($filename, $mode, $use_include_path = 0)
  1287. {
  1288. return gzopen64($filename, $mode, $use_include_path);
  1289. }
  1290. }
  1291. if (!function_exists('gztell') && function_exists('gztell64')) {
  1292. function gztell($zp)
  1293. {
  1294. return gztell64($zp);
  1295. }
  1296. }
  1297. if (!function_exists('gzseek') && function_exists('gzseek64')) {
  1298. function gzseek($zp, $offset, $whence = SEEK_SET)
  1299. {
  1300. return gzseek64($zp, $offset, $whence);
  1301. }
  1302. }
  1303. /**
  1304. * Creates a (compressed) Tar archive
  1305. *
  1306. * @package Archive_Tar
  1307. * @author Vincent Blavet <vincent@phpconcept.net>
  1308. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  1309. * @version $Revision$
  1310. */
  1311. class Archive_Tar extends PEAR
  1312. {
  1313. /**
  1314. * @var string Name of the Tar
  1315. */
  1316. public $_tarname = '';
  1317. /**
  1318. * @var boolean if true, the Tar file will be gzipped
  1319. */
  1320. public $_compress = false;
  1321. /**
  1322. * @var string Type of compression : 'none', 'gz', 'bz2' or 'lzma2'
  1323. */
  1324. public $_compress_type = 'none';
  1325. /**
  1326. * @var string Explode separator
  1327. */
  1328. public $_separator = ' ';
  1329. /**
  1330. * @var file descriptor
  1331. */
  1332. public $_file = 0;
  1333. /**
  1334. * @var string Local Tar name of a remote Tar (http:// or ftp://)
  1335. */
  1336. public $_temp_tarname = '';
  1337. /**
  1338. * @var string regular expression for ignoring files or directories
  1339. */
  1340. public $_ignore_regexp = '';
  1341. /**
  1342. * @var object PEAR_Error object
  1343. */
  1344. public $error_object = null;
  1345. /**
  1346. * Format for data extraction
  1347. *
  1348. * @var string
  1349. */
  1350. public $_fmt = '';
  1351. /**
  1352. * @var int Length of the read buffer in bytes
  1353. */
  1354. protected $buffer_length;
  1355. /**
  1356. * Archive_Tar Class constructor. This flavour of the constructor only
  1357. * declare a new Archive_Tar object, identifying it by the name of the
  1358. * tar file.
  1359. * If the compress argument is set the tar will be read or created as a
  1360. * gzip or bz2 compressed TAR file.
  1361. *
  1362. * @param string $p_tarname The name of the tar archive to create
  1363. * @param string $p_compress can be null, 'gz', 'bz2' or 'lzma2'. This
  1364. * parameter indicates if gzip, bz2 or lzma2 compression
  1365. * is required. For compatibility reason the
  1366. * boolean value 'true' means 'gz'.
  1367. * @param int $buffer_length Length of the read buffer in bytes
  1368. *
  1369. * @return bool
  1370. */
  1371. public function __construct($p_tarname, $p_compress = null, $buffer_length = 512)
  1372. {
  1373. parent::__construct();
  1374. $this->_compress = false;
  1375. $this->_compress_type = 'none';
  1376. if (($p_compress === null) || ($p_compress == '')) {
  1377. if (@file_exists($p_tarname)) {
  1378. if ($fp = @fopen($p_tarname, "rb")) {
  1379. // look for gzip magic cookie
  1380. $data = fread($fp, 2);
  1381. fclose($fp);
  1382. if ($data == "\37\213") {
  1383. $this->_compress = true;
  1384. $this->_compress_type = 'gz';
  1385. // No sure it's enought for a magic code ....
  1386. } elseif ($data == "BZ") {
  1387. $this->_compress = true;
  1388. $this->_compress_type = 'bz2';
  1389. } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
  1390. $this->_compress = true;
  1391. $this->_compress_type = 'lzma2';
  1392. }
  1393. }
  1394. } else {
  1395. // probably a remote file or some file accessible
  1396. // through a stream interface
  1397. if (substr($p_tarname, -2) == 'gz') {
  1398. $this->_compress = true;
  1399. $this->_compress_type = 'gz';
  1400. } elseif ((substr($p_tarname, -3) == 'bz2') ||
  1401. (substr($p_tarname, -2) == 'bz')
  1402. ) {
  1403. $this->_compress = true;
  1404. $this->_compress_type = 'bz2';
  1405. } else {
  1406. if (substr($p_tarname, -2) == 'xz') {
  1407. $this->_compress = true;
  1408. $this->_compress_type = 'lzma2';
  1409. }
  1410. }
  1411. }
  1412. } else {
  1413. if (($p_compress === true) || ($p_compress == 'gz')) {
  1414. $this->_compress = true;
  1415. $this->_compress_type = 'gz';
  1416. } else {
  1417. if ($p_compress == 'bz2') {
  1418. $this->_compress = true;
  1419. $this->_compress_type = 'bz2';
  1420. } else {
  1421. if ($p_compress == 'lzma2') {
  1422. $this->_compress = true;
  1423. $this->_compress_type = 'lzma2';
  1424. } else {
  1425. $this->_error(
  1426. "Unsupported compression type '$p_compress'\n" .
  1427. "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
  1428. );
  1429. return false;
  1430. }
  1431. }
  1432. }
  1433. }
  1434. $this->_tarname = $p_tarname;
  1435. if ($this->_compress) { // assert zlib or bz2 or xz extension support
  1436. if ($this->_compress_type == 'gz') {
  1437. $extname = 'zlib';
  1438. } else {
  1439. if ($this->_compress_type == 'bz2') {
  1440. $extname = 'bz2';
  1441. } else {
  1442. if ($this->_compress_type == 'lzma2') {
  1443. $extname = 'xz';
  1444. }
  1445. }
  1446. }
  1447. if (!extension_loaded($extname)) {
  1448. PEAR::loadExtension($extname);
  1449. }
  1450. if (!extension_loaded($extname)) {
  1451. $this->_error(
  1452. "The extension '$extname' couldn't be found.\n" .
  1453. "Please make sure your version of PHP was built " .
  1454. "with '$extname' support.\n"
  1455. );
  1456. return false;
  1457. }
  1458. }
  1459. if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
  1460. $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
  1461. "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
  1462. "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
  1463. } else {
  1464. $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
  1465. "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
  1466. "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
  1467. }
  1468. $this->buffer_length = $buffer_length;
  1469. }
  1470. public function __destruct()
  1471. {
  1472. $this->_close();
  1473. // ----- Look for a local copy to delete
  1474. if ($this->_temp_tarname != '') {
  1475. @unlink($this->_temp_tarname);
  1476. }
  1477. }
  1478. /**
  1479. * This method creates the archive file and add the files / directories
  1480. * that are listed in $p_filelist.
  1481. * If a file with the same name exist and is writable, it is replaced
  1482. * by the new tar.
  1483. * The method return false and a PEAR error text.
  1484. * The $p_filelist parameter can be an array of string, each string
  1485. * representing a filename or a directory name with their path if
  1486. * needed. It can also be a single string with names separated by a
  1487. * single blank.
  1488. * For each directory added in the archive, the files and
  1489. * sub-directories are also added.
  1490. * See also createModify() method for more details.
  1491. *
  1492. * @param array $p_filelist An array of filenames and directory names, or a
  1493. * single string with names separated by a single
  1494. * blank space.
  1495. *
  1496. * @return true on success, false on error.
  1497. * @see createModify()
  1498. */
  1499. public function create($p_filelist)
  1500. {
  1501. return $this->createModify($p_filelist, '', '');
  1502. }
  1503. /**
  1504. * This method add the files / directories that are listed in $p_filelist in
  1505. * the archive. If the archive does not exist it is created.
  1506. * The method return false and a PEAR error text.
  1507. * The files and directories listed are only added at the end of the archive,
  1508. * even if a file with the same name is already archived.
  1509. * See also createModify() method for more details.
  1510. *
  1511. * @param array $p_filelist An array of filenames and directory names, or a
  1512. * single string with names separated by a single
  1513. * blank space.
  1514. *
  1515. * @return true on success, false on error.
  1516. * @see createModify()
  1517. * @access public
  1518. */
  1519. public function add($p_filelist)
  1520. {
  1521. return $this->addModify($p_filelist, '', '');
  1522. }
  1523. /**
  1524. * @param string $p_path
  1525. * @param bool $p_preserve
  1526. * @return bool
  1527. */
  1528. public function extract($p_path = '', $p_preserve = false)
  1529. {
  1530. return $this->extractModify($p_path, '', $p_preserve);
  1531. }
  1532. /**
  1533. * @return array|int
  1534. */
  1535. public function listContent()
  1536. {
  1537. $v_list_detail = array();
  1538. if ($this->_openRead()) {
  1539. if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  1540. unset($v_list_detail);
  1541. $v_list_detail = 0;
  1542. }
  1543. $this->_close();
  1544. }
  1545. return $v_list_detail;
  1546. }
  1547. /**
  1548. * This method creates the archive file and add the files / directories
  1549. * that are listed in $p_filelist.
  1550. * If the file already exists and is writable, it is replaced by the
  1551. * new tar. It is a create and not an add. If the file exists and is
  1552. * read-only or is a directory it is not replaced. The method return
  1553. * false and a PEAR error text.
  1554. * The $p_filelist parameter can be an array of string, each string
  1555. * representing a filename or a directory name with their path if
  1556. * needed. It can also be a single string with names separated by a
  1557. * single blank.
  1558. * The path indicated in $p_remove_dir will be removed from the
  1559. * memorized path of each file / directory listed when this path
  1560. * exists. By default nothing is removed (empty path '')
  1561. * The path indicated in $p_add_dir will be added at the beginning of
  1562. * the memorized path of each file / directory listed. However it can
  1563. * be set to empty ''. The adding of a path is done after the removing
  1564. * of path.
  1565. * The path add/remove ability enables the user to prepare an archive
  1566. * for extraction in a different path than the origin files are.
  1567. * See also addModify() method for file adding properties.
  1568. *
  1569. * @param array $p_filelist An array of filenames and directory names,
  1570. * or a single string with names separated by
  1571. * a single blank space.
  1572. * @param string $p_add_dir A string which contains a path to be added
  1573. * to the memorized path of each element in
  1574. * the list.
  1575. * @param string $p_remove_dir A string which contains a path to be
  1576. * removed from the memorized path of each
  1577. * element in the list, when relevant.
  1578. *
  1579. * @return boolean true on success, false on error.
  1580. * @see addModify()
  1581. */
  1582. public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
  1583. {
  1584. $v_result = true;
  1585. if (!$this->_openWrite()) {
  1586. return false;
  1587. }
  1588. if ($p_filelist != '') {
  1589. if (is_array($p_filelist)) {
  1590. $v_list = $p_filelist;
  1591. } elseif (is_string($p_filelist)) {
  1592. $v_list = explode($this->_separator, $p_filelist);
  1593. } else {
  1594. $this->_cleanFile();
  1595. $this->_error('Invalid file list');
  1596. return false;
  1597. }
  1598. $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  1599. }
  1600. if ($v_result) {
  1601. $this->_writeFooter();
  1602. $this->_close();
  1603. } else {
  1604. $this->_cleanFile();
  1605. }
  1606. return $v_result;
  1607. }
  1608. /**
  1609. * This method add the files / directories listed in $p_filelist at the
  1610. * end of the existing archive. If the archive does not yet exists it
  1611. * is created.
  1612. * The $p_filelist parameter can be an array of string, each string
  1613. * representing a filename or a directory name with their path if
  1614. * needed. It can also be a single string with names separated by a
  1615. * single blank.
  1616. * The path indicated in $p_remove_dir will be removed from the
  1617. * memorized path of each file / directory listed when this path
  1618. * exists. By default nothing is removed (empty path '')
  1619. * The path indicated in $p_add_dir will be added at the beginning of
  1620. * the memorized path of each file / directory listed. However it can
  1621. * be set to empty ''. The adding of a path is done after the removing
  1622. * of path.
  1623. * The path add/remove ability enables the user to prepare an archive
  1624. * for extraction in a different path than the origin files are.
  1625. * If a file/dir is already in the archive it will only be added at the
  1626. * end of the archive. There is no update of the existing archived
  1627. * file/dir. However while extracting the archive, the last file will
  1628. * replace the first one. This results in a none optimization of the
  1629. * archive size.
  1630. * If a file/dir does not exist the file/dir is ignored. However an
  1631. * error text is send to PEAR error.
  1632. * If a file/dir is not readable the file/dir is ignored. However an
  1633. * error text is send to PEAR error.
  1634. *
  1635. * @param array $p_filelist An array of filenames and directory
  1636. * names, or a single string with names
  1637. * separated by a single blank space.
  1638. * @param string $p_add_dir A string which contains a path to be
  1639. * added to the memorized path of each
  1640. * element in the list.
  1641. * @param string $p_remove_dir A string which contains a path to be
  1642. * removed from the memorized path of
  1643. * each element in the list, when
  1644. * relevant.
  1645. *
  1646. * @return true on success, false on error.
  1647. */
  1648. public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
  1649. {
  1650. $v_result = true;
  1651. if (!$this->_isArchive()) {
  1652. $v_result = $this->createModify(
  1653. $p_filelist,
  1654. $p_add_dir,
  1655. $p_remove_dir
  1656. );
  1657. } else {
  1658. if (is_array($p_filelist)) {
  1659. $v_list = $p_filelist;
  1660. } elseif (is_string($p_filelist)) {
  1661. $v_list = explode($this->_separator, $p_filelist);
  1662. } else {
  1663. $this->_error('Invalid file list');
  1664. return false;
  1665. }
  1666. $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  1667. }
  1668. return $v_result;
  1669. }
  1670. /**
  1671. * This method add a single string as a file at the
  1672. * end of the existing archive. If the archive does not yet exists it
  1673. * is created.
  1674. *
  1675. * @param string $p_filename A string which contains the full
  1676. * filename path that will be associated
  1677. * with the string.
  1678. * @param string $p_string The content of the file added in
  1679. * the archive.
  1680. * @param bool|int $p_datetime A custom date/time (unix timestamp)
  1681. * for the file (optional).
  1682. * @param array $p_params An array of optional params:
  1683. * stamp => the datetime (replaces
  1684. * datetime above if it exists)
  1685. * mode => the permissions on the
  1686. * file (600 by default)
  1687. * type => is this a link? See the
  1688. * tar specification for details.
  1689. * (default = regular file)
  1690. * uid => the user ID of the file
  1691. * (default = 0 = root)
  1692. * gid => the group ID of the file
  1693. * (default = 0 = root)
  1694. *
  1695. * @return true on success, false on error.
  1696. */
  1697. public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
  1698. {
  1699. $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
  1700. $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
  1701. $p_type = @$p_params["type"] ? $p_params["type"] : "";
  1702. $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
  1703. $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
  1704. $v_result = true;
  1705. if (!$this->_isArchive()) {
  1706. if (!$this->_openWrite()) {
  1707. return false;
  1708. }
  1709. $this->_close();
  1710. }
  1711. if (!$this->_openAppend()) {
  1712. return false;
  1713. }
  1714. // Need to check the get back to the temporary file ? ....
  1715. $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
  1716. $this->_writeFooter();
  1717. $this->_close();
  1718. return $v_result;
  1719. }
  1720. /**
  1721. * This method extract all the content of the archive in the directory
  1722. * indicated by $p_path. When relevant the memorized path of the
  1723. * files/dir can be modified by removing the $p_remove_path path at the
  1724. * beginning of the file/dir path.
  1725. * While extracting a file, if the directory path does not exists it is
  1726. * created.
  1727. * While extracting a file, if the file already exists it is replaced
  1728. * without looking for last modification date.
  1729. * While extracting a file, if the file already exists and is write
  1730. * protected, the extraction is aborted.
  1731. * While extracting a file, if a directory with the same name already
  1732. * exists, the extraction is aborted.
  1733. * While extracting a directory, if a file with the same name already
  1734. * exists, the extraction is aborted.
  1735. * While extracting a file/directory if the destination directory exist
  1736. * and is write protected, or does not exist but can not be created,
  1737. * the extraction is aborted.
  1738. * If after extraction an extracted file does not show the correct
  1739. * stored file size, the extraction is aborted.
  1740. * When the extraction is aborted, a PEAR error text is set and false
  1741. * is returned. However the result can be a partial extraction that may
  1742. * need to be manually cleaned.
  1743. *
  1744. * @param string $p_path The path of the directory where the
  1745. * files/dir need to by extracted.
  1746. * @param string $p_remove_path Part of the memorized path that can be
  1747. * removed if present at the beginning of
  1748. * the file/dir path.
  1749. * @param boolean $p_preserve Preserve user/group ownership of files
  1750. *
  1751. * @return boolean true on success, false on error.
  1752. * @see extractList()
  1753. */
  1754. public function extractModify($p_path, $p_remove_path, $p_preserve = false)
  1755. {
  1756. $v_result = true;
  1757. $v_list_detail = array();
  1758. if ($v_result = $this->_openRead()) {
  1759. $v_result = $this->_extractList(
  1760. $p_path,
  1761. $v_list_detail,
  1762. "complete",
  1763. 0,
  1764. $p_remove_path,
  1765. $p_preserve
  1766. );
  1767. $this->_close();
  1768. }
  1769. return $v_result;
  1770. }
  1771. /**
  1772. * This method extract from the archive one file identified by $p_filename.
  1773. * The return value is a string with the file content, or NULL on error.
  1774. *
  1775. * @param string $p_filename The path of the file to extract in a string.
  1776. *
  1777. * @return a string with the file content or NULL.
  1778. */
  1779. public function extractInString($p_filename)
  1780. {
  1781. if ($this->_openRead()) {
  1782. $v_result = $this->_extractInString($p_filename);
  1783. $this->_close();
  1784. } else {
  1785. $v_result = null;
  1786. }
  1787. return $v_result;
  1788. }
  1789. /**
  1790. * This method extract from the archive only the files indicated in the
  1791. * $p_filelist. These files are extracted in the current directory or
  1792. * in the directory indicated by the optional $p_path parameter.
  1793. * If indicated the $p_remove_path can be used in the same way as it is
  1794. * used in extractModify() method.
  1795. *
  1796. * @param array $p_filelist An array of filenames and directory names,
  1797. * or a single string with names separated
  1798. * by a single blank space.
  1799. * @param string $p_path The path of the directory where the
  1800. * files/dir need to by extracted.
  1801. * @param string $p_remove_path Part of the memorized path that can be
  1802. * removed if present at the beginning of
  1803. * the file/dir path.
  1804. * @param boolean $p_preserve Preserve user/group ownership of files
  1805. *
  1806. * @return true on success, false on error.
  1807. * @see extractModify()
  1808. */
  1809. public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false)
  1810. {
  1811. $v_result = true;
  1812. $v_list_detail = array();
  1813. if (is_array($p_filelist)) {
  1814. $v_list = $p_filelist;
  1815. } elseif (is_string($p_filelist)) {
  1816. $v_list = explode($this->_separator, $p_filelist);
  1817. } else {
  1818. $this->_error('Invalid string list');
  1819. return false;
  1820. }
  1821. if ($v_result = $this->_openRead()) {
  1822. $v_result = $this->_extractList(
  1823. $p_path,
  1824. $v_list_detail,
  1825. "partial",
  1826. $v_list,
  1827. $p_remove_path,
  1828. $p_preserve
  1829. );
  1830. $this->_close();
  1831. }
  1832. return $v_result;
  1833. }
  1834. /**
  1835. * This method set specific attributes of the archive. It uses a variable
  1836. * list of parameters, in the format attribute code + attribute values :
  1837. * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  1838. *
  1839. * @return true on success, false on error.
  1840. */
  1841. public function setAttribute()
  1842. {
  1843. $v_result = true;
  1844. // ----- Get the number of variable list of arguments
  1845. if (($v_size = func_num_args()) == 0) {
  1846. return true;
  1847. }
  1848. // ----- Get the arguments
  1849. $v_att_list = func_get_args();
  1850. // ----- Read the attributes
  1851. $i = 0;
  1852. while ($i < $v_size) {
  1853. // ----- Look for next option
  1854. switch ($v_att_list[$i]) {
  1855. // ----- Look for options that request a string value
  1856. case ARCHIVE_TAR_ATT_SEPARATOR :
  1857. // ----- Check the number of parameters
  1858. if (($i + 1) >= $v_size) {
  1859. $this->_error(
  1860. 'Invalid number of parameters for '
  1861. . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
  1862. );
  1863. return false;
  1864. }
  1865. // ----- Get the value
  1866. $this->_separator = $v_att_list[$i + 1];
  1867. $i++;
  1868. break;
  1869. default :
  1870. $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
  1871. return false;
  1872. }
  1873. // ----- Next attribute
  1874. $i++;
  1875. }
  1876. return $v_result;
  1877. }
  1878. /**
  1879. * This method sets the regular expression for ignoring files and directories
  1880. * at import, for example:
  1881. * $arch->setIgnoreRegexp("#CVS|\.svn#");
  1882. *
  1883. * @param string $regexp regular expression defining which files or directories to ignore
  1884. */
  1885. public function setIgnoreRegexp($regexp)
  1886. {
  1887. $this->_ignore_regexp = $regexp;
  1888. }
  1889. /**
  1890. * This method sets the regular expression for ignoring all files and directories
  1891. * matching the filenames in the array list at import, for example:
  1892. * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
  1893. *
  1894. * @param array $list a list of file or directory names to ignore
  1895. *
  1896. * @access public
  1897. */
  1898. public function setIgnoreList($list)
  1899. {
  1900. $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
  1901. $regexp = '#/' . join('$|/', $list) . '#';
  1902. $this->setIgnoreRegexp($regexp);
  1903. }
  1904. /**
  1905. * @param string $p_message
  1906. */
  1907. public function _error($p_message)
  1908. {
  1909. $this->error_object = $this->raiseError($p_message);
  1910. }
  1911. /**
  1912. * @param string $p_message
  1913. */
  1914. public function _warning($p_message)
  1915. {
  1916. $this->error_object = $this->raiseError($p_message);
  1917. }
  1918. /**
  1919. * @param string $p_filename
  1920. * @return bool
  1921. */
  1922. public function _isArchive($p_filename = null)
  1923. {
  1924. if ($p_filename == null) {
  1925. $p_filename = $this->_tarname;
  1926. }
  1927. clearstatcache();
  1928. return @is_file($p_filename) && !@is_link($p_filename);
  1929. }
  1930. /**
  1931. * @return bool
  1932. */
  1933. public function _openWrite()
  1934. {
  1935. if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
  1936. $this->_file = @gzopen($this->_tarname, "wb9");
  1937. } else {
  1938. if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
  1939. $this->_file = @bzopen($this->_tarname, "w");
  1940. } else {
  1941. if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
  1942. $this->_file = @xzopen($this->_tarname, 'w');
  1943. } else {
  1944. if ($this->_compress_type == 'none') {
  1945. $this->_file = @fopen($this->_tarname, "wb");
  1946. } else {
  1947. $this->_error(
  1948. 'Unknown or missing compression type ('
  1949. . $this->_compress_type . ')'
  1950. );
  1951. return false;
  1952. }
  1953. }
  1954. }
  1955. }
  1956. if ($this->_file == 0) {
  1957. $this->_error(
  1958. 'Unable to open in write mode \''
  1959. . $this->_tarname . '\''
  1960. );
  1961. return false;
  1962. }
  1963. return true;
  1964. }
  1965. /**
  1966. * @return bool
  1967. */
  1968. public function _openRead()
  1969. {
  1970. if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  1971. // ----- Look if a local copy need to be done
  1972. if ($this->_temp_tarname == '') {
  1973. $this->_temp_tarname = uniqid('tar') . '.tmp';
  1974. if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  1975. $this->_error(
  1976. 'Unable to open in read mode \''
  1977. . $this->_tarname . '\''
  1978. );
  1979. $this->_temp_tarname = '';
  1980. return false;
  1981. }
  1982. if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  1983. $this->_error(
  1984. 'Unable to open in write mode \''
  1985. . $this->_temp_tarname . '\''
  1986. );
  1987. $this->_temp_tarname = '';
  1988. return false;
  1989. }
  1990. while ($v_data = @fread($v_file_from, 1024)) {
  1991. @fwrite($v_file_to, $v_data);
  1992. }
  1993. @fclose($v_file_from);
  1994. @fclose($v_file_to);
  1995. }
  1996. // ----- File to open if the local copy
  1997. $v_filename = $this->_temp_tarname;
  1998. } else {
  1999. // ----- File to open if the normal Tar file
  2000. $v_filename = $this->_tarname;
  2001. }
  2002. if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
  2003. $this->_file = @gzopen($v_filename, "rb");
  2004. } else {
  2005. if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
  2006. $this->_file = @bzopen($v_filename, "r");
  2007. } else {
  2008. if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
  2009. $this->_file = @xzopen($v_filename, "r");
  2010. } else {
  2011. if ($this->_compress_type == 'none') {
  2012. $this->_file = @fopen($v_filename, "rb");
  2013. } else {
  2014. $this->_error(
  2015. 'Unknown or missing compression type ('
  2016. . $this->_compress_type . ')'
  2017. );
  2018. return false;
  2019. }
  2020. }
  2021. }
  2022. }
  2023. if ($this->_file == 0) {
  2024. $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
  2025. return false;
  2026. }
  2027. return true;
  2028. }
  2029. /**
  2030. * @return bool
  2031. */
  2032. public function _openReadWrite()
  2033. {
  2034. if ($this->_compress_type == 'gz') {
  2035. $this->_file = @gzopen($this->_tarname, "r+b");
  2036. } else {
  2037. if ($this->_compress_type == 'bz2') {
  2038. $this->_error(
  2039. 'Unable to open bz2 in read/write mode \''
  2040. . $this->_tarname . '\' (limitation of bz2 extension)'
  2041. );
  2042. return false;
  2043. } else {
  2044. if ($this->_compress_type == 'lzma2') {
  2045. $this->_error(
  2046. 'Unable to open lzma2 in read/write mode \''
  2047. . $this->_tarname . '\' (limitation of lzma2 extension)'
  2048. );
  2049. return false;
  2050. } else {
  2051. if ($this->_compress_type == 'none') {
  2052. $this->_file = @fopen($this->_tarname, "r+b");
  2053. } else {
  2054. $this->_error(
  2055. 'Unknown or missing compression type ('
  2056. . $this->_compress_type . ')'
  2057. );
  2058. return false;
  2059. }
  2060. }
  2061. }
  2062. }
  2063. if ($this->_file == 0) {
  2064. $this->_error(
  2065. 'Unable to open in read/write mode \''
  2066. . $this->_tarname . '\''
  2067. );
  2068. return false;
  2069. }
  2070. return true;
  2071. }
  2072. /**
  2073. * @return bool
  2074. */
  2075. public function _close()
  2076. {
  2077. //if (isset($this->_file)) {
  2078. if (is_resource($this->_file)) {
  2079. if ($this->_compress_type == 'gz') {
  2080. @gzclose($this->_file);
  2081. } else {
  2082. if ($this->_compress_type == 'bz2') {
  2083. @bzclose($this->_file);
  2084. } else {
  2085. if ($this->_compress_type == 'lzma2') {
  2086. @xzclose($this->_file);
  2087. } else {
  2088. if ($this->_compress_type == 'none') {
  2089. @fclose($this->_file);
  2090. } else {
  2091. $this->_error(
  2092. 'Unknown or missing compression type ('
  2093. . $this->_compress_type . ')'
  2094. );
  2095. }
  2096. }
  2097. }
  2098. }
  2099. $this->_file = 0;
  2100. }
  2101. // ----- Look if a local copy need to be erase
  2102. // Note that it might be interesting to keep the url for a time : ToDo
  2103. if ($this->_temp_tarname != '') {
  2104. @unlink($this->_temp_tarname);
  2105. $this->_temp_tarname = '';
  2106. }
  2107. return true;
  2108. }
  2109. /**
  2110. * @return bool
  2111. */
  2112. public function _cleanFile()
  2113. {
  2114. $this->_close();
  2115. // ----- Look for a local copy
  2116. if ($this->_temp_tarname != '') {
  2117. // ----- Remove the local copy but not the remote tarname
  2118. @unlink($this->_temp_tarname);
  2119. $this->_temp_tarname = '';
  2120. } else {
  2121. // ----- Remove the local tarname file
  2122. @unlink($this->_tarname);
  2123. }
  2124. $this->_tarname = '';
  2125. return true;
  2126. }
  2127. /**
  2128. * @param mixed $p_binary_data
  2129. * @param integer $p_len
  2130. * @return bool
  2131. */
  2132. public function _writeBlock($p_binary_data, $p_len = null)
  2133. {
  2134. if (is_resource($this->_file)) {
  2135. if ($p_len === null) {
  2136. if ($this->_compress_type == 'gz') {
  2137. @gzputs($this->_file, $p_binary_data);
  2138. } else {
  2139. if ($this->_compress_type == 'bz2') {
  2140. @bzwrite($this->_file, $p_binary_data);
  2141. } else {
  2142. if ($this->_compress_type == 'lzma2') {
  2143. @xzwrite($this->_file, $p_binary_data);
  2144. } else {
  2145. if ($this->_compress_type == 'none') {
  2146. @fputs($this->_file, $p_binary_data);
  2147. } else {
  2148. $this->_error(
  2149. 'Unknown or missing compression type ('
  2150. . $this->_compress_type . ')'
  2151. );
  2152. }
  2153. }
  2154. }
  2155. }
  2156. } else {
  2157. if ($this->_compress_type == 'gz') {
  2158. @gzputs($this->_file, $p_binary_data, $p_len);
  2159. } else {
  2160. if ($this->_compress_type == 'bz2') {
  2161. @bzwrite($this->_file, $p_binary_data, $p_len);
  2162. } else {
  2163. if ($this->_compress_type == 'lzma2') {
  2164. @xzwrite($this->_file, $p_binary_data, $p_len);
  2165. } else {
  2166. if ($this->_compress_type == 'none') {
  2167. @fputs($this->_file, $p_binary_data, $p_len);
  2168. } else {
  2169. $this->_error(
  2170. 'Unknown or missing compression type ('
  2171. . $this->_compress_type . ')'
  2172. );
  2173. }
  2174. }
  2175. }
  2176. }
  2177. }
  2178. }
  2179. return true;
  2180. }
  2181. /**
  2182. * @return null|string
  2183. */
  2184. public function _readBlock()
  2185. {
  2186. $v_block = null;
  2187. if (is_resource($this->_file)) {
  2188. if ($this->_compress_type == 'gz') {
  2189. $v_block = @gzread($this->_file, 512);
  2190. } else {
  2191. if ($this->_compress_type == 'bz2') {
  2192. $v_block = @bzread($this->_file, 512);
  2193. } else {
  2194. if ($this->_compress_type == 'lzma2') {
  2195. $v_block = @xzread($this->_file, 512);
  2196. } else {
  2197. if ($this->_compress_type == 'none') {
  2198. $v_block = @fread($this->_file, 512);
  2199. } else {
  2200. $this->_error(
  2201. 'Unknown or missing compression type ('
  2202. . $this->_compress_type . ')'
  2203. );
  2204. }
  2205. }
  2206. }
  2207. }
  2208. }
  2209. return $v_block;
  2210. }
  2211. /**
  2212. * @param null $p_len
  2213. * @return bool
  2214. */
  2215. public function _jumpBlock($p_len = null)
  2216. {
  2217. if (is_resource($this->_file)) {
  2218. if ($p_len === null) {
  2219. $p_len = 1;
  2220. }
  2221. if ($this->_compress_type == 'gz') {
  2222. @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
  2223. } else {
  2224. if ($this->_compress_type == 'bz2') {
  2225. // ----- Replace missing bztell() and bzseek()
  2226. for ($i = 0; $i < $p_len; $i++) {
  2227. $this->_readBlock();
  2228. }
  2229. } else {
  2230. if ($this->_compress_type == 'lzma2') {
  2231. // ----- Replace missing xztell() and xzseek()
  2232. for ($i = 0; $i < $p_len; $i++) {
  2233. $this->_readBlock();
  2234. }
  2235. } else {
  2236. if ($this->_compress_type == 'none') {
  2237. @fseek($this->_file, $p_len * 512, SEEK_CUR);
  2238. } else {
  2239. $this->_error(
  2240. 'Unknown or missing compression type ('
  2241. . $this->_compress_type . ')'
  2242. );
  2243. }
  2244. }
  2245. }
  2246. }
  2247. }
  2248. return true;
  2249. }
  2250. /**
  2251. * @return bool
  2252. */
  2253. public function _writeFooter()
  2254. {
  2255. if (is_resource($this->_file)) {
  2256. // ----- Write the last 0 filled block for end of archive
  2257. $v_binary_data = pack('a1024', '');
  2258. $this->_writeBlock($v_binary_data);
  2259. }
  2260. return true;
  2261. }
  2262. /**
  2263. * @param array $p_list
  2264. * @param string $p_add_dir
  2265. * @param string $p_remove_dir
  2266. * @return bool
  2267. */
  2268. public function _addList($p_list, $p_add_dir, $p_remove_dir)
  2269. {
  2270. $v_result = true;
  2271. $v_header = array();
  2272. // ----- Remove potential windows directory separator
  2273. $p_add_dir = $this->_translateWinPath($p_add_dir);
  2274. $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  2275. if (!$this->_file) {
  2276. $this->_error('Invalid file descriptor');
  2277. return false;
  2278. }
  2279. if (sizeof($p_list) == 0) {
  2280. return true;
  2281. }
  2282. foreach ($p_list as $v_filename) {
  2283. if (!$v_result) {
  2284. break;
  2285. }
  2286. // ----- Skip the current tar name
  2287. if ($v_filename == $this->_tarname) {
  2288. continue;
  2289. }
  2290. if ($v_filename == '') {
  2291. continue;
  2292. }
  2293. // ----- ignore files and directories matching the ignore regular expression
  2294. if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
  2295. $this->_warning("File '$v_filename' ignored");
  2296. continue;
  2297. }
  2298. if (!file_exists($v_filename) && !is_link($v_filename)) {
  2299. $this->_warning("File '$v_filename' does not exist");
  2300. continue;
  2301. }
  2302. // ----- Add the file or directory header
  2303. if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
  2304. return false;
  2305. }
  2306. if (@is_dir($v_filename) && !@is_link($v_filename)) {
  2307. if (!($p_hdir = opendir($v_filename))) {
  2308. $this->_warning("Directory '$v_filename' can not be read");
  2309. continue;
  2310. }
  2311. while (false !== ($p_hitem = readdir($p_hdir))) {
  2312. if (($p_hitem != '.') && ($p_hitem != '..')) {
  2313. if ($v_filename != ".") {
  2314. $p_temp_list[0] = $v_filename . '/' . $p_hitem;
  2315. } else {
  2316. $p_temp_list[0] = $p_hitem;
  2317. }
  2318. $v_result = $this->_addList(
  2319. $p_temp_list,
  2320. $p_add_dir,
  2321. $p_remove_dir
  2322. );
  2323. }
  2324. }
  2325. unset($p_temp_list);
  2326. unset($p_hdir);
  2327. unset($p_hitem);
  2328. }
  2329. }
  2330. return $v_result;
  2331. }
  2332. /**
  2333. * @param string $p_filename
  2334. * @param mixed $p_header
  2335. * @param string $p_add_dir
  2336. * @param string $p_remove_dir
  2337. * @param null $v_stored_filename
  2338. * @return bool
  2339. */
  2340. public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
  2341. {
  2342. if (!$this->_file) {
  2343. $this->_error('Invalid file descriptor');
  2344. return false;
  2345. }
  2346. if ($p_filename == '') {
  2347. $this->_error('Invalid file name');
  2348. return false;
  2349. }
  2350. if (is_null($v_stored_filename)) {
  2351. // ----- Calculate the stored filename
  2352. $p_filename = $this->_translateWinPath($p_filename, false);
  2353. $v_stored_filename = $p_filename;
  2354. if (strcmp($p_filename, $p_remove_dir) == 0) {
  2355. return true;
  2356. }
  2357. if ($p_remove_dir != '') {
  2358. if (substr($p_remove_dir, -1) != '/') {
  2359. $p_remove_dir .= '/';
  2360. }
  2361. if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
  2362. $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  2363. }
  2364. }
  2365. $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  2366. if ($p_add_dir != '') {
  2367. if (substr($p_add_dir, -1) == '/') {
  2368. $v_stored_filename = $p_add_dir . $v_stored_filename;
  2369. } else {
  2370. $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
  2371. }
  2372. }
  2373. $v_stored_filename = $this->_pathReduction($v_stored_filename);
  2374. }
  2375. if ($this->_isArchive($p_filename)) {
  2376. if (($v_file = @fopen($p_filename, "rb")) == 0) {
  2377. $this->_warning(
  2378. "Unable to open file '" . $p_filename
  2379. . "' in binary read mode"
  2380. );
  2381. return true;
  2382. }
  2383. if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
  2384. return false;
  2385. }
  2386. while (($v_buffer = fread($v_file, $this->buffer_length)) != '') {
  2387. $buffer_length = strlen("$v_buffer");
  2388. if ($buffer_length != $this->buffer_length) {
  2389. $pack_size = ((int)($buffer_length / 512) + 1) * 512;
  2390. $pack_format = sprintf('a%d', $pack_size);
  2391. } else {
  2392. $pack_format = sprintf('a%d', $this->buffer_length);
  2393. }
  2394. $v_binary_data = pack($pack_format, "$v_buffer");
  2395. $this->_writeBlock($v_binary_data);
  2396. }
  2397. fclose($v_file);
  2398. } else {
  2399. // ----- Only header for dir
  2400. if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
  2401. return false;
  2402. }
  2403. }
  2404. return true;
  2405. }
  2406. /**
  2407. * @param string $p_filename
  2408. * @param string $p_string
  2409. * @param bool $p_datetime
  2410. * @param array $p_params
  2411. * @return bool
  2412. */
  2413. public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
  2414. {
  2415. $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
  2416. $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
  2417. $p_type = @$p_params["type"] ? $p_params["type"] : "";
  2418. $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
  2419. $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
  2420. if (!$this->_file) {
  2421. $this->_error('Invalid file descriptor');
  2422. return false;
  2423. }
  2424. if ($p_filename == '') {
  2425. $this->_error('Invalid file name');
  2426. return false;
  2427. }
  2428. // ----- Calculate the stored filename
  2429. $p_filename = $this->_translateWinPath($p_filename, false);
  2430. // ----- If datetime is not specified, set current time
  2431. if ($p_datetime === false) {
  2432. $p_datetime = time();
  2433. }
  2434. if (!$this->_writeHeaderBlock(
  2435. $p_filename,
  2436. strlen($p_string),
  2437. $p_stamp,
  2438. $p_mode,
  2439. $p_type,
  2440. $p_uid,
  2441. $p_gid
  2442. )
  2443. ) {
  2444. return false;
  2445. }
  2446. $i = 0;
  2447. while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
  2448. $v_binary_data = pack("a512", $v_buffer);
  2449. $this->_writeBlock($v_binary_data);
  2450. }
  2451. return true;
  2452. }
  2453. /**
  2454. * @param string $p_filename
  2455. * @param string $p_stored_filename
  2456. * @return bool
  2457. */
  2458. public function _writeHeader($p_filename, $p_stored_filename)
  2459. {
  2460. if ($p_stored_filename == '') {
  2461. $p_stored_filename = $p_filename;
  2462. }
  2463. $v_reduced_filename = $this->_pathReduction($p_stored_filename);
  2464. if (strlen($v_reduced_filename) > 99) {
  2465. if (!$this->_writeLongHeader($v_reduced_filename, false)) {
  2466. return false;
  2467. }
  2468. }
  2469. $v_linkname = '';
  2470. if (@is_link($p_filename)) {
  2471. $v_linkname = readlink($p_filename);
  2472. }
  2473. if (strlen($v_linkname) > 99) {
  2474. if (!$this->_writeLongHeader($v_linkname, true)) {
  2475. return false;
  2476. }
  2477. }
  2478. $v_info = lstat($p_filename);
  2479. $v_uid = sprintf("%07s", DecOct($v_info[4]));
  2480. $v_gid = sprintf("%07s", DecOct($v_info[5]));
  2481. $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
  2482. $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
  2483. if (@is_link($p_filename)) {
  2484. $v_typeflag = '2';
  2485. $v_size = sprintf("%011s", DecOct(0));
  2486. } elseif (@is_dir($p_filename)) {
  2487. $v_typeflag = "5";
  2488. $v_size = sprintf("%011s", DecOct(0));
  2489. } else {
  2490. $v_typeflag = '0';
  2491. clearstatcache();
  2492. $v_size = sprintf("%011s", DecOct($v_info['size']));
  2493. }
  2494. $v_magic = 'ustar ';
  2495. $v_version = ' ';
  2496. if (function_exists('posix_getpwuid')) {
  2497. $userinfo = posix_getpwuid($v_info[4]);
  2498. $groupinfo = posix_getgrgid($v_info[5]);
  2499. $v_uname = $userinfo['name'];
  2500. $v_gname = $groupinfo['name'];
  2501. } else {
  2502. $v_uname = '';
  2503. $v_gname = '';
  2504. }
  2505. $v_devmajor = '';
  2506. $v_devminor = '';
  2507. $v_prefix = '';
  2508. $v_binary_data_first = pack(
  2509. "a100a8a8a8a12a12",
  2510. $v_reduced_filename,
  2511. $v_perms,
  2512. $v_uid,
  2513. $v_gid,
  2514. $v_size,
  2515. $v_mtime
  2516. );
  2517. $v_binary_data_last = pack(
  2518. "a1a100a6a2a32a32a8a8a155a12",
  2519. $v_typeflag,
  2520. $v_linkname,
  2521. $v_magic,
  2522. $v_version,
  2523. $v_uname,
  2524. $v_gname,
  2525. $v_devmajor,
  2526. $v_devminor,
  2527. $v_prefix,
  2528. ''
  2529. );
  2530. // ----- Calculate the checksum
  2531. $v_checksum = 0;
  2532. // ..... First part of the header
  2533. for ($i = 0; $i < 148; $i++) {
  2534. $v_checksum += ord(substr($v_binary_data_first, $i, 1));
  2535. }
  2536. // ..... Ignore the checksum value and replace it by ' ' (space)
  2537. for ($i = 148; $i < 156; $i++) {
  2538. $v_checksum += ord(' ');
  2539. }
  2540. // ..... Last part of the header
  2541. for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
  2542. $v_checksum += ord(substr($v_binary_data_last, $j, 1));
  2543. }
  2544. // ----- Write the first 148 bytes of the header in the archive
  2545. $this->_writeBlock($v_binary_data_first, 148);
  2546. // ----- Write the calculated checksum
  2547. $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
  2548. $v_binary_data = pack("a8", $v_checksum);
  2549. $this->_writeBlock($v_binary_data, 8);
  2550. // ----- Write the last 356 bytes of the header in the archive
  2551. $this->_writeBlock($v_binary_data_last, 356);
  2552. return true;
  2553. }
  2554. /**
  2555. * @param string $p_filename
  2556. * @param int $p_size
  2557. * @param int $p_mtime
  2558. * @param int $p_perms
  2559. * @param string $p_type
  2560. * @param int $p_uid
  2561. * @param int $p_gid
  2562. * @return bool
  2563. */
  2564. public function _writeHeaderBlock(
  2565. $p_filename,
  2566. $p_size,
  2567. $p_mtime = 0,
  2568. $p_perms = 0,
  2569. $p_type = '',
  2570. $p_uid = 0,
  2571. $p_gid = 0
  2572. )
  2573. {
  2574. $p_filename = $this->_pathReduction($p_filename);
  2575. if (strlen($p_filename) > 99) {
  2576. if (!$this->_writeLongHeader($p_filename, false)) {
  2577. return false;
  2578. }
  2579. }
  2580. if ($p_type == "5") {
  2581. $v_size = sprintf("%011s", DecOct(0));
  2582. } else {
  2583. $v_size = sprintf("%011s", DecOct($p_size));
  2584. }
  2585. $v_uid = sprintf("%07s", DecOct($p_uid));
  2586. $v_gid = sprintf("%07s", DecOct($p_gid));
  2587. $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
  2588. $v_mtime = sprintf("%11s", DecOct($p_mtime));
  2589. $v_linkname = '';
  2590. $v_magic = 'ustar ';
  2591. $v_version = ' ';
  2592. if (function_exists('posix_getpwuid')) {
  2593. $userinfo = posix_getpwuid($p_uid);
  2594. $groupinfo = posix_getgrgid($p_gid);
  2595. $v_uname = $userinfo['name'];
  2596. $v_gname = $groupinfo['name'];
  2597. } else {
  2598. $v_uname = '';
  2599. $v_gname = '';
  2600. }
  2601. $v_devmajor = '';
  2602. $v_devminor = '';
  2603. $v_prefix = '';
  2604. $v_binary_data_first = pack(
  2605. "a100a8a8a8a12A12",
  2606. $p_filename,
  2607. $v_perms,
  2608. $v_uid,
  2609. $v_gid,
  2610. $v_size,
  2611. $v_mtime
  2612. );
  2613. $v_binary_data_last = pack(
  2614. "a1a100a6a2a32a32a8a8a155a12",
  2615. $p_type,
  2616. $v_linkname,
  2617. $v_magic,
  2618. $v_version,
  2619. $v_uname,
  2620. $v_gname,
  2621. $v_devmajor,
  2622. $v_devminor,
  2623. $v_prefix,
  2624. ''
  2625. );
  2626. // ----- Calculate the checksum
  2627. $v_checksum = 0;
  2628. // ..... First part of the header
  2629. for ($i = 0; $i < 148; $i++) {
  2630. $v_checksum += ord(substr($v_binary_data_first, $i, 1));
  2631. }
  2632. // ..... Ignore the checksum value and replace it by ' ' (space)
  2633. for ($i = 148; $i < 156; $i++) {
  2634. $v_checksum += ord(' ');
  2635. }
  2636. // ..... Last part of the header
  2637. for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
  2638. $v_checksum += ord(substr($v_binary_data_last, $j, 1));
  2639. }
  2640. // ----- Write the first 148 bytes of the header in the archive
  2641. $this->_writeBlock($v_binary_data_first, 148);
  2642. // ----- Write the calculated checksum
  2643. $v_checksum = sprintf("%06s ", DecOct($v_checksum));
  2644. $v_binary_data = pack("a8", $v_checksum);
  2645. $this->_writeBlock($v_binary_data, 8);
  2646. // ----- Write the last 356 bytes of the header in the archive
  2647. $this->_writeBlock($v_binary_data_last, 356);
  2648. return true;
  2649. }
  2650. /**
  2651. * @param string $p_filename
  2652. * @return bool
  2653. */
  2654. public function _writeLongHeader($p_filename, $is_link = false)
  2655. {
  2656. $v_uid = sprintf("%07s", 0);
  2657. $v_gid = sprintf("%07s", 0);
  2658. $v_perms = sprintf("%07s", 0);
  2659. $v_size = sprintf("%'011s", DecOct(strlen($p_filename)));
  2660. $v_mtime = sprintf("%011s", 0);
  2661. $v_typeflag = ($is_link ? 'K' : 'L');
  2662. $v_linkname = '';
  2663. $v_magic = 'ustar ';
  2664. $v_version = ' ';
  2665. $v_uname = '';
  2666. $v_gname = '';
  2667. $v_devmajor = '';
  2668. $v_devminor = '';
  2669. $v_prefix = '';
  2670. $v_binary_data_first = pack(
  2671. "a100a8a8a8a12a12",
  2672. '././@LongLink',
  2673. $v_perms,
  2674. $v_uid,
  2675. $v_gid,
  2676. $v_size,
  2677. $v_mtime
  2678. );
  2679. $v_binary_data_last = pack(
  2680. "a1a100a6a2a32a32a8a8a155a12",
  2681. $v_typeflag,
  2682. $v_linkname,
  2683. $v_magic,
  2684. $v_version,
  2685. $v_uname,
  2686. $v_gname,
  2687. $v_devmajor,
  2688. $v_devminor,
  2689. $v_prefix,
  2690. ''
  2691. );
  2692. // ----- Calculate the checksum
  2693. $v_checksum = 0;
  2694. // ..... First part of the header
  2695. for ($i = 0; $i < 148; $i++) {
  2696. $v_checksum += ord(substr($v_binary_data_first, $i, 1));
  2697. }
  2698. // ..... Ignore the checksum value and replace it by ' ' (space)
  2699. for ($i = 148; $i < 156; $i++) {
  2700. $v_checksum += ord(' ');
  2701. }
  2702. // ..... Last part of the header
  2703. for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
  2704. $v_checksum += ord(substr($v_binary_data_last, $j, 1));
  2705. }
  2706. // ----- Write the first 148 bytes of the header in the archive
  2707. $this->_writeBlock($v_binary_data_first, 148);
  2708. // ----- Write the calculated checksum
  2709. $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
  2710. $v_binary_data = pack("a8", $v_checksum);
  2711. $this->_writeBlock($v_binary_data, 8);
  2712. // ----- Write the last 356 bytes of the header in the archive
  2713. $this->_writeBlock($v_binary_data_last, 356);
  2714. // ----- Write the filename as content of the block
  2715. $i = 0;
  2716. while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
  2717. $v_binary_data = pack("a512", "$v_buffer");
  2718. $this->_writeBlock($v_binary_data);
  2719. }
  2720. return true;
  2721. }
  2722. /**
  2723. * @param mixed $v_binary_data
  2724. * @param mixed $v_header
  2725. * @return bool
  2726. */
  2727. public function _readHeader($v_binary_data, &$v_header)
  2728. {
  2729. if (strlen($v_binary_data) == 0) {
  2730. $v_header['filename'] = '';
  2731. return true;
  2732. }
  2733. if (strlen($v_binary_data) != 512) {
  2734. $v_header['filename'] = '';
  2735. $this->_error('Invalid block size : ' . strlen($v_binary_data));
  2736. return false;
  2737. }
  2738. if (!is_array($v_header)) {
  2739. $v_header = array();
  2740. }
  2741. // ----- Calculate the checksum
  2742. $v_checksum = 0;
  2743. // ..... First part of the header
  2744. $v_binary_split = str_split($v_binary_data);
  2745. $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
  2746. $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
  2747. $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
  2748. $v_data = unpack($this->_fmt, $v_binary_data);
  2749. if (strlen($v_data["prefix"]) > 0) {
  2750. $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
  2751. }
  2752. // ----- Extract the checksum
  2753. $v_data_checksum = trim($v_data['checksum']);
  2754. if (!preg_match('/^[0-7]*$/', $v_data_checksum)) {
  2755. $this->_error(
  2756. 'Invalid checksum for file "' . $v_data['filename']
  2757. . '" : ' . $v_data_checksum . ' extracted'
  2758. );
  2759. return false;
  2760. }
  2761. $v_header['checksum'] = OctDec($v_data_checksum);
  2762. if ($v_header['checksum'] != $v_checksum) {
  2763. $v_header['filename'] = '';
  2764. // ----- Look for last block (empty block)
  2765. if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
  2766. return true;
  2767. }
  2768. $this->_error(
  2769. 'Invalid checksum for file "' . $v_data['filename']
  2770. . '" : ' . $v_checksum . ' calculated, '
  2771. . $v_header['checksum'] . ' expected'
  2772. );
  2773. return false;
  2774. }
  2775. // ----- Extract the properties
  2776. $v_header['filename'] = rtrim($v_data['filename'], "\0");
  2777. if ($this->_maliciousFilename($v_header['filename'])) {
  2778. $this->_error(
  2779. 'Malicious .tar detected, file "' . $v_header['filename'] .
  2780. '" will not install in desired directory tree'
  2781. );
  2782. return false;
  2783. }
  2784. $v_header['mode'] = OctDec(trim($v_data['mode']));
  2785. $v_header['uid'] = OctDec(trim($v_data['uid']));
  2786. $v_header['gid'] = OctDec(trim($v_data['gid']));
  2787. $v_header['size'] = $this->_tarRecToSize($v_data['size']);
  2788. $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  2789. if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  2790. $v_header['size'] = 0;
  2791. }
  2792. $v_header['link'] = trim($v_data['link']);
  2793. /* ----- All these fields are removed form the header because
  2794. they do not carry interesting info
  2795. $v_header[magic] = trim($v_data[magic]);
  2796. $v_header[version] = trim($v_data[version]);
  2797. $v_header[uname] = trim($v_data[uname]);
  2798. $v_header[gname] = trim($v_data[gname]);
  2799. $v_header[devmajor] = trim($v_data[devmajor]);
  2800. $v_header[devminor] = trim($v_data[devminor]);
  2801. */
  2802. return true;
  2803. }
  2804. /**
  2805. * Convert Tar record size to actual size
  2806. *
  2807. * @param string $tar_size
  2808. * @return size of tar record in bytes
  2809. */
  2810. private function _tarRecToSize($tar_size)
  2811. {
  2812. /*
  2813. * First byte of size has a special meaning if bit 7 is set.
  2814. *
  2815. * Bit 7 indicates base-256 encoding if set.
  2816. * Bit 6 is the sign bit.
  2817. * Bits 5:0 are most significant value bits.
  2818. */
  2819. $ch = ord($tar_size[0]);
  2820. if ($ch & 0x80) {
  2821. // Full 12-bytes record is required.
  2822. $rec_str = $tar_size . "\x00";
  2823. $size = ($ch & 0x40) ? -1 : 0;
  2824. $size = ($size << 6) | ($ch & 0x3f);
  2825. for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
  2826. $size = ($size * 256) + ord($rec_str[$num_ch]);
  2827. }
  2828. return $size;
  2829. } else {
  2830. return OctDec(trim($tar_size));
  2831. }
  2832. }
  2833. /**
  2834. * Detect and report a malicious file name
  2835. *
  2836. * @param string $file
  2837. *
  2838. * @return bool
  2839. */
  2840. private function _maliciousFilename($file)
  2841. {
  2842. if (strpos($file, 'phar://') === 0) {
  2843. return true;
  2844. }
  2845. if (strpos($file, '../') !== false || strpos($file, '..\\') !== false) {
  2846. return true;
  2847. }
  2848. return false;
  2849. }
  2850. /**
  2851. * @param $v_header
  2852. * @return bool
  2853. */
  2854. public function _readLongHeader(&$v_header)
  2855. {
  2856. $v_filename = '';
  2857. $v_filesize = $v_header['size'];
  2858. $n = floor($v_header['size'] / 512);
  2859. for ($i = 0; $i < $n; $i++) {
  2860. $v_content = $this->_readBlock();
  2861. $v_filename .= $v_content;
  2862. }
  2863. if (($v_header['size'] % 512) != 0) {
  2864. $v_content = $this->_readBlock();
  2865. $v_filename .= $v_content;
  2866. }
  2867. // ----- Read the next header
  2868. $v_binary_data = $this->_readBlock();
  2869. if (!$this->_readHeader($v_binary_data, $v_header)) {
  2870. return false;
  2871. }
  2872. $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
  2873. $v_header['filename'] = $v_filename;
  2874. if ($this->_maliciousFilename($v_filename)) {
  2875. $this->_error(
  2876. 'Malicious .tar detected, file "' . $v_filename .
  2877. '" will not install in desired directory tree'
  2878. );
  2879. return false;
  2880. }
  2881. return true;
  2882. }
  2883. /**
  2884. * This method extract from the archive one file identified by $p_filename.
  2885. * The return value is a string with the file content, or null on error.
  2886. *
  2887. * @param string $p_filename The path of the file to extract in a string.
  2888. *
  2889. * @return a string with the file content or null.
  2890. */
  2891. private function _extractInString($p_filename)
  2892. {
  2893. $v_result_str = "";
  2894. while (strlen($v_binary_data = $this->_readBlock()) != 0) {
  2895. if (!$this->_readHeader($v_binary_data, $v_header)) {
  2896. return null;
  2897. }
  2898. if ($v_header['filename'] == '') {
  2899. continue;
  2900. }
  2901. switch ($v_header['typeflag']) {
  2902. case 'L':
  2903. {
  2904. if (!$this->_readLongHeader($v_header)) {
  2905. return null;
  2906. }
  2907. }
  2908. break;
  2909. case 'K':
  2910. {
  2911. $v_link_header = $v_header;
  2912. if (!$this->_readLongHeader($v_link_header)) {
  2913. return null;
  2914. }
  2915. $v_header['link'] = $v_link_header['filename'];
  2916. }
  2917. break;
  2918. }
  2919. if ($v_header['filename'] == $p_filename) {
  2920. if ($v_header['typeflag'] == "5") {
  2921. $this->_error(
  2922. 'Unable to extract in string a directory '
  2923. . 'entry {' . $v_header['filename'] . '}'
  2924. );
  2925. return null;
  2926. } else {
  2927. $n = floor($v_header['size'] / 512);
  2928. for ($i = 0; $i < $n; $i++) {
  2929. $v_result_str .= $this->_readBlock();
  2930. }
  2931. if (($v_header['size'] % 512) != 0) {
  2932. $v_content = $this->_readBlock();
  2933. $v_result_str .= substr(
  2934. $v_content,
  2935. 0,
  2936. ($v_header['size'] % 512)
  2937. );
  2938. }
  2939. return $v_result_str;
  2940. }
  2941. } else {
  2942. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  2943. }
  2944. }
  2945. return null;
  2946. }
  2947. /**
  2948. * @param string $p_path
  2949. * @param string $p_list_detail
  2950. * @param string $p_mode
  2951. * @param string $p_file_list
  2952. * @param string $p_remove_path
  2953. * @param bool $p_preserve
  2954. * @return bool
  2955. */
  2956. public function _extractList(
  2957. $p_path,
  2958. &$p_list_detail,
  2959. $p_mode,
  2960. $p_file_list,
  2961. $p_remove_path,
  2962. $p_preserve = false
  2963. )
  2964. {
  2965. $v_result = true;
  2966. $v_nb = 0;
  2967. $v_extract_all = true;
  2968. $v_listing = false;
  2969. $p_path = $this->_translateWinPath($p_path, false);
  2970. if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  2971. && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
  2972. ) {
  2973. $p_path = "./" . $p_path;
  2974. }
  2975. $p_remove_path = $this->_translateWinPath($p_remove_path);
  2976. // ----- Look for path to remove format (should end by /)
  2977. if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
  2978. $p_remove_path .= '/';
  2979. }
  2980. $p_remove_path_size = strlen($p_remove_path);
  2981. switch ($p_mode) {
  2982. case "complete" :
  2983. $v_extract_all = true;
  2984. $v_listing = false;
  2985. break;
  2986. case "partial" :
  2987. $v_extract_all = false;
  2988. $v_listing = false;
  2989. break;
  2990. case "list" :
  2991. $v_extract_all = false;
  2992. $v_listing = true;
  2993. break;
  2994. default :
  2995. $this->_error('Invalid extract mode (' . $p_mode . ')');
  2996. return false;
  2997. }
  2998. clearstatcache();
  2999. while (strlen($v_binary_data = $this->_readBlock()) != 0) {
  3000. $v_extract_file = false;
  3001. $v_extraction_stopped = 0;
  3002. if (!$this->_readHeader($v_binary_data, $v_header)) {
  3003. return false;
  3004. }
  3005. if ($v_header['filename'] == '') {
  3006. continue;
  3007. }
  3008. switch ($v_header['typeflag']) {
  3009. case 'L':
  3010. {
  3011. if (!$this->_readLongHeader($v_header)) {
  3012. return null;
  3013. }
  3014. }
  3015. break;
  3016. case 'K':
  3017. {
  3018. $v_link_header = $v_header;
  3019. if (!$this->_readLongHeader($v_link_header)) {
  3020. return null;
  3021. }
  3022. $v_header['link'] = $v_link_header['filename'];
  3023. }
  3024. break;
  3025. }
  3026. // ignore extended / pax headers
  3027. if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
  3028. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  3029. continue;
  3030. }
  3031. if ((!$v_extract_all) && (is_array($p_file_list))) {
  3032. // ----- By default no unzip if the file is not found
  3033. $v_extract_file = false;
  3034. for ($i = 0; $i < sizeof($p_file_list); $i++) {
  3035. // ----- Look if it is a directory
  3036. if (substr($p_file_list[$i], -1) == '/') {
  3037. // ----- Look if the directory is in the filename path
  3038. if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  3039. && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  3040. == $p_file_list[$i])
  3041. ) {
  3042. $v_extract_file = true;
  3043. break;
  3044. }
  3045. } // ----- It is a file, so compare the file names
  3046. elseif ($p_file_list[$i] == $v_header['filename']) {
  3047. $v_extract_file = true;
  3048. break;
  3049. }
  3050. }
  3051. } else {
  3052. $v_extract_file = true;
  3053. }
  3054. // ----- Look if this file need to be extracted
  3055. if (($v_extract_file) && (!$v_listing)) {
  3056. if (($p_remove_path != '')
  3057. && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
  3058. == $p_remove_path)
  3059. ) {
  3060. $v_header['filename'] = substr(
  3061. $v_header['filename'],
  3062. $p_remove_path_size
  3063. );
  3064. if ($v_header['filename'] == '') {
  3065. continue;
  3066. }
  3067. }
  3068. if (($p_path != './') && ($p_path != '/')) {
  3069. while (substr($p_path, -1) == '/') {
  3070. $p_path = substr($p_path, 0, strlen($p_path) - 1);
  3071. }
  3072. if (substr($v_header['filename'], 0, 1) == '/') {
  3073. $v_header['filename'] = $p_path . $v_header['filename'];
  3074. } else {
  3075. $v_header['filename'] = $p_path . '/' . $v_header['filename'];
  3076. }
  3077. }
  3078. if (file_exists($v_header['filename'])) {
  3079. if ((@is_dir($v_header['filename']))
  3080. && ($v_header['typeflag'] == '')
  3081. ) {
  3082. $this->_error(
  3083. 'File ' . $v_header['filename']
  3084. . ' already exists as a directory'
  3085. );
  3086. return false;
  3087. }
  3088. if (($this->_isArchive($v_header['filename']))
  3089. && ($v_header['typeflag'] == "5")
  3090. ) {
  3091. $this->_error(
  3092. 'Directory ' . $v_header['filename']
  3093. . ' already exists as a file'
  3094. );
  3095. return false;
  3096. }
  3097. if (!is_writeable($v_header['filename'])) {
  3098. $this->_error(
  3099. 'File ' . $v_header['filename']
  3100. . ' already exists and is write protected'
  3101. );
  3102. return false;
  3103. }
  3104. if (filemtime($v_header['filename']) > $v_header['mtime']) {
  3105. // To be completed : An error or silent no replace ?
  3106. }
  3107. } // ----- Check the directory availability and create it if necessary
  3108. elseif (($v_result
  3109. = $this->_dirCheck(
  3110. ($v_header['typeflag'] == "5"
  3111. ? $v_header['filename']
  3112. : dirname($v_header['filename']))
  3113. )) != 1
  3114. ) {
  3115. $this->_error('Unable to create path for ' . $v_header['filename']);
  3116. return false;
  3117. }
  3118. if ($v_extract_file) {
  3119. if ($v_header['typeflag'] == "5") {
  3120. if (!@file_exists($v_header['filename'])) {
  3121. if (!@mkdir($v_header['filename'], 0777)) {
  3122. $this->_error(
  3123. 'Unable to create directory {'
  3124. . $v_header['filename'] . '}'
  3125. );
  3126. return false;
  3127. }
  3128. }
  3129. } elseif ($v_header['typeflag'] == "2") {
  3130. if (@file_exists($v_header['filename'])) {
  3131. @unlink($v_header['filename']);
  3132. }
  3133. if (!@symlink($v_header['link'], $v_header['filename'])) {
  3134. $this->_error(
  3135. 'Unable to extract symbolic link {'
  3136. . $v_header['filename'] . '}'
  3137. );
  3138. return false;
  3139. }
  3140. } else {
  3141. if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  3142. $this->_error(
  3143. 'Error while opening {' . $v_header['filename']
  3144. . '} in write binary mode'
  3145. );
  3146. return false;
  3147. } else {
  3148. $n = floor($v_header['size'] / 512);
  3149. for ($i = 0; $i < $n; $i++) {
  3150. $v_content = $this->_readBlock();
  3151. fwrite($v_dest_file, $v_content, 512);
  3152. }
  3153. if (($v_header['size'] % 512) != 0) {
  3154. $v_content = $this->_readBlock();
  3155. fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  3156. }
  3157. @fclose($v_dest_file);
  3158. if ($p_preserve) {
  3159. @chown($v_header['filename'], $v_header['uid']);
  3160. @chgrp($v_header['filename'], $v_header['gid']);
  3161. }
  3162. // ----- Change the file mode, mtime
  3163. @touch($v_header['filename'], $v_header['mtime']);
  3164. if ($v_header['mode'] & 0111) {
  3165. // make file executable, obey umask
  3166. $mode = fileperms($v_header['filename']) | (~umask() & 0111);
  3167. @chmod($v_header['filename'], $mode);
  3168. }
  3169. }
  3170. // ----- Check the file size
  3171. clearstatcache();
  3172. if (!is_file($v_header['filename'])) {
  3173. $this->_error(
  3174. 'Extracted file ' . $v_header['filename']
  3175. . 'does not exist. Archive may be corrupted.'
  3176. );
  3177. return false;
  3178. }
  3179. $filesize = filesize($v_header['filename']);
  3180. if ($filesize != $v_header['size']) {
  3181. $this->_error(
  3182. 'Extracted file ' . $v_header['filename']
  3183. . ' does not have the correct file size \''
  3184. . $filesize
  3185. . '\' (' . $v_header['size']
  3186. . ' expected). Archive may be corrupted.'
  3187. );
  3188. return false;
  3189. }
  3190. }
  3191. } else {
  3192. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  3193. }
  3194. } else {
  3195. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  3196. }
  3197. /* TBC : Seems to be unused ...
  3198. if ($this->_compress)
  3199. $v_end_of_file = @gzeof($this->_file);
  3200. else
  3201. $v_end_of_file = @feof($this->_file);
  3202. */
  3203. if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  3204. // ----- Log extracted files
  3205. if (($v_file_dir = dirname($v_header['filename']))
  3206. == $v_header['filename']
  3207. ) {
  3208. $v_file_dir = '';
  3209. }
  3210. if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
  3211. $v_file_dir = '/';
  3212. }
  3213. $p_list_detail[$v_nb++] = $v_header;
  3214. if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
  3215. return true;
  3216. }
  3217. }
  3218. }
  3219. return true;
  3220. }
  3221. /**
  3222. * @return bool
  3223. */
  3224. public function _openAppend()
  3225. {
  3226. if (filesize($this->_tarname) == 0) {
  3227. return $this->_openWrite();
  3228. }
  3229. if ($this->_compress) {
  3230. $this->_close();
  3231. if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
  3232. $this->_error(
  3233. 'Error while renaming \'' . $this->_tarname
  3234. . '\' to temporary file \'' . $this->_tarname
  3235. . '.tmp\''
  3236. );
  3237. return false;
  3238. }
  3239. if ($this->_compress_type == 'gz') {
  3240. $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
  3241. } elseif ($this->_compress_type == 'bz2') {
  3242. $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
  3243. } elseif ($this->_compress_type == 'lzma2') {
  3244. $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
  3245. }
  3246. if ($v_temp_tar == 0) {
  3247. $this->_error(
  3248. 'Unable to open file \'' . $this->_tarname
  3249. . '.tmp\' in binary read mode'
  3250. );
  3251. @rename($this->_tarname . ".tmp", $this->_tarname);
  3252. return false;
  3253. }
  3254. if (!$this->_openWrite()) {
  3255. @rename($this->_tarname . ".tmp", $this->_tarname);
  3256. return false;
  3257. }
  3258. if ($this->_compress_type == 'gz') {
  3259. $end_blocks = 0;
  3260. while (!@gzeof($v_temp_tar)) {
  3261. $v_buffer = @gzread($v_temp_tar, 512);
  3262. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  3263. $end_blocks++;
  3264. // do not copy end blocks, we will re-make them
  3265. // after appending
  3266. continue;
  3267. } elseif ($end_blocks > 0) {
  3268. for ($i = 0; $i < $end_blocks; $i++) {
  3269. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  3270. }
  3271. $end_blocks = 0;
  3272. }
  3273. $v_binary_data = pack("a512", $v_buffer);
  3274. $this->_writeBlock($v_binary_data);
  3275. }
  3276. @gzclose($v_temp_tar);
  3277. } elseif ($this->_compress_type == 'bz2') {
  3278. $end_blocks = 0;
  3279. while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
  3280. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  3281. $end_blocks++;
  3282. // do not copy end blocks, we will re-make them
  3283. // after appending
  3284. continue;
  3285. } elseif ($end_blocks > 0) {
  3286. for ($i = 0; $i < $end_blocks; $i++) {
  3287. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  3288. }
  3289. $end_blocks = 0;
  3290. }
  3291. $v_binary_data = pack("a512", $v_buffer);
  3292. $this->_writeBlock($v_binary_data);
  3293. }
  3294. @bzclose($v_temp_tar);
  3295. } elseif ($this->_compress_type == 'lzma2') {
  3296. $end_blocks = 0;
  3297. while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
  3298. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  3299. $end_blocks++;
  3300. // do not copy end blocks, we will re-make them
  3301. // after appending
  3302. continue;
  3303. } elseif ($end_blocks > 0) {
  3304. for ($i = 0; $i < $end_blocks; $i++) {
  3305. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  3306. }
  3307. $end_blocks = 0;
  3308. }
  3309. $v_binary_data = pack("a512", $v_buffer);
  3310. $this->_writeBlock($v_binary_data);
  3311. }
  3312. @xzclose($v_temp_tar);
  3313. }
  3314. if (!@unlink($this->_tarname . ".tmp")) {
  3315. $this->_error(
  3316. 'Error while deleting temporary file \''
  3317. . $this->_tarname . '.tmp\''
  3318. );
  3319. }
  3320. } else {
  3321. // ----- For not compressed tar, just add files before the last
  3322. // one or two 512 bytes block
  3323. if (!$this->_openReadWrite()) {
  3324. return false;
  3325. }
  3326. clearstatcache();
  3327. $v_size = filesize($this->_tarname);
  3328. // We might have zero, one or two end blocks.
  3329. // The standard is two, but we should try to handle
  3330. // other cases.
  3331. fseek($this->_file, $v_size - 1024);
  3332. if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  3333. fseek($this->_file, $v_size - 1024);
  3334. } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  3335. fseek($this->_file, $v_size - 512);
  3336. }
  3337. }
  3338. return true;
  3339. }
  3340. /**
  3341. * @param $p_filelist
  3342. * @param string $p_add_dir
  3343. * @param string $p_remove_dir
  3344. * @return bool
  3345. */
  3346. public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
  3347. {
  3348. if (!$this->_openAppend()) {
  3349. return false;
  3350. }
  3351. if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
  3352. $this->_writeFooter();
  3353. }
  3354. $this->_close();
  3355. return true;
  3356. }
  3357. /**
  3358. * Check if a directory exists and create it (including parent
  3359. * dirs) if not.
  3360. *
  3361. * @param string $p_dir directory to check
  3362. *
  3363. * @return bool true if the directory exists or was created
  3364. */
  3365. public function _dirCheck($p_dir)
  3366. {
  3367. clearstatcache();
  3368. if ((@is_dir($p_dir)) || ($p_dir == '')) {
  3369. return true;
  3370. }
  3371. $p_parent_dir = dirname($p_dir);
  3372. if (($p_parent_dir != $p_dir) &&
  3373. ($p_parent_dir != '') &&
  3374. (!$this->_dirCheck($p_parent_dir))
  3375. ) {
  3376. return false;
  3377. }
  3378. if (!@mkdir($p_dir, 0777)) {
  3379. $this->_error("Unable to create directory '$p_dir'");
  3380. return false;
  3381. }
  3382. return true;
  3383. }
  3384. /**
  3385. * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
  3386. * rand emove double slashes.
  3387. *
  3388. * @param string $p_dir path to reduce
  3389. *
  3390. * @return string reduced path
  3391. */
  3392. private function _pathReduction($p_dir)
  3393. {
  3394. $v_result = '';
  3395. // ----- Look for not empty path
  3396. if ($p_dir != '') {
  3397. // ----- Explode path by directory names
  3398. $v_list = explode('/', $p_dir);
  3399. // ----- Study directories from last to first
  3400. for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
  3401. // ----- Look for current path
  3402. if ($v_list[$i] == ".") {
  3403. // ----- Ignore this directory
  3404. // Should be the first $i=0, but no check is done
  3405. } else {
  3406. if ($v_list[$i] == "..") {
  3407. // ----- Ignore it and ignore the $i-1
  3408. $i--;
  3409. } else {
  3410. if (($v_list[$i] == '')
  3411. && ($i != (sizeof($v_list) - 1))
  3412. && ($i != 0)
  3413. ) {
  3414. // ----- Ignore only the double '//' in path,
  3415. // but not the first and last /
  3416. } else {
  3417. $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
  3418. . $v_result : '');
  3419. }
  3420. }
  3421. }
  3422. }
  3423. }
  3424. if (defined('OS_WINDOWS') && OS_WINDOWS) {
  3425. $v_result = strtr($v_result, '\\', '/');
  3426. }
  3427. return $v_result;
  3428. }
  3429. /**
  3430. * @param $p_path
  3431. * @param bool $p_remove_disk_letter
  3432. * @return string
  3433. */
  3434. public function _translateWinPath($p_path, $p_remove_disk_letter = true)
  3435. {
  3436. if (defined('OS_WINDOWS') && OS_WINDOWS) {
  3437. // ----- Look for potential disk letter
  3438. if (($p_remove_disk_letter)
  3439. && (($v_position = strpos($p_path, ':')) != false)
  3440. ) {
  3441. $p_path = substr($p_path, $v_position + 1);
  3442. }
  3443. // ----- Change potential windows directory separator
  3444. if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
  3445. $p_path = strtr($p_path, '\\', '/');
  3446. }
  3447. }
  3448. return $p_path;
  3449. }
  3450. }
  3451. <?php
  3452. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3453. /**
  3454. * PHP Version 5
  3455. *
  3456. * Copyright (c) 2001-2015, The PEAR developers
  3457. *
  3458. * This source file is subject to the BSD-2-Clause license,
  3459. * that is bundled with this package in the file LICENSE, and is
  3460. * available through the world-wide-web at the following url:
  3461. * http://opensource.org/licenses/bsd-license.php.
  3462. *
  3463. * @category Console
  3464. * @package Console_Getopt
  3465. * @author Andrei Zmievski <andrei@php.net>
  3466. * @license http://opensource.org/licenses/bsd-license.php BSD-2-Clause
  3467. * @version CVS: $Id$
  3468. * @link http://pear.php.net/package/Console_Getopt
  3469. */
  3470. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  3471. /**
  3472. * Command-line options parsing class.
  3473. *
  3474. * @category Console
  3475. * @package Console_Getopt
  3476. * @author Andrei Zmievski <andrei@php.net>
  3477. * @license http://opensource.org/licenses/bsd-license.php BSD-2-Clause
  3478. * @link http://pear.php.net/package/Console_Getopt
  3479. */
  3480. class Console_Getopt
  3481. {
  3482. /**
  3483. * Parses the command-line options.
  3484. *
  3485. * The first parameter to this function should be the list of command-line
  3486. * arguments without the leading reference to the running program.
  3487. *
  3488. * The second parameter is a string of allowed short options. Each of the
  3489. * option letters can be followed by a colon ':' to specify that the option
  3490. * requires an argument, or a double colon '::' to specify that the option
  3491. * takes an optional argument.
  3492. *
  3493. * The third argument is an optional array of allowed long options. The
  3494. * leading '--' should not be included in the option name. Options that
  3495. * require an argument should be followed by '=', and options that take an
  3496. * option argument should be followed by '=='.
  3497. *
  3498. * The return value is an array of two elements: the list of parsed
  3499. * options and the list of non-option command-line arguments. Each entry in
  3500. * the list of parsed options is a pair of elements - the first one
  3501. * specifies the option, and the second one specifies the option argument,
  3502. * if there was one.
  3503. *
  3504. * Long and short options can be mixed.
  3505. *
  3506. * Most of the semantics of this function are based on GNU getopt_long().
  3507. *
  3508. * @param array $args an array of command-line arguments
  3509. * @param string $short_options specifies the list of allowed short options
  3510. * @param array $long_options specifies the list of allowed long options
  3511. * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
  3512. *
  3513. * @return array two-element array containing the list of parsed options and
  3514. * the non-option arguments
  3515. */
  3516. public static function getopt2($args, $short_options, $long_options = null, $skip_unknown = false)
  3517. {
  3518. return Console_Getopt::doGetopt(2, $args, $short_options, $long_options, $skip_unknown);
  3519. }
  3520. /**
  3521. * This function expects $args to start with the script name (POSIX-style).
  3522. * Preserved for backwards compatibility.
  3523. *
  3524. * @param array $args an array of command-line arguments
  3525. * @param string $short_options specifies the list of allowed short options
  3526. * @param array $long_options specifies the list of allowed long options
  3527. *
  3528. * @see getopt2()
  3529. * @return array two-element array containing the list of parsed options and
  3530. * the non-option arguments
  3531. */
  3532. public static function getopt($args, $short_options, $long_options = null, $skip_unknown = false)
  3533. {
  3534. return Console_Getopt::doGetopt(1, $args, $short_options, $long_options, $skip_unknown);
  3535. }
  3536. /**
  3537. * The actual implementation of the argument parsing code.
  3538. *
  3539. * @param int $version Version to use
  3540. * @param array $args an array of command-line arguments
  3541. * @param string $short_options specifies the list of allowed short options
  3542. * @param array $long_options specifies the list of allowed long options
  3543. * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
  3544. *
  3545. * @return array
  3546. */
  3547. public static function doGetopt($version, $args, $short_options, $long_options = null, $skip_unknown = false)
  3548. {
  3549. // in case you pass directly readPHPArgv() as the first arg
  3550. if (PEAR::isError($args)) {
  3551. return $args;
  3552. }
  3553. if (empty($args)) {
  3554. return array(array(), array());
  3555. }
  3556. $non_opts = $opts = array();
  3557. settype($args, 'array');
  3558. if ($long_options) {
  3559. sort($long_options);
  3560. }
  3561. /*
  3562. * Preserve backwards compatibility with callers that relied on
  3563. * erroneous POSIX fix.
  3564. */
  3565. if ($version < 2) {
  3566. if (isset($args[0][0]) && $args[0][0] != '-') {
  3567. array_shift($args);
  3568. }
  3569. }
  3570. for ($i = 0; $i < count($args); $i++) {
  3571. $arg = $args[$i];
  3572. /* The special element '--' means explicit end of
  3573. options. Treat the rest of the arguments as non-options
  3574. and end the loop. */
  3575. if ($arg == '--') {
  3576. $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  3577. break;
  3578. }
  3579. if ($arg[0] != '-' || (strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) {
  3580. $non_opts = array_merge($non_opts, array_slice($args, $i));
  3581. break;
  3582. } elseif (strlen($arg) > 1 && $arg[1] == '-') {
  3583. $error = Console_Getopt::_parseLongOption(substr($arg, 2),
  3584. $long_options,
  3585. $opts,
  3586. $i,
  3587. $args,
  3588. $skip_unknown);
  3589. if (PEAR::isError($error)) {
  3590. return $error;
  3591. }
  3592. } elseif ($arg == '-') {
  3593. // - is stdin
  3594. $non_opts = array_merge($non_opts, array_slice($args, $i));
  3595. break;
  3596. } else {
  3597. $error = Console_Getopt::_parseShortOption(substr($arg, 1),
  3598. $short_options,
  3599. $opts,
  3600. $i,
  3601. $args,
  3602. $skip_unknown);
  3603. if (PEAR::isError($error)) {
  3604. return $error;
  3605. }
  3606. }
  3607. }
  3608. return array($opts, $non_opts);
  3609. }
  3610. /**
  3611. * Parse short option
  3612. *
  3613. * @param string $arg Argument
  3614. * @param string[] $short_options Available short options
  3615. * @param string[][] &$opts
  3616. * @param int &$argIdx
  3617. * @param string[] $args
  3618. * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
  3619. *
  3620. * @return void
  3621. */
  3622. protected static function _parseShortOption($arg, $short_options, &$opts, &$argIdx, $args, $skip_unknown)
  3623. {
  3624. for ($i = 0; $i < strlen($arg); $i++) {
  3625. $opt = $arg[$i];
  3626. $opt_arg = null;
  3627. /* Try to find the short option in the specifier string. */
  3628. if (($spec = strstr($short_options, $opt)) === false || $arg[$i] == ':') {
  3629. if ($skip_unknown === true) {
  3630. break;
  3631. }
  3632. $msg = "Console_Getopt: unrecognized option -- $opt";
  3633. return PEAR::raiseError($msg);
  3634. }
  3635. if (strlen($spec) > 1 && $spec[1] == ':') {
  3636. if (strlen($spec) > 2 && $spec[2] == ':') {
  3637. if ($i + 1 < strlen($arg)) {
  3638. /* Option takes an optional argument. Use the remainder of
  3639. the arg string if there is anything left. */
  3640. $opts[] = array($opt, substr($arg, $i + 1));
  3641. break;
  3642. }
  3643. } else {
  3644. /* Option requires an argument. Use the remainder of the arg
  3645. string if there is anything left. */
  3646. if ($i + 1 < strlen($arg)) {
  3647. $opts[] = array($opt, substr($arg, $i + 1));
  3648. break;
  3649. } else if (isset($args[++$argIdx])) {
  3650. $opt_arg = $args[$argIdx];
  3651. /* Else use the next argument. */;
  3652. if (Console_Getopt::_isShortOpt($opt_arg)
  3653. || Console_Getopt::_isLongOpt($opt_arg)) {
  3654. $msg = "option requires an argument --$opt";
  3655. return PEAR::raiseError("Console_Getopt: " . $msg);
  3656. }
  3657. } else {
  3658. $msg = "option requires an argument --$opt";
  3659. return PEAR::raiseError("Console_Getopt: " . $msg);
  3660. }
  3661. }
  3662. }
  3663. $opts[] = array($opt, $opt_arg);
  3664. }
  3665. }
  3666. /**
  3667. * Checks if an argument is a short option
  3668. *
  3669. * @param string $arg Argument to check
  3670. *
  3671. * @return bool
  3672. */
  3673. protected static function _isShortOpt($arg)
  3674. {
  3675. return strlen($arg) == 2 && $arg[0] == '-'
  3676. && preg_match('/[a-zA-Z]/', $arg[1]);
  3677. }
  3678. /**
  3679. * Checks if an argument is a long option
  3680. *
  3681. * @param string $arg Argument to check
  3682. *
  3683. * @return bool
  3684. */
  3685. protected static function _isLongOpt($arg)
  3686. {
  3687. return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
  3688. preg_match('/[a-zA-Z]+$/', substr($arg, 2));
  3689. }
  3690. /**
  3691. * Parse long option
  3692. *
  3693. * @param string $arg Argument
  3694. * @param string[] $long_options Available long options
  3695. * @param string[][] &$opts
  3696. * @param int &$argIdx
  3697. * @param string[] $args
  3698. *
  3699. * @return void|PEAR_Error
  3700. */
  3701. protected static function _parseLongOption($arg, $long_options, &$opts, &$argIdx, $args, $skip_unknown)
  3702. {
  3703. @list($opt, $opt_arg) = explode('=', $arg, 2);
  3704. $opt_len = strlen($opt);
  3705. for ($i = 0; $i < count($long_options); $i++) {
  3706. $long_opt = $long_options[$i];
  3707. $opt_start = substr($long_opt, 0, $opt_len);
  3708. $long_opt_name = str_replace('=', '', $long_opt);
  3709. /* Option doesn't match. Go on to the next one. */
  3710. if ($long_opt_name != $opt) {
  3711. continue;
  3712. }
  3713. $opt_rest = substr($long_opt, $opt_len);
  3714. /* Check that the options uniquely matches one of the allowed
  3715. options. */
  3716. if ($i + 1 < count($long_options)) {
  3717. $next_option_rest = substr($long_options[$i + 1], $opt_len);
  3718. } else {
  3719. $next_option_rest = '';
  3720. }
  3721. if ($opt_rest != '' && $opt[0] != '=' &&
  3722. $i + 1 < count($long_options) &&
  3723. $opt == substr($long_options[$i+1], 0, $opt_len) &&
  3724. $next_option_rest != '' &&
  3725. $next_option_rest[0] != '=') {
  3726. $msg = "Console_Getopt: option --$opt is ambiguous";
  3727. return PEAR::raiseError($msg);
  3728. }
  3729. if (substr($long_opt, -1) == '=') {
  3730. if (substr($long_opt, -2) != '==') {
  3731. /* Long option requires an argument.
  3732. Take the next argument if one wasn't specified. */;
  3733. if (!strlen($opt_arg)) {
  3734. if (!isset($args[++$argIdx])) {
  3735. $msg = "Console_Getopt: option requires an argument --$opt";
  3736. return PEAR::raiseError($msg);
  3737. }
  3738. $opt_arg = $args[$argIdx];
  3739. }
  3740. if (Console_Getopt::_isShortOpt($opt_arg)
  3741. || Console_Getopt::_isLongOpt($opt_arg)) {
  3742. $msg = "Console_Getopt: option requires an argument --$opt";
  3743. return PEAR::raiseError($msg);
  3744. }
  3745. }
  3746. } else if ($opt_arg) {
  3747. $msg = "Console_Getopt: option --$opt doesn't allow an argument";
  3748. return PEAR::raiseError($msg);
  3749. }
  3750. $opts[] = array('--' . $opt, $opt_arg);
  3751. return;
  3752. }
  3753. if ($skip_unknown === true) {
  3754. return;
  3755. }
  3756. return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  3757. }
  3758. /**
  3759. * Safely read the $argv PHP array across different PHP configurations.
  3760. * Will take care on register_globals and register_argc_argv ini directives
  3761. *
  3762. * @return mixed the $argv PHP array or PEAR error if not registered
  3763. */
  3764. public static function readPHPArgv()
  3765. {
  3766. global $argv;
  3767. if (!is_array($argv)) {
  3768. if (!@is_array($_SERVER['argv'])) {
  3769. if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  3770. $msg = "Could not read cmd args (register_argc_argv=Off?)";
  3771. return PEAR::raiseError("Console_Getopt: " . $msg);
  3772. }
  3773. return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  3774. }
  3775. return $_SERVER['argv'];
  3776. }
  3777. return $argv;
  3778. }
  3779. }
  3780. <?php
  3781. require_once 'phar://go-pear.phar/PEAR/Start/CLI.php';
  3782. PEAR::setErrorHandling(PEAR_ERROR_DIE);
  3783. $a = new PEAR_Start_CLI;
  3784. $a->run();
  3785. ?><?php
  3786. /**
  3787. * The OS_Guess class
  3788. *
  3789. * PHP versions 4 and 5
  3790. *
  3791. * @category pear
  3792. * @package PEAR
  3793. * @author Stig Bakken <ssb@php.net>
  3794. * @author Gregory Beaver <cellog@php.net>
  3795. * @copyright 1997-2009 The Authors
  3796. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  3797. * @link http://pear.php.net/package/PEAR
  3798. * @since File available since PEAR 0.1
  3799. */
  3800. // {{{ uname examples
  3801. // php_uname() without args returns the same as 'uname -a', or a PHP-custom
  3802. // string for Windows.
  3803. // PHP versions prior to 4.3 return the uname of the host where PHP was built,
  3804. // as of 4.3 it returns the uname of the host running the PHP code.
  3805. //
  3806. // PC RedHat Linux 7.1:
  3807. // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
  3808. //
  3809. // PC Debian Potato:
  3810. // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
  3811. //
  3812. // PC FreeBSD 3.3:
  3813. // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386
  3814. //
  3815. // PC FreeBSD 4.3:
  3816. // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386
  3817. //
  3818. // PC FreeBSD 4.5:
  3819. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386
  3820. //
  3821. // PC FreeBSD 4.5 w/uname from GNU shellutils:
  3822. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown
  3823. //
  3824. // HP 9000/712 HP-UX 10:
  3825. // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
  3826. //
  3827. // HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
  3828. // HP-UX host B.10.10 A 9000/712 unknown
  3829. //
  3830. // IBM RS6000/550 AIX 4.3:
  3831. // AIX host 3 4 000003531C00
  3832. //
  3833. // AIX 4.3 w/uname from GNU shellutils:
  3834. // AIX host 3 4 000003531C00 unknown
  3835. //
  3836. // SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
  3837. // IRIX64 host 6.5 01091820 IP19 mips
  3838. //
  3839. // SGI Onyx IRIX 6.5:
  3840. // IRIX64 host 6.5 01091820 IP19
  3841. //
  3842. // SparcStation 20 Solaris 8 w/uname from GNU shellutils:
  3843. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
  3844. //
  3845. // SparcStation 20 Solaris 8:
  3846. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
  3847. //
  3848. // Mac OS X (Darwin)
  3849. // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh
  3850. //
  3851. // Mac OS X early versions
  3852. //
  3853. // }}}
  3854. /* TODO:
  3855. * - define endianness, to allow matchSignature("bigend") etc.
  3856. */
  3857. /**
  3858. * Retrieves information about the current operating system
  3859. *
  3860. * This class uses php_uname() to grok information about the current OS
  3861. *
  3862. * @category pear
  3863. * @package PEAR
  3864. * @author Stig Bakken <ssb@php.net>
  3865. * @author Gregory Beaver <cellog@php.net>
  3866. * @copyright 1997-2009 The Authors
  3867. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  3868. * @version Release: 1.10.10
  3869. * @link http://pear.php.net/package/PEAR
  3870. * @since Class available since Release 0.1
  3871. */
  3872. class OS_Guess
  3873. {
  3874. var $sysname;
  3875. var $nodename;
  3876. var $cpu;
  3877. var $release;
  3878. var $extra;
  3879. function __construct($uname = null)
  3880. {
  3881. list($this->sysname,
  3882. $this->release,
  3883. $this->cpu,
  3884. $this->extra,
  3885. $this->nodename) = $this->parseSignature($uname);
  3886. }
  3887. function parseSignature($uname = null)
  3888. {
  3889. static $sysmap = array(
  3890. 'HP-UX' => 'hpux',
  3891. 'IRIX64' => 'irix',
  3892. );
  3893. static $cpumap = array(
  3894. 'i586' => 'i386',
  3895. 'i686' => 'i386',
  3896. 'ppc' => 'powerpc',
  3897. );
  3898. if ($uname === null) {
  3899. $uname = php_uname();
  3900. }
  3901. $parts = preg_split('/\s+/', trim($uname));
  3902. $n = count($parts);
  3903. $release = $machine = $cpu = '';
  3904. $sysname = $parts[0];
  3905. $nodename = $parts[1];
  3906. $cpu = $parts[$n-1];
  3907. $extra = '';
  3908. if ($cpu == 'unknown') {
  3909. $cpu = $parts[$n - 2];
  3910. }
  3911. switch ($sysname) {
  3912. case 'AIX' :
  3913. $release = "$parts[3].$parts[2]";
  3914. break;
  3915. case 'Windows' :
  3916. switch ($parts[1]) {
  3917. case '95/98':
  3918. $release = '9x';
  3919. break;
  3920. default:
  3921. $release = $parts[1];
  3922. break;
  3923. }
  3924. $cpu = 'i386';
  3925. break;
  3926. case 'Linux' :
  3927. $extra = $this->_detectGlibcVersion();
  3928. // use only the first two digits from the kernel version
  3929. $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
  3930. break;
  3931. case 'Mac' :
  3932. $sysname = 'darwin';
  3933. $nodename = $parts[2];
  3934. $release = $parts[3];
  3935. if ($cpu == 'Macintosh') {
  3936. if ($parts[$n - 2] == 'Power') {
  3937. $cpu = 'powerpc';
  3938. }
  3939. }
  3940. break;
  3941. case 'Darwin' :
  3942. if ($cpu == 'Macintosh') {
  3943. if ($parts[$n - 2] == 'Power') {
  3944. $cpu = 'powerpc';
  3945. }
  3946. }
  3947. $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
  3948. break;
  3949. default:
  3950. $release = preg_replace('/-.*/', '', $parts[2]);
  3951. break;
  3952. }
  3953. if (isset($sysmap[$sysname])) {
  3954. $sysname = $sysmap[$sysname];
  3955. } else {
  3956. $sysname = strtolower($sysname);
  3957. }
  3958. if (isset($cpumap[$cpu])) {
  3959. $cpu = $cpumap[$cpu];
  3960. }
  3961. return array($sysname, $release, $cpu, $extra, $nodename);
  3962. }
  3963. function _detectGlibcVersion()
  3964. {
  3965. static $glibc = false;
  3966. if ($glibc !== false) {
  3967. return $glibc; // no need to run this multiple times
  3968. }
  3969. $major = $minor = 0;
  3970. include_once 'phar://go-pear.phar/' . "System.php";
  3971. if (@is_link('/lib64/libc.so.6')) {
  3972. // Let's try reading the libc.so.6 symlink
  3973. if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib64/libc.so.6')), $matches)) {
  3974. list($major, $minor) = explode('.', $matches[1]);
  3975. }
  3976. } else if (@is_link('/lib/libc.so.6')) {
  3977. // Let's try reading the libc.so.6 symlink
  3978. if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) {
  3979. list($major, $minor) = explode('.', $matches[1]);
  3980. }
  3981. }
  3982. // Use glibc's <features.h> header file to
  3983. // get major and minor version number:
  3984. if (!($major && $minor) &&
  3985. @file_exists('/usr/include/features.h') &&
  3986. @is_readable('/usr/include/features.h')) {
  3987. if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
  3988. $features_file = fopen('/usr/include/features.h', 'rb');
  3989. while (!feof($features_file)) {
  3990. $line = fgets($features_file, 8192);
  3991. if (!$line || (strpos($line, '#define') === false)) {
  3992. continue;
  3993. }
  3994. if (strpos($line, '__GLIBC__')) {
  3995. // major version number #define __GLIBC__ version
  3996. $line = preg_split('/\s+/', $line);
  3997. $glibc_major = trim($line[2]);
  3998. if (isset($glibc_minor)) {
  3999. break;
  4000. }
  4001. continue;
  4002. }
  4003. if (strpos($line, '__GLIBC_MINOR__')) {
  4004. // got the minor version number
  4005. // #define __GLIBC_MINOR__ version
  4006. $line = preg_split('/\s+/', $line);
  4007. $glibc_minor = trim($line[2]);
  4008. if (isset($glibc_major)) {
  4009. break;
  4010. }
  4011. continue;
  4012. }
  4013. }
  4014. fclose($features_file);
  4015. if (!isset($glibc_major) || !isset($glibc_minor)) {
  4016. return $glibc = '';
  4017. }
  4018. return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
  4019. } // no cpp
  4020. $tmpfile = System::mktemp("glibctest");
  4021. $fp = fopen($tmpfile, "w");
  4022. fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
  4023. fclose($fp);
  4024. $cpp = popen("/usr/bin/cpp $tmpfile", "r");
  4025. while ($line = fgets($cpp, 1024)) {
  4026. if ($line[0] == '#' || trim($line) == '') {
  4027. continue;
  4028. }
  4029. if (list($major, $minor) = explode(' ', trim($line))) {
  4030. break;
  4031. }
  4032. }
  4033. pclose($cpp);
  4034. unlink($tmpfile);
  4035. } // features.h
  4036. if (!($major && $minor)) {
  4037. return $glibc = '';
  4038. }
  4039. return $glibc = "glibc{$major}.{$minor}";
  4040. }
  4041. function getSignature()
  4042. {
  4043. if (empty($this->extra)) {
  4044. return "{$this->sysname}-{$this->release}-{$this->cpu}";
  4045. }
  4046. return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
  4047. }
  4048. function getSysname()
  4049. {
  4050. return $this->sysname;
  4051. }
  4052. function getNodename()
  4053. {
  4054. return $this->nodename;
  4055. }
  4056. function getCpu()
  4057. {
  4058. return $this->cpu;
  4059. }
  4060. function getRelease()
  4061. {
  4062. return $this->release;
  4063. }
  4064. function getExtra()
  4065. {
  4066. return $this->extra;
  4067. }
  4068. function matchSignature($match)
  4069. {
  4070. $fragments = is_array($match) ? $match : explode('-', $match);
  4071. $n = count($fragments);
  4072. $matches = 0;
  4073. if ($n > 0) {
  4074. $matches += $this->_matchFragment($fragments[0], $this->sysname);
  4075. }
  4076. if ($n > 1) {
  4077. $matches += $this->_matchFragment($fragments[1], $this->release);
  4078. }
  4079. if ($n > 2) {
  4080. $matches += $this->_matchFragment($fragments[2], $this->cpu);
  4081. }
  4082. if ($n > 3) {
  4083. $matches += $this->_matchFragment($fragments[3], $this->extra);
  4084. }
  4085. return ($matches == $n);
  4086. }
  4087. function _matchFragment($fragment, $value)
  4088. {
  4089. if (strcspn($fragment, '*?') < strlen($fragment)) {
  4090. $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/';
  4091. return preg_match($reg, $value);
  4092. }
  4093. return ($fragment == '*' || !strcasecmp($fragment, $value));
  4094. }
  4095. }
  4096. /*
  4097. * Local Variables:
  4098. * indent-tabs-mode: nil
  4099. * c-basic-offset: 4
  4100. * End:
  4101. */
  4102. <?php
  4103. /**
  4104. * PEAR, the PHP Extension and Application Repository
  4105. *
  4106. * PEAR class and PEAR_Error class
  4107. *
  4108. * PHP versions 4 and 5
  4109. *
  4110. * @category pear
  4111. * @package PEAR
  4112. * @author Sterling Hughes <sterling@php.net>
  4113. * @author Stig Bakken <ssb@php.net>
  4114. * @author Tomas V.V.Cox <cox@idecnet.com>
  4115. * @author Greg Beaver <cellog@php.net>
  4116. * @copyright 1997-2010 The Authors
  4117. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  4118. * @link http://pear.php.net/package/PEAR
  4119. * @since File available since Release 0.1
  4120. */
  4121. /**#@+
  4122. * ERROR constants
  4123. */
  4124. define('PEAR_ERROR_RETURN', 1);
  4125. define('PEAR_ERROR_PRINT', 2);
  4126. define('PEAR_ERROR_TRIGGER', 4);
  4127. define('PEAR_ERROR_DIE', 8);
  4128. define('PEAR_ERROR_CALLBACK', 16);
  4129. /**
  4130. * WARNING: obsolete
  4131. * @deprecated
  4132. */
  4133. define('PEAR_ERROR_EXCEPTION', 32);
  4134. /**#@-*/
  4135. if (substr(PHP_OS, 0, 3) == 'WIN') {
  4136. define('OS_WINDOWS', true);
  4137. define('OS_UNIX', false);
  4138. define('PEAR_OS', 'Windows');
  4139. } else {
  4140. define('OS_WINDOWS', false);
  4141. define('OS_UNIX', true);
  4142. define('PEAR_OS', 'Unix'); // blatant assumption
  4143. }
  4144. $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
  4145. $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
  4146. $GLOBALS['_PEAR_destructor_object_list'] = array();
  4147. $GLOBALS['_PEAR_shutdown_funcs'] = array();
  4148. $GLOBALS['_PEAR_error_handler_stack'] = array();
  4149. @ini_set('track_errors', true);
  4150. /**
  4151. * Base class for other PEAR classes. Provides rudimentary
  4152. * emulation of destructors.
  4153. *
  4154. * If you want a destructor in your class, inherit PEAR and make a
  4155. * destructor method called _yourclassname (same name as the
  4156. * constructor, but with a "_" prefix). Also, in your constructor you
  4157. * have to call the PEAR constructor: $this->PEAR();.
  4158. * The destructor method will be called without parameters. Note that
  4159. * at in some SAPI implementations (such as Apache), any output during
  4160. * the request shutdown (in which destructors are called) seems to be
  4161. * discarded. If you need to get any debug information from your
  4162. * destructor, use error_log(), syslog() or something similar.
  4163. *
  4164. * IMPORTANT! To use the emulated destructors you need to create the
  4165. * objects by reference: $obj =& new PEAR_child;
  4166. *
  4167. * @category pear
  4168. * @package PEAR
  4169. * @author Stig Bakken <ssb@php.net>
  4170. * @author Tomas V.V. Cox <cox@idecnet.com>
  4171. * @author Greg Beaver <cellog@php.net>
  4172. * @copyright 1997-2006 The PHP Group
  4173. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  4174. * @version Release: 1.10.10
  4175. * @link http://pear.php.net/package/PEAR
  4176. * @see PEAR_Error
  4177. * @since Class available since PHP 4.0.2
  4178. * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear
  4179. */
  4180. class PEAR
  4181. {
  4182. /**
  4183. * Whether to enable internal debug messages.
  4184. *
  4185. * @var bool
  4186. * @access private
  4187. */
  4188. var $_debug = false;
  4189. /**
  4190. * Default error mode for this object.
  4191. *
  4192. * @var int
  4193. * @access private
  4194. */
  4195. var $_default_error_mode = null;
  4196. /**
  4197. * Default error options used for this object when error mode
  4198. * is PEAR_ERROR_TRIGGER.
  4199. *
  4200. * @var int
  4201. * @access private
  4202. */
  4203. var $_default_error_options = null;
  4204. /**
  4205. * Default error handler (callback) for this object, if error mode is
  4206. * PEAR_ERROR_CALLBACK.
  4207. *
  4208. * @var string
  4209. * @access private
  4210. */
  4211. var $_default_error_handler = '';
  4212. /**
  4213. * Which class to use for error objects.
  4214. *
  4215. * @var string
  4216. * @access private
  4217. */
  4218. var $_error_class = 'PEAR_Error';
  4219. /**
  4220. * An array of expected errors.
  4221. *
  4222. * @var array
  4223. * @access private
  4224. */
  4225. var $_expected_errors = array();
  4226. /**
  4227. * List of methods that can be called both statically and non-statically.
  4228. * @var array
  4229. */
  4230. protected static $bivalentMethods = array(
  4231. 'setErrorHandling' => true,
  4232. 'raiseError' => true,
  4233. 'throwError' => true,
  4234. 'pushErrorHandling' => true,
  4235. 'popErrorHandling' => true,
  4236. );
  4237. /**
  4238. * Constructor. Registers this object in
  4239. * $_PEAR_destructor_object_list for destructor emulation if a
  4240. * destructor object exists.
  4241. *
  4242. * @param string $error_class (optional) which class to use for
  4243. * error objects, defaults to PEAR_Error.
  4244. * @access public
  4245. * @return void
  4246. */
  4247. function __construct($error_class = null)
  4248. {
  4249. $classname = strtolower(get_class($this));
  4250. if ($this->_debug) {
  4251. print "PEAR constructor called, class=$classname\n";
  4252. }
  4253. if ($error_class !== null) {
  4254. $this->_error_class = $error_class;
  4255. }
  4256. while ($classname && strcasecmp($classname, "pear")) {
  4257. $destructor = "_$classname";
  4258. if (method_exists($this, $destructor)) {
  4259. global $_PEAR_destructor_object_list;
  4260. $_PEAR_destructor_object_list[] = $this;
  4261. if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  4262. register_shutdown_function("_PEAR_call_destructors");
  4263. $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  4264. }
  4265. break;
  4266. } else {
  4267. $classname = get_parent_class($classname);
  4268. }
  4269. }
  4270. }
  4271. /**
  4272. * Only here for backwards compatibility.
  4273. * E.g. Archive_Tar calls $this->PEAR() in its constructor.
  4274. *
  4275. * @param string $error_class Which class to use for error objects,
  4276. * defaults to PEAR_Error.
  4277. */
  4278. public function PEAR($error_class = null)
  4279. {
  4280. self::__construct($error_class);
  4281. }
  4282. /**
  4283. * Destructor (the emulated type of...). Does nothing right now,
  4284. * but is included for forward compatibility, so subclass
  4285. * destructors should always call it.
  4286. *
  4287. * See the note in the class desciption about output from
  4288. * destructors.
  4289. *
  4290. * @access public
  4291. * @return void
  4292. */
  4293. function _PEAR() {
  4294. if ($this->_debug) {
  4295. printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
  4296. }
  4297. }
  4298. public function __call($method, $arguments)
  4299. {
  4300. if (!isset(self::$bivalentMethods[$method])) {
  4301. trigger_error(
  4302. 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
  4303. );
  4304. }
  4305. return call_user_func_array(
  4306. array(get_class(), '_' . $method),
  4307. array_merge(array($this), $arguments)
  4308. );
  4309. }
  4310. public static function __callStatic($method, $arguments)
  4311. {
  4312. if (!isset(self::$bivalentMethods[$method])) {
  4313. trigger_error(
  4314. 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
  4315. );
  4316. }
  4317. return call_user_func_array(
  4318. array(get_class(), '_' . $method),
  4319. array_merge(array(null), $arguments)
  4320. );
  4321. }
  4322. /**
  4323. * If you have a class that's mostly/entirely static, and you need static
  4324. * properties, you can use this method to simulate them. Eg. in your method(s)
  4325. * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
  4326. * You MUST use a reference, or they will not persist!
  4327. *
  4328. * @param string $class The calling classname, to prevent clashes
  4329. * @param string $var The variable to retrieve.
  4330. * @return mixed A reference to the variable. If not set it will be
  4331. * auto initialised to NULL.
  4332. */
  4333. public static function &getStaticProperty($class, $var)
  4334. {
  4335. static $properties;
  4336. if (!isset($properties[$class])) {
  4337. $properties[$class] = array();
  4338. }
  4339. if (!array_key_exists($var, $properties[$class])) {
  4340. $properties[$class][$var] = null;
  4341. }
  4342. return $properties[$class][$var];
  4343. }
  4344. /**
  4345. * Use this function to register a shutdown method for static
  4346. * classes.
  4347. *
  4348. * @param mixed $func The function name (or array of class/method) to call
  4349. * @param mixed $args The arguments to pass to the function
  4350. *
  4351. * @return void
  4352. */
  4353. public static function registerShutdownFunc($func, $args = array())
  4354. {
  4355. // if we are called statically, there is a potential
  4356. // that no shutdown func is registered. Bug #6445
  4357. if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  4358. register_shutdown_function("_PEAR_call_destructors");
  4359. $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  4360. }
  4361. $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
  4362. }
  4363. /**
  4364. * Tell whether a value is a PEAR error.
  4365. *
  4366. * @param mixed $data the value to test
  4367. * @param int $code if $data is an error object, return true
  4368. * only if $code is a string and
  4369. * $obj->getMessage() == $code or
  4370. * $code is an integer and $obj->getCode() == $code
  4371. *
  4372. * @return bool true if parameter is an error
  4373. */
  4374. public static function isError($data, $code = null)
  4375. {
  4376. if (!is_a($data, 'PEAR_Error')) {
  4377. return false;
  4378. }
  4379. if (is_null($code)) {
  4380. return true;
  4381. } elseif (is_string($code)) {
  4382. return $data->getMessage() == $code;
  4383. }
  4384. return $data->getCode() == $code;
  4385. }
  4386. /**
  4387. * Sets how errors generated by this object should be handled.
  4388. * Can be invoked both in objects and statically. If called
  4389. * statically, setErrorHandling sets the default behaviour for all
  4390. * PEAR objects. If called in an object, setErrorHandling sets
  4391. * the default behaviour for that object.
  4392. *
  4393. * @param object $object
  4394. * Object the method was called on (non-static mode)
  4395. *
  4396. * @param int $mode
  4397. * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  4398. * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  4399. * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
  4400. *
  4401. * @param mixed $options
  4402. * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
  4403. * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  4404. *
  4405. * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
  4406. * to be the callback function or method. A callback
  4407. * function is a string with the name of the function, a
  4408. * callback method is an array of two elements: the element
  4409. * at index 0 is the object, and the element at index 1 is
  4410. * the name of the method to call in the object.
  4411. *
  4412. * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
  4413. * a printf format string used when printing the error
  4414. * message.
  4415. *
  4416. * @access public
  4417. * @return void
  4418. * @see PEAR_ERROR_RETURN
  4419. * @see PEAR_ERROR_PRINT
  4420. * @see PEAR_ERROR_TRIGGER
  4421. * @see PEAR_ERROR_DIE
  4422. * @see PEAR_ERROR_CALLBACK
  4423. * @see PEAR_ERROR_EXCEPTION
  4424. *
  4425. * @since PHP 4.0.5
  4426. */
  4427. protected static function _setErrorHandling(
  4428. $object, $mode = null, $options = null
  4429. ) {
  4430. if ($object !== null) {
  4431. $setmode = &$object->_default_error_mode;
  4432. $setoptions = &$object->_default_error_options;
  4433. } else {
  4434. $setmode = &$GLOBALS['_PEAR_default_error_mode'];
  4435. $setoptions = &$GLOBALS['_PEAR_default_error_options'];
  4436. }
  4437. switch ($mode) {
  4438. case PEAR_ERROR_EXCEPTION:
  4439. case PEAR_ERROR_RETURN:
  4440. case PEAR_ERROR_PRINT:
  4441. case PEAR_ERROR_TRIGGER:
  4442. case PEAR_ERROR_DIE:
  4443. case null:
  4444. $setmode = $mode;
  4445. $setoptions = $options;
  4446. break;
  4447. case PEAR_ERROR_CALLBACK:
  4448. $setmode = $mode;
  4449. // class/object method callback
  4450. if (is_callable($options)) {
  4451. $setoptions = $options;
  4452. } else {
  4453. trigger_error("invalid error callback", E_USER_WARNING);
  4454. }
  4455. break;
  4456. default:
  4457. trigger_error("invalid error mode", E_USER_WARNING);
  4458. break;
  4459. }
  4460. }
  4461. /**
  4462. * This method is used to tell which errors you expect to get.
  4463. * Expected errors are always returned with error mode
  4464. * PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
  4465. * and this method pushes a new element onto it. The list of
  4466. * expected errors are in effect until they are popped off the
  4467. * stack with the popExpect() method.
  4468. *
  4469. * Note that this method can not be called statically
  4470. *
  4471. * @param mixed $code a single error code or an array of error codes to expect
  4472. *
  4473. * @return int the new depth of the "expected errors" stack
  4474. * @access public
  4475. */
  4476. function expectError($code = '*')
  4477. {
  4478. if (is_array($code)) {
  4479. array_push($this->_expected_errors, $code);
  4480. } else {
  4481. array_push($this->_expected_errors, array($code));
  4482. }
  4483. return count($this->_expected_errors);
  4484. }
  4485. /**
  4486. * This method pops one element off the expected error codes
  4487. * stack.
  4488. *
  4489. * @return array the list of error codes that were popped
  4490. */
  4491. function popExpect()
  4492. {
  4493. return array_pop($this->_expected_errors);
  4494. }
  4495. /**
  4496. * This method checks unsets an error code if available
  4497. *
  4498. * @param mixed error code
  4499. * @return bool true if the error code was unset, false otherwise
  4500. * @access private
  4501. * @since PHP 4.3.0
  4502. */
  4503. function _checkDelExpect($error_code)
  4504. {
  4505. $deleted = false;
  4506. foreach ($this->_expected_errors as $key => $error_array) {
  4507. if (in_array($error_code, $error_array)) {
  4508. unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
  4509. $deleted = true;
  4510. }
  4511. // clean up empty arrays
  4512. if (0 == count($this->_expected_errors[$key])) {
  4513. unset($this->_expected_errors[$key]);
  4514. }
  4515. }
  4516. return $deleted;
  4517. }
  4518. /**
  4519. * This method deletes all occurrences of the specified element from
  4520. * the expected error codes stack.
  4521. *
  4522. * @param mixed $error_code error code that should be deleted
  4523. * @return mixed list of error codes that were deleted or error
  4524. * @access public
  4525. * @since PHP 4.3.0
  4526. */
  4527. function delExpect($error_code)
  4528. {
  4529. $deleted = false;
  4530. if ((is_array($error_code) && (0 != count($error_code)))) {
  4531. // $error_code is a non-empty array here; we walk through it trying
  4532. // to unset all values
  4533. foreach ($error_code as $key => $error) {
  4534. $deleted = $this->_checkDelExpect($error) ? true : false;
  4535. }
  4536. return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  4537. } elseif (!empty($error_code)) {
  4538. // $error_code comes alone, trying to unset it
  4539. if ($this->_checkDelExpect($error_code)) {
  4540. return true;
  4541. }
  4542. return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  4543. }
  4544. // $error_code is empty
  4545. return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
  4546. }
  4547. /**
  4548. * This method is a wrapper that returns an instance of the
  4549. * configured error class with this object's default error
  4550. * handling applied. If the $mode and $options parameters are not
  4551. * specified, the object's defaults are used.
  4552. *
  4553. * @param mixed $message a text error message or a PEAR error object
  4554. *
  4555. * @param int $code a numeric error code (it is up to your class
  4556. * to define these if you want to use codes)
  4557. *
  4558. * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  4559. * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  4560. * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
  4561. *
  4562. * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
  4563. * specifies the PHP-internal error level (one of
  4564. * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  4565. * If $mode is PEAR_ERROR_CALLBACK, this
  4566. * parameter specifies the callback function or
  4567. * method. In other error modes this parameter
  4568. * is ignored.
  4569. *
  4570. * @param string $userinfo If you need to pass along for example debug
  4571. * information, this parameter is meant for that.
  4572. *
  4573. * @param string $error_class The returned error object will be
  4574. * instantiated from this class, if specified.
  4575. *
  4576. * @param bool $skipmsg If true, raiseError will only pass error codes,
  4577. * the error message parameter will be dropped.
  4578. *
  4579. * @return object a PEAR error object
  4580. * @see PEAR::setErrorHandling
  4581. * @since PHP 4.0.5
  4582. */
  4583. protected static function _raiseError($object,
  4584. $message = null,
  4585. $code = null,
  4586. $mode = null,
  4587. $options = null,
  4588. $userinfo = null,
  4589. $error_class = null,
  4590. $skipmsg = false)
  4591. {
  4592. // The error is yet a PEAR error object
  4593. if (is_object($message)) {
  4594. $code = $message->getCode();
  4595. $userinfo = $message->getUserInfo();
  4596. $error_class = $message->getType();
  4597. $message->error_message_prefix = '';
  4598. $message = $message->getMessage();
  4599. }
  4600. if (
  4601. $object !== null &&
  4602. isset($object->_expected_errors) &&
  4603. count($object->_expected_errors) > 0 &&
  4604. count($exp = end($object->_expected_errors))
  4605. ) {
  4606. if ($exp[0] === "*" ||
  4607. (is_int(reset($exp)) && in_array($code, $exp)) ||
  4608. (is_string(reset($exp)) && in_array($message, $exp))
  4609. ) {
  4610. $mode = PEAR_ERROR_RETURN;
  4611. }
  4612. }
  4613. // No mode given, try global ones
  4614. if ($mode === null) {
  4615. // Class error handler
  4616. if ($object !== null && isset($object->_default_error_mode)) {
  4617. $mode = $object->_default_error_mode;
  4618. $options = $object->_default_error_options;
  4619. // Global error handler
  4620. } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
  4621. $mode = $GLOBALS['_PEAR_default_error_mode'];
  4622. $options = $GLOBALS['_PEAR_default_error_options'];
  4623. }
  4624. }
  4625. if ($error_class !== null) {
  4626. $ec = $error_class;
  4627. } elseif ($object !== null && isset($object->_error_class)) {
  4628. $ec = $object->_error_class;
  4629. } else {
  4630. $ec = 'PEAR_Error';
  4631. }
  4632. if ($skipmsg) {
  4633. $a = new $ec($code, $mode, $options, $userinfo);
  4634. } else {
  4635. $a = new $ec($message, $code, $mode, $options, $userinfo);
  4636. }
  4637. return $a;
  4638. }
  4639. /**
  4640. * Simpler form of raiseError with fewer options. In most cases
  4641. * message, code and userinfo are enough.
  4642. *
  4643. * @param mixed $message a text error message or a PEAR error object
  4644. *
  4645. * @param int $code a numeric error code (it is up to your class
  4646. * to define these if you want to use codes)
  4647. *
  4648. * @param string $userinfo If you need to pass along for example debug
  4649. * information, this parameter is meant for that.
  4650. *
  4651. * @return object a PEAR error object
  4652. * @see PEAR::raiseError
  4653. */
  4654. protected static function _throwError($object, $message = null, $code = null, $userinfo = null)
  4655. {
  4656. if ($object !== null) {
  4657. $a = $object->raiseError($message, $code, null, null, $userinfo);
  4658. return $a;
  4659. }
  4660. $a = PEAR::raiseError($message, $code, null, null, $userinfo);
  4661. return $a;
  4662. }
  4663. public static function staticPushErrorHandling($mode, $options = null)
  4664. {
  4665. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4666. $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
  4667. $def_options = &$GLOBALS['_PEAR_default_error_options'];
  4668. $stack[] = array($def_mode, $def_options);
  4669. switch ($mode) {
  4670. case PEAR_ERROR_EXCEPTION:
  4671. case PEAR_ERROR_RETURN:
  4672. case PEAR_ERROR_PRINT:
  4673. case PEAR_ERROR_TRIGGER:
  4674. case PEAR_ERROR_DIE:
  4675. case null:
  4676. $def_mode = $mode;
  4677. $def_options = $options;
  4678. break;
  4679. case PEAR_ERROR_CALLBACK:
  4680. $def_mode = $mode;
  4681. // class/object method callback
  4682. if (is_callable($options)) {
  4683. $def_options = $options;
  4684. } else {
  4685. trigger_error("invalid error callback", E_USER_WARNING);
  4686. }
  4687. break;
  4688. default:
  4689. trigger_error("invalid error mode", E_USER_WARNING);
  4690. break;
  4691. }
  4692. $stack[] = array($mode, $options);
  4693. return true;
  4694. }
  4695. public static function staticPopErrorHandling()
  4696. {
  4697. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4698. $setmode = &$GLOBALS['_PEAR_default_error_mode'];
  4699. $setoptions = &$GLOBALS['_PEAR_default_error_options'];
  4700. array_pop($stack);
  4701. list($mode, $options) = $stack[sizeof($stack) - 1];
  4702. array_pop($stack);
  4703. switch ($mode) {
  4704. case PEAR_ERROR_EXCEPTION:
  4705. case PEAR_ERROR_RETURN:
  4706. case PEAR_ERROR_PRINT:
  4707. case PEAR_ERROR_TRIGGER:
  4708. case PEAR_ERROR_DIE:
  4709. case null:
  4710. $setmode = $mode;
  4711. $setoptions = $options;
  4712. break;
  4713. case PEAR_ERROR_CALLBACK:
  4714. $setmode = $mode;
  4715. // class/object method callback
  4716. if (is_callable($options)) {
  4717. $setoptions = $options;
  4718. } else {
  4719. trigger_error("invalid error callback", E_USER_WARNING);
  4720. }
  4721. break;
  4722. default:
  4723. trigger_error("invalid error mode", E_USER_WARNING);
  4724. break;
  4725. }
  4726. return true;
  4727. }
  4728. /**
  4729. * Push a new error handler on top of the error handler options stack. With this
  4730. * you can easily override the actual error handler for some code and restore
  4731. * it later with popErrorHandling.
  4732. *
  4733. * @param mixed $mode (same as setErrorHandling)
  4734. * @param mixed $options (same as setErrorHandling)
  4735. *
  4736. * @return bool Always true
  4737. *
  4738. * @see PEAR::setErrorHandling
  4739. */
  4740. protected static function _pushErrorHandling($object, $mode, $options = null)
  4741. {
  4742. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4743. if ($object !== null) {
  4744. $def_mode = &$object->_default_error_mode;
  4745. $def_options = &$object->_default_error_options;
  4746. } else {
  4747. $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
  4748. $def_options = &$GLOBALS['_PEAR_default_error_options'];
  4749. }
  4750. $stack[] = array($def_mode, $def_options);
  4751. if ($object !== null) {
  4752. $object->setErrorHandling($mode, $options);
  4753. } else {
  4754. PEAR::setErrorHandling($mode, $options);
  4755. }
  4756. $stack[] = array($mode, $options);
  4757. return true;
  4758. }
  4759. /**
  4760. * Pop the last error handler used
  4761. *
  4762. * @return bool Always true
  4763. *
  4764. * @see PEAR::pushErrorHandling
  4765. */
  4766. protected static function _popErrorHandling($object)
  4767. {
  4768. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  4769. array_pop($stack);
  4770. list($mode, $options) = $stack[sizeof($stack) - 1];
  4771. array_pop($stack);
  4772. if ($object !== null) {
  4773. $object->setErrorHandling($mode, $options);
  4774. } else {
  4775. PEAR::setErrorHandling($mode, $options);
  4776. }
  4777. return true;
  4778. }
  4779. /**
  4780. * OS independent PHP extension load. Remember to take care
  4781. * on the correct extension name for case sensitive OSes.
  4782. *
  4783. * @param string $ext The extension name
  4784. * @return bool Success or not on the dl() call
  4785. */
  4786. public static function loadExtension($ext)
  4787. {
  4788. if (extension_loaded($ext)) {
  4789. return true;
  4790. }
  4791. // if either returns true dl() will produce a FATAL error, stop that
  4792. if (
  4793. function_exists('dl') === false ||
  4794. ini_get('enable_dl') != 1
  4795. ) {
  4796. return false;
  4797. }
  4798. if (OS_WINDOWS) {
  4799. $suffix = '.dll';
  4800. } elseif (PHP_OS == 'HP-UX') {
  4801. $suffix = '.sl';
  4802. } elseif (PHP_OS == 'AIX') {
  4803. $suffix = '.a';
  4804. } elseif (PHP_OS == 'OSX') {
  4805. $suffix = '.bundle';
  4806. } else {
  4807. $suffix = '.so';
  4808. }
  4809. return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
  4810. }
  4811. /**
  4812. * Get SOURCE_DATE_EPOCH environment variable
  4813. * See https://reproducible-builds.org/specs/source-date-epoch/
  4814. *
  4815. * @return int
  4816. * @access public
  4817. */
  4818. static function getSourceDateEpoch()
  4819. {
  4820. if ($source_date_epoch = getenv('SOURCE_DATE_EPOCH')) {
  4821. if (preg_match('/^\d+$/', $source_date_epoch)) {
  4822. return (int) $source_date_epoch;
  4823. } else {
  4824. // "If the value is malformed, the build process SHOULD exit with a non-zero error code."
  4825. self::raiseError("Invalid SOURCE_DATE_EPOCH: $source_date_epoch");
  4826. exit(1);
  4827. }
  4828. } else {
  4829. return time();
  4830. }
  4831. }
  4832. }
  4833. function _PEAR_call_destructors()
  4834. {
  4835. global $_PEAR_destructor_object_list;
  4836. if (is_array($_PEAR_destructor_object_list) &&
  4837. sizeof($_PEAR_destructor_object_list))
  4838. {
  4839. reset($_PEAR_destructor_object_list);
  4840. $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
  4841. if ($destructLifoExists) {
  4842. $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
  4843. }
  4844. foreach ($_PEAR_destructor_object_list as $k => $objref) {
  4845. $classname = get_class($objref);
  4846. while ($classname) {
  4847. $destructor = "_$classname";
  4848. if (method_exists($objref, $destructor)) {
  4849. $objref->$destructor();
  4850. break;
  4851. } else {
  4852. $classname = get_parent_class($classname);
  4853. }
  4854. }
  4855. }
  4856. // Empty the object list to ensure that destructors are
  4857. // not called more than once.
  4858. $_PEAR_destructor_object_list = array();
  4859. }
  4860. // Now call the shutdown functions
  4861. if (
  4862. isset($GLOBALS['_PEAR_shutdown_funcs']) &&
  4863. is_array($GLOBALS['_PEAR_shutdown_funcs']) &&
  4864. !empty($GLOBALS['_PEAR_shutdown_funcs'])
  4865. ) {
  4866. foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
  4867. call_user_func_array($value[0], $value[1]);
  4868. }
  4869. }
  4870. }
  4871. /**
  4872. * Standard PEAR error class for PHP 4
  4873. *
  4874. * This class is supserseded by {@link PEAR_Exception} in PHP 5
  4875. *
  4876. * @category pear
  4877. * @package PEAR
  4878. * @author Stig Bakken <ssb@php.net>
  4879. * @author Tomas V.V. Cox <cox@idecnet.com>
  4880. * @author Gregory Beaver <cellog@php.net>
  4881. * @copyright 1997-2006 The PHP Group
  4882. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  4883. * @version Release: 1.10.10
  4884. * @link http://pear.php.net/manual/en/core.pear.pear-error.php
  4885. * @see PEAR::raiseError(), PEAR::throwError()
  4886. * @since Class available since PHP 4.0.2
  4887. */
  4888. class PEAR_Error
  4889. {
  4890. var $error_message_prefix = '';
  4891. var $mode = PEAR_ERROR_RETURN;
  4892. var $level = E_USER_NOTICE;
  4893. var $code = -1;
  4894. var $message = '';
  4895. var $userinfo = '';
  4896. var $backtrace = null;
  4897. /**
  4898. * PEAR_Error constructor
  4899. *
  4900. * @param string $message message
  4901. *
  4902. * @param int $code (optional) error code
  4903. *
  4904. * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
  4905. * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
  4906. * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
  4907. *
  4908. * @param mixed $options (optional) error level, _OR_ in the case of
  4909. * PEAR_ERROR_CALLBACK, the callback function or object/method
  4910. * tuple.
  4911. *
  4912. * @param string $userinfo (optional) additional user/debug info
  4913. *
  4914. * @access public
  4915. *
  4916. */
  4917. function __construct($message = 'unknown error', $code = null,
  4918. $mode = null, $options = null, $userinfo = null)
  4919. {
  4920. if ($mode === null) {
  4921. $mode = PEAR_ERROR_RETURN;
  4922. }
  4923. $this->message = $message;
  4924. $this->code = $code;
  4925. $this->mode = $mode;
  4926. $this->userinfo = $userinfo;
  4927. $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
  4928. if (!$skiptrace) {
  4929. $this->backtrace = debug_backtrace();
  4930. if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
  4931. unset($this->backtrace[0]['object']);
  4932. }
  4933. }
  4934. if ($mode & PEAR_ERROR_CALLBACK) {
  4935. $this->level = E_USER_NOTICE;
  4936. $this->callback = $options;
  4937. } else {
  4938. if ($options === null) {
  4939. $options = E_USER_NOTICE;
  4940. }
  4941. $this->level = $options;
  4942. $this->callback = null;
  4943. }
  4944. if ($this->mode & PEAR_ERROR_PRINT) {
  4945. if (is_null($options) || is_int($options)) {
  4946. $format = "%s";
  4947. } else {
  4948. $format = $options;
  4949. }
  4950. printf($format, $this->getMessage());
  4951. }
  4952. if ($this->mode & PEAR_ERROR_TRIGGER) {
  4953. trigger_error($this->getMessage(), $this->level);
  4954. }
  4955. if ($this->mode & PEAR_ERROR_DIE) {
  4956. $msg = $this->getMessage();
  4957. if (is_null($options) || is_int($options)) {
  4958. $format = "%s";
  4959. if (substr($msg, -1) != "\n") {
  4960. $msg .= "\n";
  4961. }
  4962. } else {
  4963. $format = $options;
  4964. }
  4965. printf($format, $msg);
  4966. exit($code);
  4967. }
  4968. if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
  4969. call_user_func($this->callback, $this);
  4970. }
  4971. if ($this->mode & PEAR_ERROR_EXCEPTION) {
  4972. trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
  4973. eval('$e = new Exception($this->message, $this->code);throw($e);');
  4974. }
  4975. }
  4976. /**
  4977. * Only here for backwards compatibility.
  4978. *
  4979. * Class "Cache_Error" still uses it, among others.
  4980. *
  4981. * @param string $message Message
  4982. * @param int $code Error code
  4983. * @param int $mode Error mode
  4984. * @param mixed $options See __construct()
  4985. * @param string $userinfo Additional user/debug info
  4986. */
  4987. public function PEAR_Error(
  4988. $message = 'unknown error', $code = null, $mode = null,
  4989. $options = null, $userinfo = null
  4990. ) {
  4991. self::__construct($message, $code, $mode, $options, $userinfo);
  4992. }
  4993. /**
  4994. * Get the error mode from an error object.
  4995. *
  4996. * @return int error mode
  4997. * @access public
  4998. */
  4999. function getMode()
  5000. {
  5001. return $this->mode;
  5002. }
  5003. /**
  5004. * Get the callback function/method from an error object.
  5005. *
  5006. * @return mixed callback function or object/method array
  5007. * @access public
  5008. */
  5009. function getCallback()
  5010. {
  5011. return $this->callback;
  5012. }
  5013. /**
  5014. * Get the error message from an error object.
  5015. *
  5016. * @return string full error message
  5017. * @access public
  5018. */
  5019. function getMessage()
  5020. {
  5021. return ($this->error_message_prefix . $this->message);
  5022. }
  5023. /**
  5024. * Get error code from an error object
  5025. *
  5026. * @return int error code
  5027. * @access public
  5028. */
  5029. function getCode()
  5030. {
  5031. return $this->code;
  5032. }
  5033. /**
  5034. * Get the name of this error/exception.
  5035. *
  5036. * @return string error/exception name (type)
  5037. * @access public
  5038. */
  5039. function getType()
  5040. {
  5041. return get_class($this);
  5042. }
  5043. /**
  5044. * Get additional user-supplied information.
  5045. *
  5046. * @return string user-supplied information
  5047. * @access public
  5048. */
  5049. function getUserInfo()
  5050. {
  5051. return $this->userinfo;
  5052. }
  5053. /**
  5054. * Get additional debug information supplied by the application.
  5055. *
  5056. * @return string debug information
  5057. * @access public
  5058. */
  5059. function getDebugInfo()
  5060. {
  5061. return $this->getUserInfo();
  5062. }
  5063. /**
  5064. * Get the call backtrace from where the error was generated.
  5065. * Supported with PHP 4.3.0 or newer.
  5066. *
  5067. * @param int $frame (optional) what frame to fetch
  5068. * @return array Backtrace, or NULL if not available.
  5069. * @access public
  5070. */
  5071. function getBacktrace($frame = null)
  5072. {
  5073. if (defined('PEAR_IGNORE_BACKTRACE')) {
  5074. return null;
  5075. }
  5076. if ($frame === null) {
  5077. return $this->backtrace;
  5078. }
  5079. return $this->backtrace[$frame];
  5080. }
  5081. function addUserInfo($info)
  5082. {
  5083. if (empty($this->userinfo)) {
  5084. $this->userinfo = $info;
  5085. } else {
  5086. $this->userinfo .= " ** $info";
  5087. }
  5088. }
  5089. function __toString()
  5090. {
  5091. return $this->getMessage();
  5092. }
  5093. /**
  5094. * Make a string representation of this object.
  5095. *
  5096. * @return string a string with an object summary
  5097. * @access public
  5098. */
  5099. function toString()
  5100. {
  5101. $modes = array();
  5102. $levels = array(E_USER_NOTICE => 'notice',
  5103. E_USER_WARNING => 'warning',
  5104. E_USER_ERROR => 'error');
  5105. if ($this->mode & PEAR_ERROR_CALLBACK) {
  5106. if (is_array($this->callback)) {
  5107. $callback = (is_object($this->callback[0]) ?
  5108. strtolower(get_class($this->callback[0])) :
  5109. $this->callback[0]) . '::' .
  5110. $this->callback[1];
  5111. } else {
  5112. $callback = $this->callback;
  5113. }
  5114. return sprintf('[%s: message="%s" code=%d mode=callback '.
  5115. 'callback=%s prefix="%s" info="%s"]',
  5116. strtolower(get_class($this)), $this->message, $this->code,
  5117. $callback, $this->error_message_prefix,
  5118. $this->userinfo);
  5119. }
  5120. if ($this->mode & PEAR_ERROR_PRINT) {
  5121. $modes[] = 'print';
  5122. }
  5123. if ($this->mode & PEAR_ERROR_TRIGGER) {
  5124. $modes[] = 'trigger';
  5125. }
  5126. if ($this->mode & PEAR_ERROR_DIE) {
  5127. $modes[] = 'die';
  5128. }
  5129. if ($this->mode & PEAR_ERROR_RETURN) {
  5130. $modes[] = 'return';
  5131. }
  5132. return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
  5133. 'prefix="%s" info="%s"]',
  5134. strtolower(get_class($this)), $this->message, $this->code,
  5135. implode("|", $modes), $levels[$this->level],
  5136. $this->error_message_prefix,
  5137. $this->userinfo);
  5138. }
  5139. }
  5140. /*
  5141. * Local Variables:
  5142. * mode: php
  5143. * tab-width: 4
  5144. * c-basic-offset: 4
  5145. * End:
  5146. */
  5147. <?php
  5148. /**
  5149. * PEAR_ChannelFile, the channel handling class
  5150. *
  5151. * PHP versions 4 and 5
  5152. *
  5153. * @category pear
  5154. * @package PEAR
  5155. * @author Greg Beaver <cellog@php.net>
  5156. * @copyright 1997-2009 The Authors
  5157. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  5158. * @link http://pear.php.net/package/PEAR
  5159. * @since File available since Release 1.4.0a1
  5160. */
  5161. /**
  5162. * Needed for error handling
  5163. */
  5164. require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php';
  5165. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  5166. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  5167. /**
  5168. * Error code if the channel.xml <channel> tag does not contain a valid version
  5169. */
  5170. define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
  5171. /**
  5172. * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
  5173. * currently
  5174. */
  5175. define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
  5176. /**
  5177. * Error code if parsing is attempted with no xml extension
  5178. */
  5179. define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
  5180. /**
  5181. * Error code if creating the xml parser resource fails
  5182. */
  5183. define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
  5184. /**
  5185. * Error code used for all sax xml parsing errors
  5186. */
  5187. define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
  5188. /**#@+
  5189. * Validation errors
  5190. */
  5191. /**
  5192. * Error code when channel name is missing
  5193. */
  5194. define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
  5195. /**
  5196. * Error code when channel name is invalid
  5197. */
  5198. define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
  5199. /**
  5200. * Error code when channel summary is missing
  5201. */
  5202. define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
  5203. /**
  5204. * Error code when channel summary is multi-line
  5205. */
  5206. define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
  5207. /**
  5208. * Error code when channel server is missing for protocol
  5209. */
  5210. define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
  5211. /**
  5212. * Error code when channel server is invalid for protocol
  5213. */
  5214. define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
  5215. /**
  5216. * Error code when a mirror name is invalid
  5217. */
  5218. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
  5219. /**
  5220. * Error code when a mirror type is invalid
  5221. */
  5222. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
  5223. /**
  5224. * Error code when an attempt is made to generate xml, but the parsed content is invalid
  5225. */
  5226. define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
  5227. /**
  5228. * Error code when an empty package name validate regex is passed in
  5229. */
  5230. define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
  5231. /**
  5232. * Error code when a <function> tag has no version
  5233. */
  5234. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
  5235. /**
  5236. * Error code when a <function> tag has no name
  5237. */
  5238. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
  5239. /**
  5240. * Error code when a <validatepackage> tag has no name
  5241. */
  5242. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
  5243. /**
  5244. * Error code when a <validatepackage> tag has no version attribute
  5245. */
  5246. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
  5247. /**
  5248. * Error code when a mirror does not exist but is called for in one of the set*
  5249. * methods.
  5250. */
  5251. define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
  5252. /**
  5253. * Error code when a server port is not numeric
  5254. */
  5255. define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
  5256. /**
  5257. * Error code when <static> contains no version attribute
  5258. */
  5259. define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
  5260. /**
  5261. * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
  5262. */
  5263. define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
  5264. /**
  5265. * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
  5266. */
  5267. define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
  5268. /**
  5269. * Error code when ssl attribute is present and is not "yes"
  5270. */
  5271. define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
  5272. /**#@-*/
  5273. /**
  5274. * Mirror types allowed. Currently only internet servers are recognized.
  5275. */
  5276. $GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server');
  5277. /**
  5278. * The Channel handling class
  5279. *
  5280. * @category pear
  5281. * @package PEAR
  5282. * @author Greg Beaver <cellog@php.net>
  5283. * @copyright 1997-2009 The Authors
  5284. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  5285. * @version Release: 1.10.10
  5286. * @link http://pear.php.net/package/PEAR
  5287. * @since Class available since Release 1.4.0a1
  5288. */
  5289. class PEAR_ChannelFile
  5290. {
  5291. /**
  5292. * @access private
  5293. * @var PEAR_ErrorStack
  5294. * @access private
  5295. */
  5296. var $_stack;
  5297. /**
  5298. * Supported channel.xml versions, for parsing
  5299. * @var array
  5300. * @access private
  5301. */
  5302. var $_supportedVersions = array('1.0');
  5303. /**
  5304. * Parsed channel information
  5305. * @var array
  5306. * @access private
  5307. */
  5308. var $_channelInfo;
  5309. /**
  5310. * index into the subchannels array, used for parsing xml
  5311. * @var int
  5312. * @access private
  5313. */
  5314. var $_subchannelIndex;
  5315. /**
  5316. * index into the mirrors array, used for parsing xml
  5317. * @var int
  5318. * @access private
  5319. */
  5320. var $_mirrorIndex;
  5321. /**
  5322. * Flag used to determine the validity of parsed content
  5323. * @var boolean
  5324. * @access private
  5325. */
  5326. var $_isValid = false;
  5327. function __construct()
  5328. {
  5329. $this->_stack = new PEAR_ErrorStack('PEAR_ChannelFile');
  5330. $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  5331. $this->_isValid = false;
  5332. }
  5333. /**
  5334. * @return array
  5335. * @access protected
  5336. */
  5337. function _getErrorMessage()
  5338. {
  5339. return
  5340. array(
  5341. PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
  5342. 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
  5343. PEAR_CHANNELFILE_ERROR_NO_VERSION =>
  5344. 'No version number found in <channel> tag',
  5345. PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
  5346. '%error%',
  5347. PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
  5348. 'Unable to create XML parser',
  5349. PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
  5350. '%error%',
  5351. PEAR_CHANNELFILE_ERROR_NO_NAME =>
  5352. 'Missing channel name',
  5353. PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
  5354. 'Invalid channel %tag% "%name%"',
  5355. PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
  5356. 'Missing channel summary',
  5357. PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
  5358. 'Channel summary should be on one line, but is multi-line',
  5359. PEAR_CHANNELFILE_ERROR_NO_HOST =>
  5360. 'Missing channel server for %type% server',
  5361. PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
  5362. 'Server name "%server%" is invalid for %type% server',
  5363. PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
  5364. 'Invalid mirror name "%name%", mirror type %type%',
  5365. PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
  5366. 'Invalid mirror type "%type%"',
  5367. PEAR_CHANNELFILE_ERROR_INVALID =>
  5368. 'Cannot generate xml, contents are invalid',
  5369. PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
  5370. 'packagenameregex cannot be empty',
  5371. PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
  5372. '%parent% %protocol% function has no version',
  5373. PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
  5374. '%parent% %protocol% function has no name',
  5375. PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
  5376. '%parent% rest baseurl has no type',
  5377. PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
  5378. 'Validation package has no name in <validatepackage> tag',
  5379. PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
  5380. 'Validation package "%package%" has no version',
  5381. PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
  5382. 'Mirror "%mirror%" does not exist',
  5383. PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
  5384. 'Port "%port%" must be numeric',
  5385. PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
  5386. '<static> tag must contain version attribute',
  5387. PEAR_CHANNELFILE_URI_CANT_MIRROR =>
  5388. 'The __uri pseudo-channel cannot have mirrors',
  5389. PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
  5390. '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
  5391. );
  5392. }
  5393. /**
  5394. * @param string contents of package.xml file
  5395. * @return bool success of parsing
  5396. */
  5397. function fromXmlString($data)
  5398. {
  5399. if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
  5400. if (!in_array($channelversion[1], $this->_supportedVersions)) {
  5401. $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
  5402. array('version' => $channelversion[1]));
  5403. return false;
  5404. }
  5405. $parser = new PEAR_XMLParser;
  5406. $result = $parser->parse($data);
  5407. if ($result !== true) {
  5408. if ($result->getCode() == 1) {
  5409. $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
  5410. array('error' => $result->getMessage()));
  5411. } else {
  5412. $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
  5413. }
  5414. return false;
  5415. }
  5416. $this->_channelInfo = $parser->getData();
  5417. return true;
  5418. } else {
  5419. $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
  5420. return false;
  5421. }
  5422. }
  5423. /**
  5424. * @return array
  5425. */
  5426. function toArray()
  5427. {
  5428. if (!$this->_isValid && !$this->validate()) {
  5429. return false;
  5430. }
  5431. return $this->_channelInfo;
  5432. }
  5433. /**
  5434. * @param array
  5435. *
  5436. * @return PEAR_ChannelFile|false false if invalid
  5437. */
  5438. public static function &fromArray(
  5439. $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
  5440. ) {
  5441. $a = new PEAR_ChannelFile($compatibility, $stackClass);
  5442. $a->_fromArray($data);
  5443. if (!$a->validate()) {
  5444. $a = false;
  5445. return $a;
  5446. }
  5447. return $a;
  5448. }
  5449. /**
  5450. * Unlike {@link fromArray()} this does not do any validation
  5451. *
  5452. * @param array
  5453. *
  5454. * @return PEAR_ChannelFile
  5455. */
  5456. public static function &fromArrayWithErrors(
  5457. $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
  5458. ) {
  5459. $a = new PEAR_ChannelFile($compatibility, $stackClass);
  5460. $a->_fromArray($data);
  5461. return $a;
  5462. }
  5463. /**
  5464. * @param array
  5465. * @access private
  5466. */
  5467. function _fromArray($data)
  5468. {
  5469. $this->_channelInfo = $data;
  5470. }
  5471. /**
  5472. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  5473. * @param boolean determines whether to purge the error stack after retrieving
  5474. * @return array
  5475. */
  5476. function getErrors($purge = false)
  5477. {
  5478. return $this->_stack->getErrors($purge);
  5479. }
  5480. /**
  5481. * Unindent given string (?)
  5482. *
  5483. * @param string $str The string that has to be unindented.
  5484. * @return string
  5485. * @access private
  5486. */
  5487. function _unIndent($str)
  5488. {
  5489. // remove leading newlines
  5490. $str = preg_replace('/^[\r\n]+/', '', $str);
  5491. // find whitespace at the beginning of the first line
  5492. $indent_len = strspn($str, " \t");
  5493. $indent = substr($str, 0, $indent_len);
  5494. $data = '';
  5495. // remove the same amount of whitespace from following lines
  5496. foreach (explode("\n", $str) as $line) {
  5497. if (substr($line, 0, $indent_len) == $indent) {
  5498. $data .= substr($line, $indent_len) . "\n";
  5499. }
  5500. }
  5501. return $data;
  5502. }
  5503. /**
  5504. * Parse a channel.xml file. Expects the name of
  5505. * a channel xml file as input.
  5506. *
  5507. * @param string $descfile name of channel xml file
  5508. * @return bool success of parsing
  5509. */
  5510. function fromXmlFile($descfile)
  5511. {
  5512. if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
  5513. (!$fp = fopen($descfile, 'r'))) {
  5514. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  5515. return PEAR::raiseError("Unable to open $descfile");
  5516. }
  5517. // read the whole thing so we only get one cdata callback
  5518. // for each block of cdata
  5519. fclose($fp);
  5520. $data = file_get_contents($descfile);
  5521. return $this->fromXmlString($data);
  5522. }
  5523. /**
  5524. * Parse channel information from different sources
  5525. *
  5526. * This method is able to extract information about a channel
  5527. * from an .xml file or a string
  5528. *
  5529. * @access public
  5530. * @param string Filename of the source or the source itself
  5531. * @return bool
  5532. */
  5533. function fromAny($info)
  5534. {
  5535. if (is_string($info) && file_exists($info) && strlen($info) < 255) {
  5536. $tmp = substr($info, -4);
  5537. if ($tmp == '.xml') {
  5538. $info = $this->fromXmlFile($info);
  5539. } else {
  5540. $fp = fopen($info, "r");
  5541. $test = fread($fp, 5);
  5542. fclose($fp);
  5543. if ($test == "<?xml") {
  5544. $info = $this->fromXmlFile($info);
  5545. }
  5546. }
  5547. if (PEAR::isError($info)) {
  5548. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  5549. return PEAR::raiseError($info);
  5550. }
  5551. }
  5552. if (is_string($info)) {
  5553. $info = $this->fromXmlString($info);
  5554. }
  5555. return $info;
  5556. }
  5557. /**
  5558. * Return an XML document based on previous parsing and modifications
  5559. *
  5560. * @return string XML data
  5561. *
  5562. * @access public
  5563. */
  5564. function toXml()
  5565. {
  5566. if (!$this->_isValid && !$this->validate()) {
  5567. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
  5568. return false;
  5569. }
  5570. if (!isset($this->_channelInfo['attribs']['version'])) {
  5571. $this->_channelInfo['attribs']['version'] = '1.0';
  5572. }
  5573. $channelInfo = $this->_channelInfo;
  5574. $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
  5575. $ret .= "<channel version=\"" .
  5576. $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
  5577. xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  5578. xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
  5579. . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
  5580. $channelInfo['attribs']['version'] . ".xsd\">
  5581. <name>$channelInfo[name]</name>
  5582. <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
  5583. ";
  5584. if (isset($channelInfo['suggestedalias'])) {
  5585. $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
  5586. }
  5587. if (isset($channelInfo['validatepackage'])) {
  5588. $ret .= ' <validatepackage version="' .
  5589. $channelInfo['validatepackage']['attribs']['version']. '">' .
  5590. htmlspecialchars($channelInfo['validatepackage']['_content']) .
  5591. "</validatepackage>\n";
  5592. }
  5593. $ret .= " <servers>\n";
  5594. $ret .= ' <primary';
  5595. if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
  5596. $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
  5597. }
  5598. if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
  5599. $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
  5600. }
  5601. $ret .= ">\n";
  5602. if (isset($channelInfo['servers']['primary']['rest'])) {
  5603. $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], ' ');
  5604. }
  5605. $ret .= " </primary>\n";
  5606. if (isset($channelInfo['servers']['mirror'])) {
  5607. $ret .= $this->_makeMirrorsXml($channelInfo);
  5608. }
  5609. $ret .= " </servers>\n";
  5610. $ret .= "</channel>";
  5611. return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
  5612. }
  5613. /**
  5614. * Generate the <rest> tag
  5615. * @access private
  5616. */
  5617. function _makeRestXml($info, $indent)
  5618. {
  5619. $ret = $indent . "<rest>\n";
  5620. if (isset($info['baseurl']) && !isset($info['baseurl'][0])) {
  5621. $info['baseurl'] = array($info['baseurl']);
  5622. }
  5623. if (isset($info['baseurl'])) {
  5624. foreach ($info['baseurl'] as $url) {
  5625. $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
  5626. $ret .= ">" . $url['_content'] . "</baseurl>\n";
  5627. }
  5628. }
  5629. $ret .= $indent . "</rest>\n";
  5630. return $ret;
  5631. }
  5632. /**
  5633. * Generate the <mirrors> tag
  5634. * @access private
  5635. */
  5636. function _makeMirrorsXml($channelInfo)
  5637. {
  5638. $ret = "";
  5639. if (!isset($channelInfo['servers']['mirror'][0])) {
  5640. $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
  5641. }
  5642. foreach ($channelInfo['servers']['mirror'] as $mirror) {
  5643. $ret .= ' <mirror host="' . $mirror['attribs']['host'] . '"';
  5644. if (isset($mirror['attribs']['port'])) {
  5645. $ret .= ' port="' . $mirror['attribs']['port'] . '"';
  5646. }
  5647. if (isset($mirror['attribs']['ssl'])) {
  5648. $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
  5649. }
  5650. $ret .= ">\n";
  5651. if (isset($mirror['rest'])) {
  5652. if (isset($mirror['rest'])) {
  5653. $ret .= $this->_makeRestXml($mirror['rest'], ' ');
  5654. }
  5655. $ret .= " </mirror>\n";
  5656. } else {
  5657. $ret .= "/>\n";
  5658. }
  5659. }
  5660. return $ret;
  5661. }
  5662. /**
  5663. * Generate the <functions> tag
  5664. * @access private
  5665. */
  5666. function _makeFunctionsXml($functions, $indent, $rest = false)
  5667. {
  5668. $ret = '';
  5669. if (!isset($functions[0])) {
  5670. $functions = array($functions);
  5671. }
  5672. foreach ($functions as $function) {
  5673. $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
  5674. if ($rest) {
  5675. $ret .= ' uri="' . $function['attribs']['uri'] . '"';
  5676. }
  5677. $ret .= ">" . $function['_content'] . "</function>\n";
  5678. }
  5679. return $ret;
  5680. }
  5681. /**
  5682. * Validation error. Also marks the object contents as invalid
  5683. * @param error code
  5684. * @param array error information
  5685. * @access private
  5686. */
  5687. function _validateError($code, $params = array())
  5688. {
  5689. $this->_stack->push($code, 'error', $params);
  5690. $this->_isValid = false;
  5691. }
  5692. /**
  5693. * Validation warning. Does not mark the object contents invalid.
  5694. * @param error code
  5695. * @param array error information
  5696. * @access private
  5697. */
  5698. function _validateWarning($code, $params = array())
  5699. {
  5700. $this->_stack->push($code, 'warning', $params);
  5701. }
  5702. /**
  5703. * Validate parsed file.
  5704. *
  5705. * @access public
  5706. * @return boolean
  5707. */
  5708. function validate()
  5709. {
  5710. $this->_isValid = true;
  5711. $info = $this->_channelInfo;
  5712. if (empty($info['name'])) {
  5713. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
  5714. } elseif (!$this->validChannelServer($info['name'])) {
  5715. if ($info['name'] != '__uri') {
  5716. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
  5717. 'name' => $info['name']));
  5718. }
  5719. }
  5720. if (empty($info['summary'])) {
  5721. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  5722. } elseif (strpos(trim($info['summary']), "\n") !== false) {
  5723. $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  5724. array('summary' => $info['summary']));
  5725. }
  5726. if (isset($info['suggestedalias'])) {
  5727. if (!$this->validChannelServer($info['suggestedalias'])) {
  5728. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  5729. array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
  5730. }
  5731. }
  5732. if (isset($info['localalias'])) {
  5733. if (!$this->validChannelServer($info['localalias'])) {
  5734. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  5735. array('tag' => 'localalias', 'name' =>$info['localalias']));
  5736. }
  5737. }
  5738. if (isset($info['validatepackage'])) {
  5739. if (!isset($info['validatepackage']['_content'])) {
  5740. $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
  5741. }
  5742. if (!isset($info['validatepackage']['attribs']['version'])) {
  5743. $content = isset($info['validatepackage']['_content']) ?
  5744. $info['validatepackage']['_content'] :
  5745. null;
  5746. $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
  5747. array('package' => $content));
  5748. }
  5749. }
  5750. if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) &&
  5751. !is_numeric($info['servers']['primary']['attribs']['port'])) {
  5752. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
  5753. array('port' => $info['servers']['primary']['attribs']['port']));
  5754. }
  5755. if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) &&
  5756. $info['servers']['primary']['attribs']['ssl'] != 'yes') {
  5757. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  5758. array('ssl' => $info['servers']['primary']['attribs']['ssl'],
  5759. 'server' => $info['name']));
  5760. }
  5761. if (isset($info['servers']['primary']['rest']) &&
  5762. isset($info['servers']['primary']['rest']['baseurl'])) {
  5763. $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
  5764. }
  5765. if (isset($info['servers']['mirror'])) {
  5766. if ($this->_channelInfo['name'] == '__uri') {
  5767. $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
  5768. }
  5769. if (!isset($info['servers']['mirror'][0])) {
  5770. $info['servers']['mirror'] = array($info['servers']['mirror']);
  5771. }
  5772. foreach ($info['servers']['mirror'] as $mirror) {
  5773. if (!isset($mirror['attribs']['host'])) {
  5774. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
  5775. array('type' => 'mirror'));
  5776. } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
  5777. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
  5778. array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
  5779. }
  5780. if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
  5781. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  5782. array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
  5783. }
  5784. if (isset($mirror['rest'])) {
  5785. $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
  5786. $mirror['attribs']['host']);
  5787. }
  5788. }
  5789. }
  5790. return $this->_isValid;
  5791. }
  5792. /**
  5793. * @param string rest - protocol name this function applies to
  5794. * @param array the functions
  5795. * @param string the name of the parent element (mirror name, for instance)
  5796. */
  5797. function _validateFunctions($protocol, $functions, $parent = '')
  5798. {
  5799. if (!isset($functions[0])) {
  5800. $functions = array($functions);
  5801. }
  5802. foreach ($functions as $function) {
  5803. if (!isset($function['_content']) || empty($function['_content'])) {
  5804. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
  5805. array('parent' => $parent, 'protocol' => $protocol));
  5806. }
  5807. if ($protocol == 'rest') {
  5808. if (!isset($function['attribs']['type']) ||
  5809. empty($function['attribs']['type'])) {
  5810. $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE,
  5811. array('parent' => $parent, 'protocol' => $protocol));
  5812. }
  5813. } else {
  5814. if (!isset($function['attribs']['version']) ||
  5815. empty($function['attribs']['version'])) {
  5816. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
  5817. array('parent' => $parent, 'protocol' => $protocol));
  5818. }
  5819. }
  5820. }
  5821. }
  5822. /**
  5823. * Test whether a string contains a valid channel server.
  5824. * @param string $ver the package version to test
  5825. * @return bool
  5826. */
  5827. function validChannelServer($server)
  5828. {
  5829. if ($server == '__uri') {
  5830. return true;
  5831. }
  5832. return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
  5833. }
  5834. /**
  5835. * @return string|false
  5836. */
  5837. function getName()
  5838. {
  5839. if (isset($this->_channelInfo['name'])) {
  5840. return $this->_channelInfo['name'];
  5841. }
  5842. return false;
  5843. }
  5844. /**
  5845. * @return string|false
  5846. */
  5847. function getServer()
  5848. {
  5849. if (isset($this->_channelInfo['name'])) {
  5850. return $this->_channelInfo['name'];
  5851. }
  5852. return false;
  5853. }
  5854. /**
  5855. * @return int|80 port number to connect to
  5856. */
  5857. function getPort($mirror = false)
  5858. {
  5859. if ($mirror) {
  5860. if ($mir = $this->getMirror($mirror)) {
  5861. if (isset($mir['attribs']['port'])) {
  5862. return $mir['attribs']['port'];
  5863. }
  5864. if ($this->getSSL($mirror)) {
  5865. return 443;
  5866. }
  5867. return 80;
  5868. }
  5869. return false;
  5870. }
  5871. if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
  5872. return $this->_channelInfo['servers']['primary']['attribs']['port'];
  5873. }
  5874. if ($this->getSSL()) {
  5875. return 443;
  5876. }
  5877. return 80;
  5878. }
  5879. /**
  5880. * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
  5881. */
  5882. function getSSL($mirror = false)
  5883. {
  5884. if ($mirror) {
  5885. if ($mir = $this->getMirror($mirror)) {
  5886. if (isset($mir['attribs']['ssl'])) {
  5887. return true;
  5888. }
  5889. return false;
  5890. }
  5891. return false;
  5892. }
  5893. if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  5894. return true;
  5895. }
  5896. return false;
  5897. }
  5898. /**
  5899. * @return string|false
  5900. */
  5901. function getSummary()
  5902. {
  5903. if (isset($this->_channelInfo['summary'])) {
  5904. return $this->_channelInfo['summary'];
  5905. }
  5906. return false;
  5907. }
  5908. /**
  5909. * @param string protocol type
  5910. * @param string Mirror name
  5911. * @return array|false
  5912. */
  5913. function getFunctions($protocol, $mirror = false)
  5914. {
  5915. if ($this->getName() == '__uri') {
  5916. return false;
  5917. }
  5918. $function = $protocol == 'rest' ? 'baseurl' : 'function';
  5919. if ($mirror) {
  5920. if ($mir = $this->getMirror($mirror)) {
  5921. if (isset($mir[$protocol][$function])) {
  5922. return $mir[$protocol][$function];
  5923. }
  5924. }
  5925. return false;
  5926. }
  5927. if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
  5928. return $this->_channelInfo['servers']['primary'][$protocol][$function];
  5929. }
  5930. return false;
  5931. }
  5932. /**
  5933. * @param string Protocol type
  5934. * @param string Function name (null to return the
  5935. * first protocol of the type requested)
  5936. * @param string Mirror name, if any
  5937. * @return array
  5938. */
  5939. function getFunction($type, $name = null, $mirror = false)
  5940. {
  5941. $protocols = $this->getFunctions($type, $mirror);
  5942. if (!$protocols) {
  5943. return false;
  5944. }
  5945. foreach ($protocols as $protocol) {
  5946. if ($name === null) {
  5947. return $protocol;
  5948. }
  5949. if ($protocol['_content'] != $name) {
  5950. continue;
  5951. }
  5952. return $protocol;
  5953. }
  5954. return false;
  5955. }
  5956. /**
  5957. * @param string protocol type
  5958. * @param string protocol name
  5959. * @param string version
  5960. * @param string mirror name
  5961. * @return boolean
  5962. */
  5963. function supports($type, $name = null, $mirror = false, $version = '1.0')
  5964. {
  5965. $protocols = $this->getFunctions($type, $mirror);
  5966. if (!$protocols) {
  5967. return false;
  5968. }
  5969. foreach ($protocols as $protocol) {
  5970. if ($protocol['attribs']['version'] != $version) {
  5971. continue;
  5972. }
  5973. if ($name === null) {
  5974. return true;
  5975. }
  5976. if ($protocol['_content'] != $name) {
  5977. continue;
  5978. }
  5979. return true;
  5980. }
  5981. return false;
  5982. }
  5983. /**
  5984. * Determines whether a channel supports Representational State Transfer (REST) protocols
  5985. * for retrieving channel information
  5986. * @param string
  5987. * @return bool
  5988. */
  5989. function supportsREST($mirror = false)
  5990. {
  5991. if ($mirror == $this->_channelInfo['name']) {
  5992. $mirror = false;
  5993. }
  5994. if ($mirror) {
  5995. if ($mir = $this->getMirror($mirror)) {
  5996. return isset($mir['rest']);
  5997. }
  5998. return false;
  5999. }
  6000. return isset($this->_channelInfo['servers']['primary']['rest']);
  6001. }
  6002. /**
  6003. * Get the URL to access a base resource.
  6004. *
  6005. * Hyperlinks in the returned xml will be used to retrieve the proper information
  6006. * needed. This allows extreme extensibility and flexibility in implementation
  6007. * @param string Resource Type to retrieve
  6008. */
  6009. function getBaseURL($resourceType, $mirror = false)
  6010. {
  6011. if ($mirror == $this->_channelInfo['name']) {
  6012. $mirror = false;
  6013. }
  6014. if ($mirror) {
  6015. $mir = $this->getMirror($mirror);
  6016. if (!$mir) {
  6017. return false;
  6018. }
  6019. $rest = $mir['rest'];
  6020. } else {
  6021. $rest = $this->_channelInfo['servers']['primary']['rest'];
  6022. }
  6023. if (!isset($rest['baseurl'][0])) {
  6024. $rest['baseurl'] = array($rest['baseurl']);
  6025. }
  6026. foreach ($rest['baseurl'] as $baseurl) {
  6027. if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
  6028. return $baseurl['_content'];
  6029. }
  6030. }
  6031. return false;
  6032. }
  6033. /**
  6034. * Since REST does not implement RPC, provide this as a logical wrapper around
  6035. * resetFunctions for REST
  6036. * @param string|false mirror name, if any
  6037. */
  6038. function resetREST($mirror = false)
  6039. {
  6040. return $this->resetFunctions('rest', $mirror);
  6041. }
  6042. /**
  6043. * Empty all protocol definitions
  6044. * @param string protocol type
  6045. * @param string|false mirror name, if any
  6046. */
  6047. function resetFunctions($type, $mirror = false)
  6048. {
  6049. if ($mirror) {
  6050. if (isset($this->_channelInfo['servers']['mirror'])) {
  6051. $mirrors = $this->_channelInfo['servers']['mirror'];
  6052. if (!isset($mirrors[0])) {
  6053. $mirrors = array($mirrors);
  6054. }
  6055. foreach ($mirrors as $i => $mir) {
  6056. if ($mir['attribs']['host'] == $mirror) {
  6057. if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
  6058. unset($this->_channelInfo['servers']['mirror'][$i][$type]);
  6059. }
  6060. return true;
  6061. }
  6062. }
  6063. return false;
  6064. }
  6065. return false;
  6066. }
  6067. if (isset($this->_channelInfo['servers']['primary'][$type])) {
  6068. unset($this->_channelInfo['servers']['primary'][$type]);
  6069. }
  6070. return true;
  6071. }
  6072. /**
  6073. * Set a channel's protocols to the protocols supported by pearweb
  6074. */
  6075. function setDefaultPEARProtocols($version = '1.0', $mirror = false)
  6076. {
  6077. switch ($version) {
  6078. case '1.0' :
  6079. $this->resetREST($mirror);
  6080. if (!isset($this->_channelInfo['servers'])) {
  6081. $this->_channelInfo['servers'] = array('primary' =>
  6082. array('rest' => array()));
  6083. } elseif (!isset($this->_channelInfo['servers']['primary'])) {
  6084. $this->_channelInfo['servers']['primary'] = array('rest' => array());
  6085. }
  6086. return true;
  6087. break;
  6088. default :
  6089. return false;
  6090. break;
  6091. }
  6092. }
  6093. /**
  6094. * @return array
  6095. */
  6096. function getMirrors()
  6097. {
  6098. if (isset($this->_channelInfo['servers']['mirror'])) {
  6099. $mirrors = $this->_channelInfo['servers']['mirror'];
  6100. if (!isset($mirrors[0])) {
  6101. $mirrors = array($mirrors);
  6102. }
  6103. return $mirrors;
  6104. }
  6105. return array();
  6106. }
  6107. /**
  6108. * Get the unserialized XML representing a mirror
  6109. * @return array|false
  6110. */
  6111. function getMirror($server)
  6112. {
  6113. foreach ($this->getMirrors() as $mirror) {
  6114. if ($mirror['attribs']['host'] == $server) {
  6115. return $mirror;
  6116. }
  6117. }
  6118. return false;
  6119. }
  6120. /**
  6121. * @param string
  6122. * @return string|false
  6123. * @error PEAR_CHANNELFILE_ERROR_NO_NAME
  6124. * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
  6125. */
  6126. function setName($name)
  6127. {
  6128. return $this->setServer($name);
  6129. }
  6130. /**
  6131. * Set the socket number (port) that is used to connect to this channel
  6132. * @param integer
  6133. * @param string|false name of the mirror server, or false for the primary
  6134. */
  6135. function setPort($port, $mirror = false)
  6136. {
  6137. if ($mirror) {
  6138. if (!isset($this->_channelInfo['servers']['mirror'])) {
  6139. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6140. array('mirror' => $mirror));
  6141. return false;
  6142. }
  6143. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6144. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6145. if ($mirror == $mir['attribs']['host']) {
  6146. $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
  6147. return true;
  6148. }
  6149. }
  6150. return false;
  6151. } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6152. $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
  6153. $this->_isValid = false;
  6154. return true;
  6155. }
  6156. }
  6157. $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
  6158. $this->_isValid = false;
  6159. return true;
  6160. }
  6161. /**
  6162. * Set the socket number (port) that is used to connect to this channel
  6163. * @param bool Determines whether to turn on SSL support or turn it off
  6164. * @param string|false name of the mirror server, or false for the primary
  6165. */
  6166. function setSSL($ssl = true, $mirror = false)
  6167. {
  6168. if ($mirror) {
  6169. if (!isset($this->_channelInfo['servers']['mirror'])) {
  6170. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6171. array('mirror' => $mirror));
  6172. return false;
  6173. }
  6174. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6175. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6176. if ($mirror == $mir['attribs']['host']) {
  6177. if (!$ssl) {
  6178. if (isset($this->_channelInfo['servers']['mirror'][$i]
  6179. ['attribs']['ssl'])) {
  6180. unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
  6181. }
  6182. } else {
  6183. $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
  6184. }
  6185. return true;
  6186. }
  6187. }
  6188. return false;
  6189. } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6190. if (!$ssl) {
  6191. if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
  6192. unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
  6193. }
  6194. } else {
  6195. $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
  6196. }
  6197. $this->_isValid = false;
  6198. return true;
  6199. }
  6200. }
  6201. if ($ssl) {
  6202. $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
  6203. } else {
  6204. if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  6205. unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
  6206. }
  6207. }
  6208. $this->_isValid = false;
  6209. return true;
  6210. }
  6211. /**
  6212. * @param string
  6213. * @return string|false
  6214. * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
  6215. * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
  6216. */
  6217. function setServer($server, $mirror = false)
  6218. {
  6219. if (empty($server)) {
  6220. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
  6221. return false;
  6222. } elseif (!$this->validChannelServer($server)) {
  6223. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  6224. array('tag' => 'name', 'name' => $server));
  6225. return false;
  6226. }
  6227. if ($mirror) {
  6228. $found = false;
  6229. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6230. if ($mirror == $mir['attribs']['host']) {
  6231. $found = true;
  6232. break;
  6233. }
  6234. }
  6235. if (!$found) {
  6236. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6237. array('mirror' => $mirror));
  6238. return false;
  6239. }
  6240. $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
  6241. return true;
  6242. }
  6243. $this->_channelInfo['name'] = $server;
  6244. return true;
  6245. }
  6246. /**
  6247. * @param string
  6248. * @return boolean success
  6249. * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
  6250. * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
  6251. */
  6252. function setSummary($summary)
  6253. {
  6254. if (empty($summary)) {
  6255. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  6256. return false;
  6257. } elseif (strpos(trim($summary), "\n") !== false) {
  6258. $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  6259. array('summary' => $summary));
  6260. }
  6261. $this->_channelInfo['summary'] = $summary;
  6262. return true;
  6263. }
  6264. /**
  6265. * @param string
  6266. * @param boolean determines whether the alias is in channel.xml or local
  6267. * @return boolean success
  6268. */
  6269. function setAlias($alias, $local = false)
  6270. {
  6271. if (!$this->validChannelServer($alias)) {
  6272. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  6273. array('tag' => 'suggestedalias', 'name' => $alias));
  6274. return false;
  6275. }
  6276. if ($local) {
  6277. $this->_channelInfo['localalias'] = $alias;
  6278. } else {
  6279. $this->_channelInfo['suggestedalias'] = $alias;
  6280. }
  6281. return true;
  6282. }
  6283. /**
  6284. * @return string
  6285. */
  6286. function getAlias()
  6287. {
  6288. if (isset($this->_channelInfo['localalias'])) {
  6289. return $this->_channelInfo['localalias'];
  6290. }
  6291. if (isset($this->_channelInfo['suggestedalias'])) {
  6292. return $this->_channelInfo['suggestedalias'];
  6293. }
  6294. if (isset($this->_channelInfo['name'])) {
  6295. return $this->_channelInfo['name'];
  6296. }
  6297. return '';
  6298. }
  6299. /**
  6300. * Set the package validation object if it differs from PEAR's default
  6301. * The class must be includeable via changing _ in the classname to path separator,
  6302. * but no checking of this is made.
  6303. * @param string|false pass in false to reset to the default packagename regex
  6304. * @return boolean success
  6305. */
  6306. function setValidationPackage($validateclass, $version)
  6307. {
  6308. if (empty($validateclass)) {
  6309. unset($this->_channelInfo['validatepackage']);
  6310. }
  6311. $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
  6312. $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
  6313. }
  6314. /**
  6315. * Add a protocol to the provides section
  6316. * @param string protocol type
  6317. * @param string protocol version
  6318. * @param string protocol name, if any
  6319. * @param string mirror name, if this is a mirror's protocol
  6320. * @return bool
  6321. */
  6322. function addFunction($type, $version, $name = '', $mirror = false)
  6323. {
  6324. if ($mirror) {
  6325. return $this->addMirrorFunction($mirror, $type, $version, $name);
  6326. }
  6327. $set = array('attribs' => array('version' => $version), '_content' => $name);
  6328. if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
  6329. if (!isset($this->_channelInfo['servers'])) {
  6330. $this->_channelInfo['servers'] = array('primary' =>
  6331. array($type => array()));
  6332. } elseif (!isset($this->_channelInfo['servers']['primary'])) {
  6333. $this->_channelInfo['servers']['primary'] = array($type => array());
  6334. }
  6335. $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
  6336. $this->_isValid = false;
  6337. return true;
  6338. } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
  6339. $this->_channelInfo['servers']['primary'][$type]['function'] = array(
  6340. $this->_channelInfo['servers']['primary'][$type]['function']);
  6341. }
  6342. $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
  6343. return true;
  6344. }
  6345. /**
  6346. * Add a protocol to a mirror's provides section
  6347. * @param string mirror name (server)
  6348. * @param string protocol type
  6349. * @param string protocol version
  6350. * @param string protocol name, if any
  6351. */
  6352. function addMirrorFunction($mirror, $type, $version, $name = '')
  6353. {
  6354. if (!isset($this->_channelInfo['servers']['mirror'])) {
  6355. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6356. array('mirror' => $mirror));
  6357. return false;
  6358. }
  6359. $setmirror = false;
  6360. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6361. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6362. if ($mirror == $mir['attribs']['host']) {
  6363. $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  6364. break;
  6365. }
  6366. }
  6367. } else {
  6368. if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6369. $setmirror = &$this->_channelInfo['servers']['mirror'];
  6370. }
  6371. }
  6372. if (!$setmirror) {
  6373. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6374. array('mirror' => $mirror));
  6375. return false;
  6376. }
  6377. $set = array('attribs' => array('version' => $version), '_content' => $name);
  6378. if (!isset($setmirror[$type]['function'])) {
  6379. $setmirror[$type]['function'] = $set;
  6380. $this->_isValid = false;
  6381. return true;
  6382. } elseif (!isset($setmirror[$type]['function'][0])) {
  6383. $setmirror[$type]['function'] = array($setmirror[$type]['function']);
  6384. }
  6385. $setmirror[$type]['function'][] = $set;
  6386. $this->_isValid = false;
  6387. return true;
  6388. }
  6389. /**
  6390. * @param string Resource Type this url links to
  6391. * @param string URL
  6392. * @param string|false mirror name, if this is not a primary server REST base URL
  6393. */
  6394. function setBaseURL($resourceType, $url, $mirror = false)
  6395. {
  6396. if ($mirror) {
  6397. if (!isset($this->_channelInfo['servers']['mirror'])) {
  6398. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  6399. array('mirror' => $mirror));
  6400. return false;
  6401. }
  6402. $setmirror = false;
  6403. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  6404. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  6405. if ($mirror == $mir['attribs']['host']) {
  6406. $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  6407. break;
  6408. }
  6409. }
  6410. } else {
  6411. if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  6412. $setmirror = &$this->_channelInfo['servers']['mirror'];
  6413. }
  6414. }
  6415. } else {
  6416. $setmirror = &$this->_channelInfo['servers']['primary'];
  6417. }
  6418. $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
  6419. if (!isset($setmirror['rest'])) {
  6420. $setmirror['rest'] = array();
  6421. }
  6422. if (!isset($setmirror['rest']['baseurl'])) {
  6423. $setmirror['rest']['baseurl'] = $set;
  6424. $this->_isValid = false;
  6425. return true;
  6426. } elseif (!isset($setmirror['rest']['baseurl'][0])) {
  6427. $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
  6428. }
  6429. foreach ($setmirror['rest']['baseurl'] as $i => $url) {
  6430. if ($url['attribs']['type'] == $resourceType) {
  6431. $this->_isValid = false;
  6432. $setmirror['rest']['baseurl'][$i] = $set;
  6433. return true;
  6434. }
  6435. }
  6436. $setmirror['rest']['baseurl'][] = $set;
  6437. $this->_isValid = false;
  6438. return true;
  6439. }
  6440. /**
  6441. * @param string mirror server
  6442. * @param int mirror http port
  6443. * @return boolean
  6444. */
  6445. function addMirror($server, $port = null)
  6446. {
  6447. if ($this->_channelInfo['name'] == '__uri') {
  6448. return false; // the __uri channel cannot have mirrors by definition
  6449. }
  6450. $set = array('attribs' => array('host' => $server));
  6451. if (is_numeric($port)) {
  6452. $set['attribs']['port'] = $port;
  6453. }
  6454. if (!isset($this->_channelInfo['servers']['mirror'])) {
  6455. $this->_channelInfo['servers']['mirror'] = $set;
  6456. return true;
  6457. }
  6458. if (!isset($this->_channelInfo['servers']['mirror'][0])) {
  6459. $this->_channelInfo['servers']['mirror'] =
  6460. array($this->_channelInfo['servers']['mirror']);
  6461. }
  6462. $this->_channelInfo['servers']['mirror'][] = $set;
  6463. return true;
  6464. }
  6465. /**
  6466. * Retrieve the name of the validation package for this channel
  6467. * @return string|false
  6468. */
  6469. function getValidationPackage()
  6470. {
  6471. if (!$this->_isValid && !$this->validate()) {
  6472. return false;
  6473. }
  6474. if (!isset($this->_channelInfo['validatepackage'])) {
  6475. return array('attribs' => array('version' => 'default'),
  6476. '_content' => 'PEAR_Validate');
  6477. }
  6478. return $this->_channelInfo['validatepackage'];
  6479. }
  6480. /**
  6481. * Retrieve the object that can be used for custom validation
  6482. * @param string|false the name of the package to validate. If the package is
  6483. * the channel validation package, PEAR_Validate is returned
  6484. * @return PEAR_Validate|false false is returned if the validation package
  6485. * cannot be located
  6486. */
  6487. function &getValidationObject($package = false)
  6488. {
  6489. if (!class_exists('PEAR_Validate')) {
  6490. require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  6491. }
  6492. if (!$this->_isValid) {
  6493. if (!$this->validate()) {
  6494. $a = false;
  6495. return $a;
  6496. }
  6497. }
  6498. if (isset($this->_channelInfo['validatepackage'])) {
  6499. if ($package == $this->_channelInfo['validatepackage']) {
  6500. // channel validation packages are always validated by PEAR_Validate
  6501. $val = new PEAR_Validate;
  6502. return $val;
  6503. }
  6504. if (!class_exists(str_replace('.', '_',
  6505. $this->_channelInfo['validatepackage']['_content']))) {
  6506. if ($this->isIncludeable(str_replace('_', '/',
  6507. $this->_channelInfo['validatepackage']['_content']) . '.php')) {
  6508. include_once 'phar://go-pear.phar/' . str_replace('_', '/',
  6509. $this->_channelInfo['validatepackage']['_content']) . '.php';
  6510. $vclass = str_replace('.', '_',
  6511. $this->_channelInfo['validatepackage']['_content']);
  6512. $val = new $vclass;
  6513. } else {
  6514. $a = false;
  6515. return $a;
  6516. }
  6517. } else {
  6518. $vclass = str_replace('.', '_',
  6519. $this->_channelInfo['validatepackage']['_content']);
  6520. $val = new $vclass;
  6521. }
  6522. } else {
  6523. $val = new PEAR_Validate;
  6524. }
  6525. return $val;
  6526. }
  6527. function isIncludeable($path)
  6528. {
  6529. $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
  6530. foreach ($possibilities as $dir) {
  6531. if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
  6532. && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
  6533. return true;
  6534. }
  6535. }
  6536. return false;
  6537. }
  6538. /**
  6539. * This function is used by the channel updater and retrieves a value set by
  6540. * the registry, or the current time if it has not been set
  6541. * @return string
  6542. */
  6543. function lastModified()
  6544. {
  6545. if (isset($this->_channelInfo['_lastmodified'])) {
  6546. return $this->_channelInfo['_lastmodified'];
  6547. }
  6548. return time();
  6549. }
  6550. }
  6551. <?php
  6552. /**
  6553. * PEAR_ChannelFile_Parser for parsing channel.xml
  6554. *
  6555. * PHP versions 4 and 5
  6556. *
  6557. * @category pear
  6558. * @package PEAR
  6559. * @author Greg Beaver <cellog@php.net>
  6560. * @copyright 1997-2009 The Authors
  6561. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  6562. * @link http://pear.php.net/package/PEAR
  6563. * @since File available since Release 1.4.0a1
  6564. */
  6565. /**
  6566. * base xml parser class
  6567. */
  6568. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  6569. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  6570. /**
  6571. * Parser for channel.xml
  6572. * @category pear
  6573. * @package PEAR
  6574. * @author Greg Beaver <cellog@php.net>
  6575. * @copyright 1997-2009 The Authors
  6576. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  6577. * @version Release: 1.10.10
  6578. * @link http://pear.php.net/package/PEAR
  6579. * @since Class available since Release 1.4.0a1
  6580. */
  6581. class PEAR_ChannelFile_Parser extends PEAR_XMLParser
  6582. {
  6583. var $_config;
  6584. var $_logger;
  6585. var $_registry;
  6586. function setConfig(&$c)
  6587. {
  6588. $this->_config = &$c;
  6589. $this->_registry = &$c->getRegistry();
  6590. }
  6591. function setLogger(&$l)
  6592. {
  6593. $this->_logger = &$l;
  6594. }
  6595. function parse($data, $file)
  6596. {
  6597. if (PEAR::isError($err = parent::parse($data, $file))) {
  6598. return $err;
  6599. }
  6600. $ret = new PEAR_ChannelFile;
  6601. $ret->setConfig($this->_config);
  6602. if (isset($this->_logger)) {
  6603. $ret->setLogger($this->_logger);
  6604. }
  6605. $ret->fromArray($this->_unserializedData);
  6606. // make sure the filelist is in the easy to read format needed
  6607. $ret->flattenFilelist();
  6608. $ret->setPackagefile($file, $archive);
  6609. return $ret;
  6610. }
  6611. }<?php
  6612. /**
  6613. * PEAR_Command, command pattern class
  6614. *
  6615. * PHP versions 4 and 5
  6616. *
  6617. * @category pear
  6618. * @package PEAR
  6619. * @author Stig Bakken <ssb@php.net>
  6620. * @author Greg Beaver <cellog@php.net>
  6621. * @copyright 1997-2009 The Authors
  6622. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  6623. * @link http://pear.php.net/package/PEAR
  6624. * @since File available since Release 0.1
  6625. */
  6626. /**
  6627. * Needed for error handling
  6628. */
  6629. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  6630. require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  6631. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  6632. /**
  6633. * List of commands and what classes they are implemented in.
  6634. * @var array command => implementing class
  6635. */
  6636. $GLOBALS['_PEAR_Command_commandlist'] = array();
  6637. /**
  6638. * List of commands and their descriptions
  6639. * @var array command => description
  6640. */
  6641. $GLOBALS['_PEAR_Command_commanddesc'] = array();
  6642. /**
  6643. * List of shortcuts to common commands.
  6644. * @var array shortcut => command
  6645. */
  6646. $GLOBALS['_PEAR_Command_shortcuts'] = array();
  6647. /**
  6648. * Array of command objects
  6649. * @var array class => object
  6650. */
  6651. $GLOBALS['_PEAR_Command_objects'] = array();
  6652. /**
  6653. * PEAR command class, a simple factory class for administrative
  6654. * commands.
  6655. *
  6656. * How to implement command classes:
  6657. *
  6658. * - The class must be called PEAR_Command_Nnn, installed in the
  6659. * "PEAR/Common" subdir, with a method called getCommands() that
  6660. * returns an array of the commands implemented by the class (see
  6661. * PEAR/Command/Install.php for an example).
  6662. *
  6663. * - The class must implement a run() function that is called with three
  6664. * params:
  6665. *
  6666. * (string) command name
  6667. * (array) assoc array with options, freely defined by each
  6668. * command, for example:
  6669. * array('force' => true)
  6670. * (array) list of the other parameters
  6671. *
  6672. * The run() function returns a PEAR_CommandResponse object. Use
  6673. * these methods to get information:
  6674. *
  6675. * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
  6676. * *_PARTIAL means that you need to issue at least
  6677. * one more command to complete the operation
  6678. * (used for example for validation steps).
  6679. *
  6680. * string getMessage() Returns a message for the user. Remember,
  6681. * no HTML or other interface-specific markup.
  6682. *
  6683. * If something unexpected happens, run() returns a PEAR error.
  6684. *
  6685. * - DON'T OUTPUT ANYTHING! Return text for output instead.
  6686. *
  6687. * - DON'T USE HTML! The text you return will be used from both Gtk,
  6688. * web and command-line interfaces, so for now, keep everything to
  6689. * plain text.
  6690. *
  6691. * - DON'T USE EXIT OR DIE! Always use pear errors. From static
  6692. * classes do PEAR::raiseError(), from other classes do
  6693. * $this->raiseError().
  6694. * @category pear
  6695. * @package PEAR
  6696. * @author Stig Bakken <ssb@php.net>
  6697. * @author Greg Beaver <cellog@php.net>
  6698. * @copyright 1997-2009 The Authors
  6699. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  6700. * @version Release: 1.10.10
  6701. * @link http://pear.php.net/package/PEAR
  6702. * @since Class available since Release 0.1
  6703. */
  6704. class PEAR_Command
  6705. {
  6706. // {{{ factory()
  6707. /**
  6708. * Get the right object for executing a command.
  6709. *
  6710. * @param string $command The name of the command
  6711. * @param object $config Instance of PEAR_Config object
  6712. *
  6713. * @return object the command object or a PEAR error
  6714. */
  6715. public static function &factory($command, &$config)
  6716. {
  6717. if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6718. PEAR_Command::registerCommands();
  6719. }
  6720. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6721. $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6722. }
  6723. if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6724. $a = PEAR::raiseError("unknown command `$command'");
  6725. return $a;
  6726. }
  6727. $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  6728. if (!class_exists($class)) {
  6729. require_once $GLOBALS['_PEAR_Command_objects'][$class];
  6730. }
  6731. if (!class_exists($class)) {
  6732. $a = PEAR::raiseError("unknown command `$command'");
  6733. return $a;
  6734. }
  6735. $ui =& PEAR_Command::getFrontendObject();
  6736. $obj = new $class($ui, $config);
  6737. return $obj;
  6738. }
  6739. // }}}
  6740. // {{{ & getObject()
  6741. public static function &getObject($command)
  6742. {
  6743. $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  6744. if (!class_exists($class)) {
  6745. require_once $GLOBALS['_PEAR_Command_objects'][$class];
  6746. }
  6747. if (!class_exists($class)) {
  6748. return PEAR::raiseError("unknown command `$command'");
  6749. }
  6750. $ui =& PEAR_Command::getFrontendObject();
  6751. $config = &PEAR_Config::singleton();
  6752. $obj = new $class($ui, $config);
  6753. return $obj;
  6754. }
  6755. // }}}
  6756. // {{{ & getFrontendObject()
  6757. /**
  6758. * Get instance of frontend object.
  6759. *
  6760. * @return object|PEAR_Error
  6761. */
  6762. public static function &getFrontendObject()
  6763. {
  6764. $a = &PEAR_Frontend::singleton();
  6765. return $a;
  6766. }
  6767. // }}}
  6768. // {{{ & setFrontendClass()
  6769. /**
  6770. * Load current frontend class.
  6771. *
  6772. * @param string $uiclass Name of class implementing the frontend
  6773. *
  6774. * @return object the frontend object, or a PEAR error
  6775. */
  6776. public static function &setFrontendClass($uiclass)
  6777. {
  6778. $a = &PEAR_Frontend::setFrontendClass($uiclass);
  6779. return $a;
  6780. }
  6781. // }}}
  6782. // {{{ setFrontendType()
  6783. /**
  6784. * Set current frontend.
  6785. *
  6786. * @param string $uitype Name of the frontend type (for example "CLI")
  6787. *
  6788. * @return object the frontend object, or a PEAR error
  6789. */
  6790. public static function setFrontendType($uitype)
  6791. {
  6792. $uiclass = 'PEAR_Frontend_' . $uitype;
  6793. return PEAR_Command::setFrontendClass($uiclass);
  6794. }
  6795. // }}}
  6796. // {{{ registerCommands()
  6797. /**
  6798. * Scan through the Command directory looking for classes
  6799. * and see what commands they implement.
  6800. *
  6801. * @param bool (optional) if FALSE (default), the new list of
  6802. * commands should replace the current one. If TRUE,
  6803. * new entries will be merged with old.
  6804. *
  6805. * @param string (optional) where (what directory) to look for
  6806. * classes, defaults to the Command subdirectory of
  6807. * the directory from where this file (__FILE__) is
  6808. * included.
  6809. *
  6810. * @return bool TRUE on success, a PEAR error on failure
  6811. */
  6812. public static function registerCommands($merge = false, $dir = null)
  6813. {
  6814. $parser = new PEAR_XMLParser;
  6815. if ($dir === null) {
  6816. $dir = dirname(__FILE__) . '/Command';
  6817. }
  6818. if (!is_dir($dir)) {
  6819. return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
  6820. }
  6821. $dp = @opendir($dir);
  6822. if (empty($dp)) {
  6823. return PEAR::raiseError("registerCommands: opendir($dir) failed");
  6824. }
  6825. if (!$merge) {
  6826. $GLOBALS['_PEAR_Command_commandlist'] = array();
  6827. }
  6828. while ($file = readdir($dp)) {
  6829. if ($file[0] == '.' || substr($file, -4) != '.xml') {
  6830. continue;
  6831. }
  6832. $f = substr($file, 0, -4);
  6833. $class = "PEAR_Command_" . $f;
  6834. // List of commands
  6835. if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
  6836. $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php';
  6837. }
  6838. $parser->parse(file_get_contents("$dir/$file"));
  6839. $implements = $parser->getData();
  6840. foreach ($implements as $command => $desc) {
  6841. if ($command == 'attribs') {
  6842. continue;
  6843. }
  6844. if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6845. return PEAR::raiseError('Command "' . $command . '" already registered in ' .
  6846. 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  6847. }
  6848. $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
  6849. $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
  6850. if (isset($desc['shortcut'])) {
  6851. $shortcut = $desc['shortcut'];
  6852. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
  6853. return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
  6854. 'registered to command "' . $command . '" in class "' .
  6855. $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  6856. }
  6857. $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
  6858. }
  6859. if (isset($desc['options']) && $desc['options']) {
  6860. foreach ($desc['options'] as $oname => $option) {
  6861. if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
  6862. return PEAR::raiseError('Option "' . $oname . '" short option "' .
  6863. $option['shortopt'] . '" must be ' .
  6864. 'only 1 character in Command "' . $command . '" in class "' .
  6865. $class . '"');
  6866. }
  6867. }
  6868. }
  6869. }
  6870. }
  6871. ksort($GLOBALS['_PEAR_Command_shortcuts']);
  6872. ksort($GLOBALS['_PEAR_Command_commandlist']);
  6873. @closedir($dp);
  6874. return true;
  6875. }
  6876. // }}}
  6877. // {{{ getCommands()
  6878. /**
  6879. * Get the list of currently supported commands, and what
  6880. * classes implement them.
  6881. *
  6882. * @return array command => implementing class
  6883. */
  6884. public static function getCommands()
  6885. {
  6886. if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6887. PEAR_Command::registerCommands();
  6888. }
  6889. return $GLOBALS['_PEAR_Command_commandlist'];
  6890. }
  6891. // }}}
  6892. // {{{ getShortcuts()
  6893. /**
  6894. * Get the list of command shortcuts.
  6895. *
  6896. * @return array shortcut => command
  6897. */
  6898. public static function getShortcuts()
  6899. {
  6900. if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
  6901. PEAR_Command::registerCommands();
  6902. }
  6903. return $GLOBALS['_PEAR_Command_shortcuts'];
  6904. }
  6905. // }}}
  6906. // {{{ getGetoptArgs()
  6907. /**
  6908. * Compiles arguments for getopt.
  6909. *
  6910. * @param string $command command to get optstring for
  6911. * @param string $short_args (reference) short getopt format
  6912. * @param array $long_args (reference) long getopt format
  6913. *
  6914. * @return void
  6915. */
  6916. public static function getGetoptArgs($command, &$short_args, &$long_args)
  6917. {
  6918. if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6919. PEAR_Command::registerCommands();
  6920. }
  6921. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6922. $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6923. }
  6924. if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6925. return null;
  6926. }
  6927. $obj = &PEAR_Command::getObject($command);
  6928. return $obj->getGetoptArgs($command, $short_args, $long_args);
  6929. }
  6930. // }}}
  6931. // {{{ getDescription()
  6932. /**
  6933. * Get description for a command.
  6934. *
  6935. * @param string $command Name of the command
  6936. *
  6937. * @return string command description
  6938. */
  6939. public static function getDescription($command)
  6940. {
  6941. if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
  6942. return null;
  6943. }
  6944. return $GLOBALS['_PEAR_Command_commanddesc'][$command];
  6945. }
  6946. // }}}
  6947. // {{{ getHelp()
  6948. /**
  6949. * Get help for command.
  6950. *
  6951. * @param string $command Name of the command to return help for
  6952. */
  6953. public static function getHelp($command)
  6954. {
  6955. $cmds = PEAR_Command::getCommands();
  6956. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6957. $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6958. }
  6959. if (isset($cmds[$command])) {
  6960. $obj = &PEAR_Command::getObject($command);
  6961. return $obj->getHelp($command);
  6962. }
  6963. return false;
  6964. }
  6965. // }}}
  6966. }<?php
  6967. /**
  6968. * PEAR_Command_Common base class
  6969. *
  6970. * PHP versions 4 and 5
  6971. *
  6972. * @category pear
  6973. * @package PEAR
  6974. * @author Stig Bakken <ssb@php.net>
  6975. * @author Greg Beaver <cellog@php.net>
  6976. * @copyright 1997-2009 The Authors
  6977. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  6978. * @link http://pear.php.net/package/PEAR
  6979. * @since File available since Release 0.1
  6980. */
  6981. /**
  6982. * base class
  6983. */
  6984. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  6985. /**
  6986. * PEAR commands base class
  6987. *
  6988. * @category pear
  6989. * @package PEAR
  6990. * @author Stig Bakken <ssb@php.net>
  6991. * @author Greg Beaver <cellog@php.net>
  6992. * @copyright 1997-2009 The Authors
  6993. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  6994. * @version Release: 1.10.10
  6995. * @link http://pear.php.net/package/PEAR
  6996. * @since Class available since Release 0.1
  6997. */
  6998. class PEAR_Command_Common extends PEAR
  6999. {
  7000. /**
  7001. * PEAR_Config object used to pass user system and configuration
  7002. * on when executing commands
  7003. *
  7004. * @var PEAR_Config
  7005. */
  7006. var $config;
  7007. /**
  7008. * @var PEAR_Registry
  7009. * @access protected
  7010. */
  7011. var $_registry;
  7012. /**
  7013. * User Interface object, for all interaction with the user.
  7014. * @var object
  7015. */
  7016. var $ui;
  7017. var $_deps_rel_trans = array(
  7018. 'lt' => '<',
  7019. 'le' => '<=',
  7020. 'eq' => '=',
  7021. 'ne' => '!=',
  7022. 'gt' => '>',
  7023. 'ge' => '>=',
  7024. 'has' => '=='
  7025. );
  7026. var $_deps_type_trans = array(
  7027. 'pkg' => 'package',
  7028. 'ext' => 'extension',
  7029. 'php' => 'PHP',
  7030. 'prog' => 'external program',
  7031. 'ldlib' => 'external library for linking',
  7032. 'rtlib' => 'external runtime library',
  7033. 'os' => 'operating system',
  7034. 'websrv' => 'web server',
  7035. 'sapi' => 'SAPI backend'
  7036. );
  7037. /**
  7038. * PEAR_Command_Common constructor.
  7039. *
  7040. * @access public
  7041. */
  7042. function __construct(&$ui, &$config)
  7043. {
  7044. parent::__construct();
  7045. $this->config = &$config;
  7046. $this->ui = &$ui;
  7047. }
  7048. /**
  7049. * Return a list of all the commands defined by this class.
  7050. * @return array list of commands
  7051. * @access public
  7052. */
  7053. function getCommands()
  7054. {
  7055. $ret = array();
  7056. foreach (array_keys($this->commands) as $command) {
  7057. $ret[$command] = $this->commands[$command]['summary'];
  7058. }
  7059. return $ret;
  7060. }
  7061. /**
  7062. * Return a list of all the command shortcuts defined by this class.
  7063. * @return array shortcut => command
  7064. * @access public
  7065. */
  7066. function getShortcuts()
  7067. {
  7068. $ret = array();
  7069. foreach (array_keys($this->commands) as $command) {
  7070. if (isset($this->commands[$command]['shortcut'])) {
  7071. $ret[$this->commands[$command]['shortcut']] = $command;
  7072. }
  7073. }
  7074. return $ret;
  7075. }
  7076. function getOptions($command)
  7077. {
  7078. $shortcuts = $this->getShortcuts();
  7079. if (isset($shortcuts[$command])) {
  7080. $command = $shortcuts[$command];
  7081. }
  7082. if (isset($this->commands[$command]) &&
  7083. isset($this->commands[$command]['options'])) {
  7084. return $this->commands[$command]['options'];
  7085. }
  7086. return null;
  7087. }
  7088. function getGetoptArgs($command, &$short_args, &$long_args)
  7089. {
  7090. $short_args = '';
  7091. $long_args = array();
  7092. if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
  7093. return;
  7094. }
  7095. reset($this->commands[$command]['options']);
  7096. foreach ($this->commands[$command]['options'] as $option => $info) {
  7097. $larg = $sarg = '';
  7098. if (isset($info['arg'])) {
  7099. if ($info['arg'][0] == '(') {
  7100. $larg = '==';
  7101. $sarg = '::';
  7102. $arg = substr($info['arg'], 1, -1);
  7103. } else {
  7104. $larg = '=';
  7105. $sarg = ':';
  7106. $arg = $info['arg'];
  7107. }
  7108. }
  7109. if (isset($info['shortopt'])) {
  7110. $short_args .= $info['shortopt'] . $sarg;
  7111. }
  7112. $long_args[] = $option . $larg;
  7113. }
  7114. }
  7115. /**
  7116. * Returns the help message for the given command
  7117. *
  7118. * @param string $command The command
  7119. * @return mixed A fail string if the command does not have help or
  7120. * a two elements array containing [0]=>help string,
  7121. * [1]=> help string for the accepted cmd args
  7122. */
  7123. function getHelp($command)
  7124. {
  7125. $config = &PEAR_Config::singleton();
  7126. if (!isset($this->commands[$command])) {
  7127. return "No such command \"$command\"";
  7128. }
  7129. $help = null;
  7130. if (isset($this->commands[$command]['doc'])) {
  7131. $help = $this->commands[$command]['doc'];
  7132. }
  7133. if (empty($help)) {
  7134. // XXX (cox) Fallback to summary if there is no doc (show both?)
  7135. if (!isset($this->commands[$command]['summary'])) {
  7136. return "No help for command \"$command\"";
  7137. }
  7138. $help = $this->commands[$command]['summary'];
  7139. }
  7140. if (preg_match_all('/{config\s+([^\}]+)}/', $help, $matches)) {
  7141. foreach($matches[0] as $k => $v) {
  7142. $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
  7143. }
  7144. }
  7145. return array($help, $this->getHelpArgs($command));
  7146. }
  7147. /**
  7148. * Returns the help for the accepted arguments of a command
  7149. *
  7150. * @param string $command
  7151. * @return string The help string
  7152. */
  7153. function getHelpArgs($command)
  7154. {
  7155. if (isset($this->commands[$command]['options']) &&
  7156. count($this->commands[$command]['options']))
  7157. {
  7158. $help = "Options:\n";
  7159. foreach ($this->commands[$command]['options'] as $k => $v) {
  7160. if (isset($v['arg'])) {
  7161. if ($v['arg'][0] == '(') {
  7162. $arg = substr($v['arg'], 1, -1);
  7163. $sapp = " [$arg]";
  7164. $lapp = "[=$arg]";
  7165. } else {
  7166. $sapp = " $v[arg]";
  7167. $lapp = "=$v[arg]";
  7168. }
  7169. } else {
  7170. $sapp = $lapp = "";
  7171. }
  7172. if (isset($v['shortopt'])) {
  7173. $s = $v['shortopt'];
  7174. $help .= " -$s$sapp, --$k$lapp\n";
  7175. } else {
  7176. $help .= " --$k$lapp\n";
  7177. }
  7178. $p = " ";
  7179. $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
  7180. $help .= " $doc\n";
  7181. }
  7182. return $help;
  7183. }
  7184. return null;
  7185. }
  7186. function run($command, $options, $params)
  7187. {
  7188. if (empty($this->commands[$command]['function'])) {
  7189. // look for shortcuts
  7190. foreach (array_keys($this->commands) as $cmd) {
  7191. if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
  7192. if (empty($this->commands[$cmd]['function'])) {
  7193. return $this->raiseError("unknown command `$command'");
  7194. } else {
  7195. $func = $this->commands[$cmd]['function'];
  7196. }
  7197. $command = $cmd;
  7198. //$command = $this->commands[$cmd]['function'];
  7199. break;
  7200. }
  7201. }
  7202. } else {
  7203. $func = $this->commands[$command]['function'];
  7204. }
  7205. return $this->$func($command, $options, $params);
  7206. }
  7207. }
  7208. <?php
  7209. /**
  7210. * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
  7211. *
  7212. * PHP versions 4 and 5
  7213. *
  7214. * @category pear
  7215. * @package PEAR
  7216. * @author Stig Bakken <ssb@php.net>
  7217. * @author Greg Beaver <cellog@php.net>
  7218. * @copyright 1997-2009 The Authors
  7219. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  7220. * @link http://pear.php.net/package/PEAR
  7221. * @since File available since Release 0.1
  7222. */
  7223. /**
  7224. * base class
  7225. */
  7226. require_once 'phar://go-pear.phar/' . 'PEAR/Command/Common.php';
  7227. /**
  7228. * PEAR commands for installation or deinstallation/upgrading of
  7229. * packages.
  7230. *
  7231. * @category pear
  7232. * @package PEAR
  7233. * @author Stig Bakken <ssb@php.net>
  7234. * @author Greg Beaver <cellog@php.net>
  7235. * @copyright 1997-2009 The Authors
  7236. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  7237. * @version Release: 1.10.10
  7238. * @link http://pear.php.net/package/PEAR
  7239. * @since Class available since Release 0.1
  7240. */
  7241. class PEAR_Command_Install extends PEAR_Command_Common
  7242. {
  7243. // {{{ properties
  7244. var $commands = array(
  7245. 'install' => array(
  7246. 'summary' => 'Install Package',
  7247. 'function' => 'doInstall',
  7248. 'shortcut' => 'i',
  7249. 'options' => array(
  7250. 'force' => array(
  7251. 'shortopt' => 'f',
  7252. 'doc' => 'will overwrite newer installed packages',
  7253. ),
  7254. 'loose' => array(
  7255. 'shortopt' => 'l',
  7256. 'doc' => 'do not check for recommended dependency version',
  7257. ),
  7258. 'nodeps' => array(
  7259. 'shortopt' => 'n',
  7260. 'doc' => 'ignore dependencies, install anyway',
  7261. ),
  7262. 'register-only' => array(
  7263. 'shortopt' => 'r',
  7264. 'doc' => 'do not install files, only register the package as installed',
  7265. ),
  7266. 'soft' => array(
  7267. 'shortopt' => 's',
  7268. 'doc' => 'soft install, fail silently, or upgrade if already installed',
  7269. ),
  7270. 'nobuild' => array(
  7271. 'shortopt' => 'B',
  7272. 'doc' => 'don\'t build C extensions',
  7273. ),
  7274. 'configureoptions' => array(
  7275. 'shortopt' => 'D',
  7276. 'arg' => 'OPTION1=VALUE[ OPTION2=VALUE]',
  7277. 'doc' => 'space-delimited list of configure options',
  7278. ),
  7279. 'nocompress' => array(
  7280. 'shortopt' => 'Z',
  7281. 'doc' => 'request uncompressed files when downloading',
  7282. ),
  7283. 'installroot' => array(
  7284. 'shortopt' => 'R',
  7285. 'arg' => 'DIR',
  7286. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  7287. ),
  7288. 'packagingroot' => array(
  7289. 'shortopt' => 'P',
  7290. 'arg' => 'DIR',
  7291. 'doc' => 'root directory used when packaging files, like RPM packaging',
  7292. ),
  7293. 'ignore-errors' => array(
  7294. 'doc' => 'force install even if there were errors',
  7295. ),
  7296. 'alldeps' => array(
  7297. 'shortopt' => 'a',
  7298. 'doc' => 'install all required and optional dependencies',
  7299. ),
  7300. 'onlyreqdeps' => array(
  7301. 'shortopt' => 'o',
  7302. 'doc' => 'install all required dependencies',
  7303. ),
  7304. 'offline' => array(
  7305. 'shortopt' => 'O',
  7306. 'doc' => 'do not attempt to download any urls or contact channels',
  7307. ),
  7308. 'pretend' => array(
  7309. 'shortopt' => 'p',
  7310. 'doc' => 'Only list the packages that would be downloaded',
  7311. ),
  7312. ),
  7313. 'doc' => '[channel/]<package> ...
  7314. Installs one or more PEAR packages. You can specify a package to
  7315. install in four ways:
  7316. "Package-1.0.tgz" : installs from a local file
  7317. "http://example.com/Package-1.0.tgz" : installs from
  7318. anywhere on the net.
  7319. "package.xml" : installs the package described in
  7320. package.xml. Useful for testing, or for wrapping a PEAR package in
  7321. another package manager such as RPM.
  7322. "Package[-version/state][.tar]" : queries your default channel\'s server
  7323. ({config master_server}) and downloads the newest package with
  7324. the preferred quality/state ({config preferred_state}).
  7325. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  7326. Package state beta, use "Package-beta." To retrieve an uncompressed
  7327. file, append .tar (make sure there is no file by the same name first)
  7328. To download a package from another channel, prefix with the channel name like
  7329. "channel/Package"
  7330. More than one package may be specified at once. It is ok to mix these
  7331. four ways of specifying packages.
  7332. '),
  7333. 'upgrade' => array(
  7334. 'summary' => 'Upgrade Package',
  7335. 'function' => 'doInstall',
  7336. 'shortcut' => 'up',
  7337. 'options' => array(
  7338. 'channel' => array(
  7339. 'shortopt' => 'c',
  7340. 'doc' => 'upgrade packages from a specific channel',
  7341. 'arg' => 'CHAN',
  7342. ),
  7343. 'force' => array(
  7344. 'shortopt' => 'f',
  7345. 'doc' => 'overwrite newer installed packages',
  7346. ),
  7347. 'loose' => array(
  7348. 'shortopt' => 'l',
  7349. 'doc' => 'do not check for recommended dependency version',
  7350. ),
  7351. 'nodeps' => array(
  7352. 'shortopt' => 'n',
  7353. 'doc' => 'ignore dependencies, upgrade anyway',
  7354. ),
  7355. 'register-only' => array(
  7356. 'shortopt' => 'r',
  7357. 'doc' => 'do not install files, only register the package as upgraded',
  7358. ),
  7359. 'nobuild' => array(
  7360. 'shortopt' => 'B',
  7361. 'doc' => 'don\'t build C extensions',
  7362. ),
  7363. 'nocompress' => array(
  7364. 'shortopt' => 'Z',
  7365. 'doc' => 'request uncompressed files when downloading',
  7366. ),
  7367. 'installroot' => array(
  7368. 'shortopt' => 'R',
  7369. 'arg' => 'DIR',
  7370. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  7371. ),
  7372. 'ignore-errors' => array(
  7373. 'doc' => 'force install even if there were errors',
  7374. ),
  7375. 'alldeps' => array(
  7376. 'shortopt' => 'a',
  7377. 'doc' => 'install all required and optional dependencies',
  7378. ),
  7379. 'onlyreqdeps' => array(
  7380. 'shortopt' => 'o',
  7381. 'doc' => 'install all required dependencies',
  7382. ),
  7383. 'offline' => array(
  7384. 'shortopt' => 'O',
  7385. 'doc' => 'do not attempt to download any urls or contact channels',
  7386. ),
  7387. 'pretend' => array(
  7388. 'shortopt' => 'p',
  7389. 'doc' => 'Only list the packages that would be downloaded',
  7390. ),
  7391. ),
  7392. 'doc' => '<package> ...
  7393. Upgrades one or more PEAR packages. See documentation for the
  7394. "install" command for ways to specify a package.
  7395. When upgrading, your package will be updated if the provided new
  7396. package has a higher version number (use the -f option if you need to
  7397. upgrade anyway).
  7398. More than one package may be specified at once.
  7399. '),
  7400. 'upgrade-all' => array(
  7401. 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]',
  7402. 'function' => 'doUpgradeAll',
  7403. 'shortcut' => 'ua',
  7404. 'options' => array(
  7405. 'channel' => array(
  7406. 'shortopt' => 'c',
  7407. 'doc' => 'upgrade packages from a specific channel',
  7408. 'arg' => 'CHAN',
  7409. ),
  7410. 'nodeps' => array(
  7411. 'shortopt' => 'n',
  7412. 'doc' => 'ignore dependencies, upgrade anyway',
  7413. ),
  7414. 'register-only' => array(
  7415. 'shortopt' => 'r',
  7416. 'doc' => 'do not install files, only register the package as upgraded',
  7417. ),
  7418. 'nobuild' => array(
  7419. 'shortopt' => 'B',
  7420. 'doc' => 'don\'t build C extensions',
  7421. ),
  7422. 'nocompress' => array(
  7423. 'shortopt' => 'Z',
  7424. 'doc' => 'request uncompressed files when downloading',
  7425. ),
  7426. 'installroot' => array(
  7427. 'shortopt' => 'R',
  7428. 'arg' => 'DIR',
  7429. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  7430. ),
  7431. 'ignore-errors' => array(
  7432. 'doc' => 'force install even if there were errors',
  7433. ),
  7434. 'loose' => array(
  7435. 'doc' => 'do not check for recommended dependency version',
  7436. ),
  7437. ),
  7438. 'doc' => '
  7439. WARNING: This function is deprecated in favor of using the upgrade command with no params
  7440. Upgrades all packages that have a newer release available. Upgrades are
  7441. done only if there is a release available of the state specified in
  7442. "preferred_state" (currently {config preferred_state}), or a state considered
  7443. more stable.
  7444. '),
  7445. 'uninstall' => array(
  7446. 'summary' => 'Un-install Package',
  7447. 'function' => 'doUninstall',
  7448. 'shortcut' => 'un',
  7449. 'options' => array(
  7450. 'nodeps' => array(
  7451. 'shortopt' => 'n',
  7452. 'doc' => 'ignore dependencies, uninstall anyway',
  7453. ),
  7454. 'register-only' => array(
  7455. 'shortopt' => 'r',
  7456. 'doc' => 'do not remove files, only register the packages as not installed',
  7457. ),
  7458. 'installroot' => array(
  7459. 'shortopt' => 'R',
  7460. 'arg' => 'DIR',
  7461. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  7462. ),
  7463. 'ignore-errors' => array(
  7464. 'doc' => 'force install even if there were errors',
  7465. ),
  7466. 'offline' => array(
  7467. 'shortopt' => 'O',
  7468. 'doc' => 'do not attempt to uninstall remotely',
  7469. ),
  7470. ),
  7471. 'doc' => '[channel/]<package> ...
  7472. Uninstalls one or more PEAR packages. More than one package may be
  7473. specified at once. Prefix with channel name to uninstall from a
  7474. channel not in your default channel ({config default_channel})
  7475. '),
  7476. 'bundle' => array(
  7477. 'summary' => 'Unpacks a Pecl Package',
  7478. 'function' => 'doBundle',
  7479. 'shortcut' => 'bun',
  7480. 'options' => array(
  7481. 'destination' => array(
  7482. 'shortopt' => 'd',
  7483. 'arg' => 'DIR',
  7484. 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  7485. ),
  7486. 'force' => array(
  7487. 'shortopt' => 'f',
  7488. 'doc' => 'Force the unpacking even if there were errors in the package',
  7489. ),
  7490. ),
  7491. 'doc' => '<package>
  7492. Unpacks a Pecl Package into the selected location. It will download the
  7493. package if needed.
  7494. '),
  7495. 'run-scripts' => array(
  7496. 'summary' => 'Run Post-Install Scripts bundled with a package',
  7497. 'function' => 'doRunScripts',
  7498. 'shortcut' => 'rs',
  7499. 'options' => array(
  7500. ),
  7501. 'doc' => '<package>
  7502. Run post-installation scripts in package <package>, if any exist.
  7503. '),
  7504. );
  7505. // }}}
  7506. // {{{ constructor
  7507. /**
  7508. * PEAR_Command_Install constructor.
  7509. *
  7510. * @access public
  7511. */
  7512. function __construct(&$ui, &$config)
  7513. {
  7514. parent::__construct($ui, $config);
  7515. }
  7516. // }}}
  7517. /**
  7518. * For unit testing purposes
  7519. */
  7520. function &getDownloader(&$ui, $options, &$config)
  7521. {
  7522. if (!class_exists('PEAR_Downloader')) {
  7523. require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php';
  7524. }
  7525. $a = new PEAR_Downloader($ui, $options, $config);
  7526. return $a;
  7527. }
  7528. /**
  7529. * For unit testing purposes
  7530. */
  7531. function &getInstaller(&$ui)
  7532. {
  7533. if (!class_exists('PEAR_Installer')) {
  7534. require_once 'phar://go-pear.phar/' . 'PEAR/Installer.php';
  7535. }
  7536. $a = new PEAR_Installer($ui);
  7537. return $a;
  7538. }
  7539. function enableExtension($binaries, $type)
  7540. {
  7541. if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  7542. return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  7543. }
  7544. $ini = $this->_parseIni($phpini);
  7545. if (PEAR::isError($ini)) {
  7546. return $ini;
  7547. }
  7548. $line = 0;
  7549. if ($type == 'extsrc' || $type == 'extbin') {
  7550. $search = 'extensions';
  7551. $enable = 'extension';
  7552. } else {
  7553. $search = 'zend_extensions';
  7554. ob_start();
  7555. phpinfo(INFO_GENERAL);
  7556. $info = ob_get_contents();
  7557. ob_end_clean();
  7558. $debug = function_exists('leak') ? '_debug' : '';
  7559. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  7560. $enable = 'zend_extension' . $debug . $ts;
  7561. }
  7562. foreach ($ini[$search] as $line => $extension) {
  7563. if (in_array($extension, $binaries, true) || in_array(
  7564. $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  7565. // already enabled - assume if one is, all are
  7566. return true;
  7567. }
  7568. }
  7569. if ($line) {
  7570. $newini = array_slice($ini['all'], 0, $line);
  7571. } else {
  7572. $newini = array();
  7573. }
  7574. foreach ($binaries as $binary) {
  7575. if ($ini['extension_dir']) {
  7576. $binary = basename($binary);
  7577. }
  7578. $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
  7579. }
  7580. $newini = array_merge($newini, array_slice($ini['all'], $line));
  7581. $fp = @fopen($phpini, 'wb');
  7582. if (!$fp) {
  7583. return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  7584. }
  7585. foreach ($newini as $line) {
  7586. fwrite($fp, $line);
  7587. }
  7588. fclose($fp);
  7589. return true;
  7590. }
  7591. function disableExtension($binaries, $type)
  7592. {
  7593. if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  7594. return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  7595. }
  7596. $ini = $this->_parseIni($phpini);
  7597. if (PEAR::isError($ini)) {
  7598. return $ini;
  7599. }
  7600. $line = 0;
  7601. if ($type == 'extsrc' || $type == 'extbin') {
  7602. $search = 'extensions';
  7603. $enable = 'extension';
  7604. } else {
  7605. $search = 'zend_extensions';
  7606. ob_start();
  7607. phpinfo(INFO_GENERAL);
  7608. $info = ob_get_contents();
  7609. ob_end_clean();
  7610. $debug = function_exists('leak') ? '_debug' : '';
  7611. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  7612. $enable = 'zend_extension' . $debug . $ts;
  7613. }
  7614. $found = false;
  7615. foreach ($ini[$search] as $line => $extension) {
  7616. if (in_array($extension, $binaries, true) || in_array(
  7617. $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  7618. $found = true;
  7619. break;
  7620. }
  7621. }
  7622. if (!$found) {
  7623. // not enabled
  7624. return true;
  7625. }
  7626. $fp = @fopen($phpini, 'wb');
  7627. if (!$fp) {
  7628. return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  7629. }
  7630. if ($line) {
  7631. $newini = array_slice($ini['all'], 0, $line);
  7632. // delete the enable line
  7633. $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
  7634. } else {
  7635. $newini = array_slice($ini['all'], 1);
  7636. }
  7637. foreach ($newini as $line) {
  7638. fwrite($fp, $line);
  7639. }
  7640. fclose($fp);
  7641. return true;
  7642. }
  7643. function _parseIni($filename)
  7644. {
  7645. if (!file_exists($filename)) {
  7646. return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
  7647. }
  7648. if (filesize($filename) > 300000) {
  7649. return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
  7650. }
  7651. ob_start();
  7652. phpinfo(INFO_GENERAL);
  7653. $info = ob_get_contents();
  7654. ob_end_clean();
  7655. $debug = function_exists('leak') ? '_debug' : '';
  7656. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  7657. $zend_extension_line = 'zend_extension' . $debug . $ts;
  7658. $all = @file($filename);
  7659. if ($all === false) {
  7660. return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
  7661. }
  7662. $zend_extensions = $extensions = array();
  7663. // assume this is right, but pull from the php.ini if it is found
  7664. $extension_dir = ini_get('extension_dir');
  7665. foreach ($all as $linenum => $line) {
  7666. $line = trim($line);
  7667. if (!$line) {
  7668. continue;
  7669. }
  7670. if ($line[0] == ';') {
  7671. continue;
  7672. }
  7673. if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
  7674. $line = trim(substr($line, 13));
  7675. if ($line[0] == '=') {
  7676. $x = trim(substr($line, 1));
  7677. $x = explode(';', $x);
  7678. $extension_dir = str_replace('"', '', array_shift($x));
  7679. continue;
  7680. }
  7681. }
  7682. if (strtolower(substr($line, 0, 9)) == 'extension') {
  7683. $line = trim(substr($line, 9));
  7684. if ($line[0] == '=') {
  7685. $x = trim(substr($line, 1));
  7686. $x = explode(';', $x);
  7687. $extensions[$linenum] = str_replace('"', '', array_shift($x));
  7688. continue;
  7689. }
  7690. }
  7691. if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
  7692. $zend_extension_line) {
  7693. $line = trim(substr($line, strlen($zend_extension_line)));
  7694. if ($line[0] == '=') {
  7695. $x = trim(substr($line, 1));
  7696. $x = explode(';', $x);
  7697. $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
  7698. continue;
  7699. }
  7700. }
  7701. }
  7702. return array(
  7703. 'extensions' => $extensions,
  7704. 'zend_extensions' => $zend_extensions,
  7705. 'extension_dir' => $extension_dir,
  7706. 'all' => $all,
  7707. );
  7708. }
  7709. // {{{ doInstall()
  7710. function doInstall($command, $options, $params)
  7711. {
  7712. if (!class_exists('PEAR_PackageFile')) {
  7713. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php';
  7714. }
  7715. if (isset($options['installroot']) && isset($options['packagingroot'])) {
  7716. return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
  7717. }
  7718. $reg = &$this->config->getRegistry();
  7719. $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
  7720. if (!$reg->channelExists($channel)) {
  7721. return $this->raiseError('Channel "' . $channel . '" does not exist');
  7722. }
  7723. if (empty($this->installer)) {
  7724. $this->installer = &$this->getInstaller($this->ui);
  7725. }
  7726. if ($command == 'upgrade' || $command == 'upgrade-all') {
  7727. // If people run the upgrade command but pass nothing, emulate a upgrade-all
  7728. if ($command == 'upgrade' && empty($params)) {
  7729. return $this->doUpgradeAll($command, $options, $params);
  7730. }
  7731. $options['upgrade'] = true;
  7732. } else {
  7733. $packages = $params;
  7734. }
  7735. $instreg = &$reg; // instreg used to check if package is installed
  7736. if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
  7737. $packrootphp_dir = $this->installer->_prependPath(
  7738. $this->config->get('php_dir', null, 'pear.php.net'),
  7739. $options['packagingroot']);
  7740. $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
  7741. if ($metadata_dir) {
  7742. $metadata_dir = $this->installer->_prependPath(
  7743. $metadata_dir,
  7744. $options['packagingroot']);
  7745. }
  7746. $instreg = new PEAR_Registry($packrootphp_dir, false, false, $metadata_dir); // other instreg!
  7747. if ($this->config->get('verbose') > 2) {
  7748. $this->ui->outputData('using package root: ' . $options['packagingroot']);
  7749. }
  7750. }
  7751. $abstractpackages = $otherpackages = array();
  7752. // parse params
  7753. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7754. foreach ($params as $param) {
  7755. if (strpos($param, 'http://') === 0) {
  7756. $otherpackages[] = $param;
  7757. continue;
  7758. }
  7759. if (strpos($param, 'channel://') === false && @file_exists($param)) {
  7760. if (isset($options['force'])) {
  7761. $otherpackages[] = $param;
  7762. continue;
  7763. }
  7764. $pkg = new PEAR_PackageFile($this->config);
  7765. $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
  7766. if (PEAR::isError($pf)) {
  7767. $otherpackages[] = $param;
  7768. continue;
  7769. }
  7770. $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel());
  7771. $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel());
  7772. $version_compare = version_compare($pf->getVersion(), $pversion, '<=');
  7773. if ($exists && $version_compare) {
  7774. if ($this->config->get('verbose')) {
  7775. $this->ui->outputData('Ignoring installed package ' .
  7776. $reg->parsedPackageNameToString(
  7777. array('package' => $pf->getPackage(),
  7778. 'channel' => $pf->getChannel()), true));
  7779. }
  7780. continue;
  7781. }
  7782. $otherpackages[] = $param;
  7783. continue;
  7784. }
  7785. $e = $reg->parsePackageName($param, $channel);
  7786. if (PEAR::isError($e)) {
  7787. $otherpackages[] = $param;
  7788. } else {
  7789. $abstractpackages[] = $e;
  7790. }
  7791. }
  7792. PEAR::staticPopErrorHandling();
  7793. // if there are any local package .tgz or remote static url, we can't
  7794. // filter. The filter only works for abstract packages
  7795. if (count($abstractpackages) && !isset($options['force'])) {
  7796. // when not being forced, only do necessary upgrades/installs
  7797. if (isset($options['upgrade'])) {
  7798. $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command);
  7799. } else {
  7800. $count = count($abstractpackages);
  7801. foreach ($abstractpackages as $i => $package) {
  7802. if (isset($package['group'])) {
  7803. // do not filter out install groups
  7804. continue;
  7805. }
  7806. if ($instreg->packageExists($package['package'], $package['channel'])) {
  7807. if ($count > 1) {
  7808. if ($this->config->get('verbose')) {
  7809. $this->ui->outputData('Ignoring installed package ' .
  7810. $reg->parsedPackageNameToString($package, true));
  7811. }
  7812. unset($abstractpackages[$i]);
  7813. } elseif ($count === 1) {
  7814. // Lets try to upgrade it since it's already installed
  7815. $options['upgrade'] = true;
  7816. }
  7817. }
  7818. }
  7819. }
  7820. $abstractpackages =
  7821. array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  7822. } elseif (count($abstractpackages)) {
  7823. $abstractpackages =
  7824. array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  7825. }
  7826. $packages = array_merge($abstractpackages, $otherpackages);
  7827. if (!count($packages)) {
  7828. $c = '';
  7829. if (isset($options['channel'])){
  7830. $c .= ' in channel "' . $options['channel'] . '"';
  7831. }
  7832. $this->ui->outputData('Nothing to ' . $command . $c);
  7833. return true;
  7834. }
  7835. $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
  7836. $errors = $downloaded = $binaries = array();
  7837. $downloaded = &$this->downloader->download($packages);
  7838. if (PEAR::isError($downloaded)) {
  7839. return $this->raiseError($downloaded);
  7840. }
  7841. $errors = $this->downloader->getErrorMsgs();
  7842. if (count($errors)) {
  7843. $err = array();
  7844. $err['data'] = array();
  7845. foreach ($errors as $error) {
  7846. if ($error !== null) {
  7847. $err['data'][] = array($error);
  7848. }
  7849. }
  7850. if (!empty($err['data'])) {
  7851. $err['headline'] = 'Install Errors';
  7852. $this->ui->outputData($err);
  7853. }
  7854. if (!count($downloaded)) {
  7855. return $this->raiseError("$command failed");
  7856. }
  7857. }
  7858. $data = array(
  7859. 'headline' => 'Packages that would be Installed'
  7860. );
  7861. if (isset($options['pretend'])) {
  7862. foreach ($downloaded as $package) {
  7863. $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
  7864. }
  7865. $this->ui->outputData($data, 'pretend');
  7866. return true;
  7867. }
  7868. $this->installer->setOptions($options);
  7869. $this->installer->sortPackagesForInstall($downloaded);
  7870. if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
  7871. $this->raiseError($err->getMessage());
  7872. return true;
  7873. }
  7874. $binaries = $extrainfo = array();
  7875. foreach ($downloaded as $param) {
  7876. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7877. $info = $this->installer->install($param, $options);
  7878. PEAR::staticPopErrorHandling();
  7879. if (PEAR::isError($info)) {
  7880. $oldinfo = $info;
  7881. $pkg = &$param->getPackageFile();
  7882. if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
  7883. if (!($info = $pkg->installBinary($this->installer))) {
  7884. return $this->raiseError('ERROR: ' .$oldinfo->getMessage());
  7885. }
  7886. // we just installed a different package than requested,
  7887. // let's change the param and info so that the rest of this works
  7888. $param = $info[0];
  7889. $info = $info[1];
  7890. }
  7891. }
  7892. if (!is_array($info)) {
  7893. return $this->raiseError("$command failed");
  7894. }
  7895. if ($param->getPackageType() == 'extsrc' ||
  7896. $param->getPackageType() == 'extbin' ||
  7897. $param->getPackageType() == 'zendextsrc' ||
  7898. $param->getPackageType() == 'zendextbin'
  7899. ) {
  7900. $pkg = &$param->getPackageFile();
  7901. if ($instbin = $pkg->getInstalledBinary()) {
  7902. $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
  7903. } else {
  7904. $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
  7905. }
  7906. foreach ($instpkg->getFilelist() as $name => $atts) {
  7907. $pinfo = pathinfo($atts['installed_as']);
  7908. if (!isset($pinfo['extension']) ||
  7909. in_array($pinfo['extension'], array('c', 'h'))
  7910. ) {
  7911. continue; // make sure we don't match php_blah.h
  7912. }
  7913. if ((strpos($pinfo['basename'], 'php_') === 0 &&
  7914. $pinfo['extension'] == 'dll') ||
  7915. // most unices
  7916. $pinfo['extension'] == 'so' ||
  7917. // hp-ux
  7918. $pinfo['extension'] == 'sl') {
  7919. $binaries[] = array($atts['installed_as'], $pinfo);
  7920. break;
  7921. }
  7922. }
  7923. if (count($binaries)) {
  7924. foreach ($binaries as $pinfo) {
  7925. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7926. $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
  7927. PEAR::staticPopErrorHandling();
  7928. if (PEAR::isError($ret)) {
  7929. $extrainfo[] = $ret->getMessage();
  7930. if ($param->getPackageType() == 'extsrc' ||
  7931. $param->getPackageType() == 'extbin') {
  7932. $exttype = 'extension';
  7933. $extpath = $pinfo[1]['basename'];
  7934. } else {
  7935. $exttype = 'zend_extension';
  7936. $extpath = $atts['installed_as'];
  7937. }
  7938. $extrainfo[] = 'You should add "' . $exttype . '=' .
  7939. $extpath . '" to php.ini';
  7940. } else {
  7941. $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
  7942. ' enabled in php.ini';
  7943. }
  7944. }
  7945. }
  7946. }
  7947. if ($this->config->get('verbose') > 0) {
  7948. $chan = $param->getChannel();
  7949. $label = $reg->parsedPackageNameToString(
  7950. array(
  7951. 'channel' => $chan,
  7952. 'package' => $param->getPackage(),
  7953. 'version' => $param->getVersion(),
  7954. ));
  7955. $out = array('data' => "$command ok: $label");
  7956. if (isset($info['release_warnings'])) {
  7957. $out['release_warnings'] = $info['release_warnings'];
  7958. }
  7959. $this->ui->outputData($out, $command);
  7960. if (!isset($options['register-only']) && !isset($options['offline'])) {
  7961. if ($this->config->isDefinedLayer('ftp')) {
  7962. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7963. $info = $this->installer->ftpInstall($param);
  7964. PEAR::staticPopErrorHandling();
  7965. if (PEAR::isError($info)) {
  7966. $this->ui->outputData($info->getMessage());
  7967. $this->ui->outputData("remote install failed: $label");
  7968. } else {
  7969. $this->ui->outputData("remote install ok: $label");
  7970. }
  7971. }
  7972. }
  7973. }
  7974. $deps = $param->getDeps();
  7975. if ($deps) {
  7976. if (isset($deps['group'])) {
  7977. $groups = $deps['group'];
  7978. if (!isset($groups[0])) {
  7979. $groups = array($groups);
  7980. }
  7981. foreach ($groups as $group) {
  7982. if ($group['attribs']['name'] == 'default') {
  7983. // default group is always installed, unless the user
  7984. // explicitly chooses to install another group
  7985. continue;
  7986. }
  7987. $extrainfo[] = $param->getPackage() . ': Optional feature ' .
  7988. $group['attribs']['name'] . ' available (' .
  7989. $group['attribs']['hint'] . ')';
  7990. }
  7991. $extrainfo[] = $param->getPackage() .
  7992. ': To install optional features use "pear install ' .
  7993. $reg->parsedPackageNameToString(
  7994. array('package' => $param->getPackage(),
  7995. 'channel' => $param->getChannel()), true) .
  7996. '#featurename"';
  7997. }
  7998. }
  7999. $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
  8000. // $pkg may be NULL if install is a 'fake' install via --packagingroot
  8001. if (is_object($pkg)) {
  8002. $pkg->setConfig($this->config);
  8003. if ($list = $pkg->listPostinstallScripts()) {
  8004. $pn = $reg->parsedPackageNameToString(array('channel' =>
  8005. $param->getChannel(), 'package' => $param->getPackage()), true);
  8006. $extrainfo[] = $pn . ' has post-install scripts:';
  8007. foreach ($list as $file) {
  8008. $extrainfo[] = $file;
  8009. }
  8010. $extrainfo[] = $param->getPackage() .
  8011. ': Use "pear run-scripts ' . $pn . '" to finish setup.';
  8012. $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
  8013. }
  8014. }
  8015. }
  8016. if (count($extrainfo)) {
  8017. foreach ($extrainfo as $info) {
  8018. $this->ui->outputData($info);
  8019. }
  8020. }
  8021. return true;
  8022. }
  8023. // }}}
  8024. // {{{ doUpgradeAll()
  8025. function doUpgradeAll($command, $options, $params)
  8026. {
  8027. $reg = &$this->config->getRegistry();
  8028. $upgrade = array();
  8029. if (isset($options['channel'])) {
  8030. $channels = array($options['channel']);
  8031. } else {
  8032. $channels = $reg->listChannels();
  8033. }
  8034. foreach ($channels as $channel) {
  8035. if ($channel == '__uri') {
  8036. continue;
  8037. }
  8038. // parse name with channel
  8039. foreach ($reg->listPackages($channel) as $name) {
  8040. $upgrade[] = $reg->parsedPackageNameToString(array(
  8041. 'channel' => $channel,
  8042. 'package' => $name
  8043. ));
  8044. }
  8045. }
  8046. $err = $this->doInstall($command, $options, $upgrade);
  8047. if (PEAR::isError($err)) {
  8048. $this->ui->outputData($err->getMessage(), $command);
  8049. }
  8050. }
  8051. // }}}
  8052. // {{{ doUninstall()
  8053. function doUninstall($command, $options, $params)
  8054. {
  8055. if (count($params) < 1) {
  8056. return $this->raiseError("Please supply the package(s) you want to uninstall");
  8057. }
  8058. if (empty($this->installer)) {
  8059. $this->installer = &$this->getInstaller($this->ui);
  8060. }
  8061. if (isset($options['remoteconfig'])) {
  8062. $e = $this->config->readFTPConfigFile($options['remoteconfig']);
  8063. if (!PEAR::isError($e)) {
  8064. $this->installer->setConfig($this->config);
  8065. }
  8066. }
  8067. $reg = &$this->config->getRegistry();
  8068. $newparams = array();
  8069. $binaries = array();
  8070. $badparams = array();
  8071. foreach ($params as $pkg) {
  8072. $channel = $this->config->get('default_channel');
  8073. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8074. $parsed = $reg->parsePackageName($pkg, $channel);
  8075. PEAR::staticPopErrorHandling();
  8076. if (!$parsed || PEAR::isError($parsed)) {
  8077. $badparams[] = $pkg;
  8078. continue;
  8079. }
  8080. $package = $parsed['package'];
  8081. $channel = $parsed['channel'];
  8082. $info = &$reg->getPackage($package, $channel);
  8083. if ($info === null &&
  8084. ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
  8085. // make sure this isn't a package that has flipped from pear to pecl but
  8086. // used a package.xml 1.0
  8087. $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
  8088. $info = &$reg->getPackage($package, $testc);
  8089. if ($info !== null) {
  8090. $channel = $testc;
  8091. }
  8092. }
  8093. if ($info === null) {
  8094. $badparams[] = $pkg;
  8095. } else {
  8096. $newparams[] = &$info;
  8097. // check for binary packages (this is an alias for those packages if so)
  8098. if ($installedbinary = $info->getInstalledBinary()) {
  8099. $this->ui->log('adding binary package ' .
  8100. $reg->parsedPackageNameToString(array('channel' => $channel,
  8101. 'package' => $installedbinary), true));
  8102. $newparams[] = &$reg->getPackage($installedbinary, $channel);
  8103. }
  8104. // add the contents of a dependency group to the list of installed packages
  8105. if (isset($parsed['group'])) {
  8106. $group = $info->getDependencyGroup($parsed['group']);
  8107. if ($group) {
  8108. $installed = $reg->getInstalledGroup($group);
  8109. if ($installed) {
  8110. foreach ($installed as $i => $p) {
  8111. $newparams[] = &$installed[$i];
  8112. }
  8113. }
  8114. }
  8115. }
  8116. }
  8117. }
  8118. $err = $this->installer->sortPackagesForUninstall($newparams);
  8119. if (PEAR::isError($err)) {
  8120. $this->ui->outputData($err->getMessage(), $command);
  8121. return true;
  8122. }
  8123. $params = $newparams;
  8124. // twist this to use it to check on whether dependent packages are also being uninstalled
  8125. // for circular dependencies like subpackages
  8126. $this->installer->setUninstallPackages($newparams);
  8127. $params = array_merge($params, $badparams);
  8128. $binaries = array();
  8129. foreach ($params as $pkg) {
  8130. $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  8131. if ($err = $this->installer->uninstall($pkg, $options)) {
  8132. $this->installer->popErrorHandling();
  8133. if (PEAR::isError($err)) {
  8134. $this->ui->outputData($err->getMessage(), $command);
  8135. continue;
  8136. }
  8137. if ($pkg->getPackageType() == 'extsrc' ||
  8138. $pkg->getPackageType() == 'extbin' ||
  8139. $pkg->getPackageType() == 'zendextsrc' ||
  8140. $pkg->getPackageType() == 'zendextbin') {
  8141. if ($instbin = $pkg->getInstalledBinary()) {
  8142. continue; // this will be uninstalled later
  8143. }
  8144. foreach ($pkg->getFilelist() as $name => $atts) {
  8145. $pinfo = pathinfo($atts['installed_as']);
  8146. if (!isset($pinfo['extension']) ||
  8147. in_array($pinfo['extension'], array('c', 'h'))) {
  8148. continue; // make sure we don't match php_blah.h
  8149. }
  8150. if ((strpos($pinfo['basename'], 'php_') === 0 &&
  8151. $pinfo['extension'] == 'dll') ||
  8152. // most unices
  8153. $pinfo['extension'] == 'so' ||
  8154. // hp-ux
  8155. $pinfo['extension'] == 'sl') {
  8156. $binaries[] = array($atts['installed_as'], $pinfo);
  8157. break;
  8158. }
  8159. }
  8160. if (count($binaries)) {
  8161. foreach ($binaries as $pinfo) {
  8162. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8163. $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
  8164. PEAR::staticPopErrorHandling();
  8165. if (PEAR::isError($ret)) {
  8166. $extrainfo[] = $ret->getMessage();
  8167. if ($pkg->getPackageType() == 'extsrc' ||
  8168. $pkg->getPackageType() == 'extbin') {
  8169. $exttype = 'extension';
  8170. } else {
  8171. ob_start();
  8172. phpinfo(INFO_GENERAL);
  8173. $info = ob_get_contents();
  8174. ob_end_clean();
  8175. $debug = function_exists('leak') ? '_debug' : '';
  8176. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  8177. $exttype = 'zend_extension' . $debug . $ts;
  8178. }
  8179. $this->ui->outputData('Unable to remove "' . $exttype . '=' .
  8180. $pinfo[1]['basename'] . '" from php.ini', $command);
  8181. } else {
  8182. $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
  8183. ' disabled in php.ini', $command);
  8184. }
  8185. }
  8186. }
  8187. }
  8188. $savepkg = $pkg;
  8189. if ($this->config->get('verbose') > 0) {
  8190. if (is_object($pkg)) {
  8191. $pkg = $reg->parsedPackageNameToString($pkg);
  8192. }
  8193. $this->ui->outputData("uninstall ok: $pkg", $command);
  8194. }
  8195. if (!isset($options['offline']) && is_object($savepkg) &&
  8196. defined('PEAR_REMOTEINSTALL_OK')) {
  8197. if ($this->config->isDefinedLayer('ftp')) {
  8198. $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  8199. $info = $this->installer->ftpUninstall($savepkg);
  8200. $this->installer->popErrorHandling();
  8201. if (PEAR::isError($info)) {
  8202. $this->ui->outputData($info->getMessage());
  8203. $this->ui->outputData("remote uninstall failed: $pkg");
  8204. } else {
  8205. $this->ui->outputData("remote uninstall ok: $pkg");
  8206. }
  8207. }
  8208. }
  8209. } else {
  8210. $this->installer->popErrorHandling();
  8211. if (!is_object($pkg)) {
  8212. return $this->raiseError("uninstall failed: $pkg");
  8213. }
  8214. $pkg = $reg->parsedPackageNameToString($pkg);
  8215. }
  8216. }
  8217. return true;
  8218. }
  8219. // }}}
  8220. // }}}
  8221. // {{{ doBundle()
  8222. /*
  8223. (cox) It just downloads and untars the package, does not do
  8224. any check that the PEAR_Installer::_installFile() does.
  8225. */
  8226. function doBundle($command, $options, $params)
  8227. {
  8228. $opts = array(
  8229. 'force' => true,
  8230. 'nodeps' => true,
  8231. 'soft' => true,
  8232. 'downloadonly' => true
  8233. );
  8234. $downloader = &$this->getDownloader($this->ui, $opts, $this->config);
  8235. $reg = &$this->config->getRegistry();
  8236. if (count($params) < 1) {
  8237. return $this->raiseError("Please supply the package you want to bundle");
  8238. }
  8239. if (isset($options['destination'])) {
  8240. if (!is_dir($options['destination'])) {
  8241. System::mkdir('-p ' . $options['destination']);
  8242. }
  8243. $dest = realpath($options['destination']);
  8244. } else {
  8245. $pwd = getcwd();
  8246. $dir = $pwd . DIRECTORY_SEPARATOR . 'ext';
  8247. $dest = is_dir($dir) ? $dir : $pwd;
  8248. }
  8249. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8250. $err = $downloader->setDownloadDir($dest);
  8251. PEAR::staticPopErrorHandling();
  8252. if (PEAR::isError($err)) {
  8253. return PEAR::raiseError('download directory "' . $dest .
  8254. '" is not writeable.');
  8255. }
  8256. $result = &$downloader->download(array($params[0]));
  8257. if (PEAR::isError($result)) {
  8258. return $result;
  8259. }
  8260. if (!isset($result[0])) {
  8261. return $this->raiseError('unable to unpack ' . $params[0]);
  8262. }
  8263. $pkgfile = &$result[0]->getPackageFile();
  8264. $pkgname = $pkgfile->getName();
  8265. $pkgversion = $pkgfile->getVersion();
  8266. // Unpacking -------------------------------------------------
  8267. $dest .= DIRECTORY_SEPARATOR . $pkgname;
  8268. $orig = $pkgname . '-' . $pkgversion;
  8269. $tar = new Archive_Tar($pkgfile->getArchiveFile());
  8270. if (!$tar->extractModify($dest, $orig)) {
  8271. return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
  8272. }
  8273. $this->ui->outputData("Package ready at '$dest'");
  8274. // }}}
  8275. }
  8276. // }}}
  8277. function doRunScripts($command, $options, $params)
  8278. {
  8279. if (!isset($params[0])) {
  8280. return $this->raiseError('run-scripts expects 1 parameter: a package name');
  8281. }
  8282. $reg = &$this->config->getRegistry();
  8283. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8284. $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  8285. PEAR::staticPopErrorHandling();
  8286. if (PEAR::isError($parsed)) {
  8287. return $this->raiseError($parsed);
  8288. }
  8289. $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
  8290. if (!is_object($package)) {
  8291. return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
  8292. }
  8293. $package->setConfig($this->config);
  8294. $package->runPostinstallScripts();
  8295. $this->ui->outputData('Install scripts complete', $command);
  8296. return true;
  8297. }
  8298. /**
  8299. * Given a list of packages, filter out those ones that are already up to date
  8300. *
  8301. * @param $packages: packages, in parsed array format !
  8302. * @return list of packages that can be upgraded
  8303. */
  8304. function _filterUptodatePackages($packages, $command)
  8305. {
  8306. $reg = &$this->config->getRegistry();
  8307. $latestReleases = array();
  8308. $ret = array();
  8309. foreach ($packages as $package) {
  8310. if (isset($package['group'])) {
  8311. $ret[] = $package;
  8312. continue;
  8313. }
  8314. $channel = $package['channel'];
  8315. $name = $package['package'];
  8316. if (!$reg->packageExists($name, $channel)) {
  8317. $ret[] = $package;
  8318. continue;
  8319. }
  8320. if (!isset($latestReleases[$channel])) {
  8321. // fill in cache for this channel
  8322. $chan = $reg->getChannel($channel);
  8323. if (PEAR::isError($chan)) {
  8324. return $this->raiseError($chan);
  8325. }
  8326. $base2 = false;
  8327. $preferred_mirror = $this->config->get('preferred_mirror', null, $channel);
  8328. if ($chan->supportsREST($preferred_mirror) &&
  8329. (
  8330. //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) ||
  8331. ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
  8332. )
  8333. ) {
  8334. $dorest = true;
  8335. }
  8336. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8337. if (!isset($package['state'])) {
  8338. $state = $this->config->get('preferred_state', null, $channel);
  8339. } else {
  8340. $state = $package['state'];
  8341. }
  8342. if ($dorest) {
  8343. if ($base2) {
  8344. $rest = &$this->config->getREST('1.4', array());
  8345. $base = $base2;
  8346. } else {
  8347. $rest = &$this->config->getREST('1.0', array());
  8348. }
  8349. $installed = array_flip($reg->listPackages($channel));
  8350. $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
  8351. }
  8352. PEAR::staticPopErrorHandling();
  8353. if (PEAR::isError($latest)) {
  8354. $this->ui->outputData('Error getting channel info from ' . $channel .
  8355. ': ' . $latest->getMessage());
  8356. continue;
  8357. }
  8358. $latestReleases[$channel] = array_change_key_case($latest);
  8359. }
  8360. // check package for latest release
  8361. $name_lower = strtolower($name);
  8362. if (isset($latestReleases[$channel][$name_lower])) {
  8363. // if not set, up to date
  8364. $inst_version = $reg->packageInfo($name, 'version', $channel);
  8365. $channel_version = $latestReleases[$channel][$name_lower]['version'];
  8366. if (version_compare($channel_version, $inst_version, 'le')) {
  8367. // installed version is up-to-date
  8368. continue;
  8369. }
  8370. // maintain BC
  8371. if ($command == 'upgrade-all') {
  8372. $this->ui->outputData(array('data' => 'Will upgrade ' .
  8373. $reg->parsedPackageNameToString($package)), $command);
  8374. }
  8375. $ret[] = $package;
  8376. }
  8377. }
  8378. return $ret;
  8379. }
  8380. }
  8381. <commands version="1.0">
  8382. <install>
  8383. <summary>Install Package</summary>
  8384. <function>doInstall</function>
  8385. <shortcut>i</shortcut>
  8386. <options>
  8387. <force>
  8388. <shortopt>f</shortopt>
  8389. <doc>will overwrite newer installed packages</doc>
  8390. </force>
  8391. <loose>
  8392. <shortopt>l</shortopt>
  8393. <doc>do not check for recommended dependency version</doc>
  8394. </loose>
  8395. <nodeps>
  8396. <shortopt>n</shortopt>
  8397. <doc>ignore dependencies, install anyway</doc>
  8398. </nodeps>
  8399. <register-only>
  8400. <shortopt>r</shortopt>
  8401. <doc>do not install files, only register the package as installed</doc>
  8402. </register-only>
  8403. <soft>
  8404. <shortopt>s</shortopt>
  8405. <doc>soft install, fail silently, or upgrade if already installed</doc>
  8406. </soft>
  8407. <nobuild>
  8408. <shortopt>B</shortopt>
  8409. <doc>don&#039;t build C extensions</doc>
  8410. </nobuild>
  8411. <configureoptions>
  8412. <shortopt>D</shortopt>
  8413. <arg>OPTION1=VALUE[ OPTION2=VALUE]</arg>
  8414. </configureoptions>
  8415. <nocompress>
  8416. <shortopt>Z</shortopt>
  8417. <doc>request uncompressed files when downloading</doc>
  8418. </nocompress>
  8419. <installroot>
  8420. <shortopt>R</shortopt>
  8421. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT), use packagingroot for RPM</doc>
  8422. <arg>DIR</arg>
  8423. </installroot>
  8424. <packagingroot>
  8425. <shortopt>P</shortopt>
  8426. <doc>root directory used when packaging files, like RPM packaging</doc>
  8427. <arg>DIR</arg>
  8428. </packagingroot>
  8429. <ignore-errors>
  8430. <shortopt></shortopt>
  8431. <doc>force install even if there were errors</doc>
  8432. </ignore-errors>
  8433. <alldeps>
  8434. <shortopt>a</shortopt>
  8435. <doc>install all required and optional dependencies</doc>
  8436. </alldeps>
  8437. <onlyreqdeps>
  8438. <shortopt>o</shortopt>
  8439. <doc>install all required dependencies</doc>
  8440. </onlyreqdeps>
  8441. <offline>
  8442. <shortopt>O</shortopt>
  8443. <doc>do not attempt to download any urls or contact channels</doc>
  8444. </offline>
  8445. <pretend>
  8446. <shortopt>p</shortopt>
  8447. <doc>Only list the packages that would be downloaded</doc>
  8448. </pretend>
  8449. </options>
  8450. <doc>[channel/]&lt;package&gt; ...
  8451. Installs one or more PEAR packages. You can specify a package to
  8452. install in four ways:
  8453. &quot;Package-1.0.tgz&quot; : installs from a local file
  8454. &quot;http://example.com/Package-1.0.tgz&quot; : installs from
  8455. anywhere on the net.
  8456. &quot;package.xml&quot; : installs the package described in
  8457. package.xml. Useful for testing, or for wrapping a PEAR package in
  8458. another package manager such as RPM.
  8459. &quot;Package[-version/state][.tar]&quot; : queries your default channel&#039;s server
  8460. ({config master_server}) and downloads the newest package with
  8461. the preferred quality/state ({config preferred_state}).
  8462. To retrieve Package version 1.1, use &quot;Package-1.1,&quot; to retrieve
  8463. Package state beta, use &quot;Package-beta.&quot; To retrieve an uncompressed
  8464. file, append .tar (make sure there is no file by the same name first)
  8465. To download a package from another channel, prefix with the channel name like
  8466. &quot;channel/Package&quot;
  8467. More than one package may be specified at once. It is ok to mix these
  8468. four ways of specifying packages.
  8469. </doc>
  8470. </install>
  8471. <upgrade>
  8472. <summary>Upgrade Package</summary>
  8473. <function>doInstall</function>
  8474. <shortcut>up</shortcut>
  8475. <options>
  8476. <channel>
  8477. <shortopt>c</shortopt>
  8478. <doc>upgrade packages from a specific channel</doc>
  8479. <arg>CHAN</arg>
  8480. </channel>
  8481. <force>
  8482. <shortopt>f</shortopt>
  8483. <doc>overwrite newer installed packages</doc>
  8484. </force>
  8485. <loose>
  8486. <shortopt>l</shortopt>
  8487. <doc>do not check for recommended dependency version</doc>
  8488. </loose>
  8489. <nodeps>
  8490. <shortopt>n</shortopt>
  8491. <doc>ignore dependencies, upgrade anyway</doc>
  8492. </nodeps>
  8493. <register-only>
  8494. <shortopt>r</shortopt>
  8495. <doc>do not install files, only register the package as upgraded</doc>
  8496. </register-only>
  8497. <nobuild>
  8498. <shortopt>B</shortopt>
  8499. <doc>don&#039;t build C extensions</doc>
  8500. </nobuild>
  8501. <nocompress>
  8502. <shortopt>Z</shortopt>
  8503. <doc>request uncompressed files when downloading</doc>
  8504. </nocompress>
  8505. <installroot>
  8506. <shortopt>R</shortopt>
  8507. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT)</doc>
  8508. <arg>DIR</arg>
  8509. </installroot>
  8510. <ignore-errors>
  8511. <shortopt></shortopt>
  8512. <doc>force install even if there were errors</doc>
  8513. </ignore-errors>
  8514. <alldeps>
  8515. <shortopt>a</shortopt>
  8516. <doc>install all required and optional dependencies</doc>
  8517. </alldeps>
  8518. <onlyreqdeps>
  8519. <shortopt>o</shortopt>
  8520. <doc>install all required dependencies</doc>
  8521. </onlyreqdeps>
  8522. <offline>
  8523. <shortopt>O</shortopt>
  8524. <doc>do not attempt to download any urls or contact channels</doc>
  8525. </offline>
  8526. <pretend>
  8527. <shortopt>p</shortopt>
  8528. <doc>Only list the packages that would be downloaded</doc>
  8529. </pretend>
  8530. </options>
  8531. <doc>&lt;package&gt; ...
  8532. Upgrades one or more PEAR packages. See documentation for the
  8533. &quot;install&quot; command for ways to specify a package.
  8534. When upgrading, your package will be updated if the provided new
  8535. package has a higher version number (use the -f option if you need to
  8536. upgrade anyway).
  8537. More than one package may be specified at once.
  8538. </doc>
  8539. </upgrade>
  8540. <upgrade-all>
  8541. <summary>Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]</summary>
  8542. <function>doUpgradeAll</function>
  8543. <shortcut>ua</shortcut>
  8544. <options>
  8545. <channel>
  8546. <shortopt>c</shortopt>
  8547. <doc>upgrade packages from a specific channel</doc>
  8548. <arg>CHAN</arg>
  8549. </channel>
  8550. <nodeps>
  8551. <shortopt>n</shortopt>
  8552. <doc>ignore dependencies, upgrade anyway</doc>
  8553. </nodeps>
  8554. <register-only>
  8555. <shortopt>r</shortopt>
  8556. <doc>do not install files, only register the package as upgraded</doc>
  8557. </register-only>
  8558. <nobuild>
  8559. <shortopt>B</shortopt>
  8560. <doc>don&#039;t build C extensions</doc>
  8561. </nobuild>
  8562. <nocompress>
  8563. <shortopt>Z</shortopt>
  8564. <doc>request uncompressed files when downloading</doc>
  8565. </nocompress>
  8566. <installroot>
  8567. <shortopt>R</shortopt>
  8568. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT), use packagingroot for RPM</doc>
  8569. <arg>DIR</arg>
  8570. </installroot>
  8571. <ignore-errors>
  8572. <shortopt></shortopt>
  8573. <doc>force install even if there were errors</doc>
  8574. </ignore-errors>
  8575. <loose>
  8576. <shortopt></shortopt>
  8577. <doc>do not check for recommended dependency version</doc>
  8578. </loose>
  8579. </options>
  8580. <doc>
  8581. WARNING: This function is deprecated in favor of using the upgrade command with no params
  8582. Upgrades all packages that have a newer release available. Upgrades are
  8583. done only if there is a release available of the state specified in
  8584. &quot;preferred_state&quot; (currently {config preferred_state}), or a state considered
  8585. more stable.
  8586. </doc>
  8587. </upgrade-all>
  8588. <uninstall>
  8589. <summary>Un-install Package</summary>
  8590. <function>doUninstall</function>
  8591. <shortcut>un</shortcut>
  8592. <options>
  8593. <nodeps>
  8594. <shortopt>n</shortopt>
  8595. <doc>ignore dependencies, uninstall anyway</doc>
  8596. </nodeps>
  8597. <register-only>
  8598. <shortopt>r</shortopt>
  8599. <doc>do not remove files, only register the packages as not installed</doc>
  8600. </register-only>
  8601. <installroot>
  8602. <shortopt>R</shortopt>
  8603. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT)</doc>
  8604. <arg>DIR</arg>
  8605. </installroot>
  8606. <ignore-errors>
  8607. <shortopt></shortopt>
  8608. <doc>force install even if there were errors</doc>
  8609. </ignore-errors>
  8610. <offline>
  8611. <shortopt>O</shortopt>
  8612. <doc>do not attempt to uninstall remotely</doc>
  8613. </offline>
  8614. </options>
  8615. <doc>[channel/]&lt;package&gt; ...
  8616. Uninstalls one or more PEAR packages. More than one package may be
  8617. specified at once. Prefix with channel name to uninstall from a
  8618. channel not in your default channel ({config default_channel})
  8619. </doc>
  8620. </uninstall>
  8621. <bundle>
  8622. <summary>Unpacks a Pecl Package</summary>
  8623. <function>doBundle</function>
  8624. <shortcut>bun</shortcut>
  8625. <options>
  8626. <destination>
  8627. <shortopt>d</shortopt>
  8628. <doc>Optional destination directory for unpacking (defaults to current path or &quot;ext&quot; if exists)</doc>
  8629. <arg>DIR</arg>
  8630. </destination>
  8631. <force>
  8632. <shortopt>f</shortopt>
  8633. <doc>Force the unpacking even if there were errors in the package</doc>
  8634. </force>
  8635. </options>
  8636. <doc>&lt;package&gt;
  8637. Unpacks a Pecl Package into the selected location. It will download the
  8638. package if needed.
  8639. </doc>
  8640. </bundle>
  8641. <run-scripts>
  8642. <summary>Run Post-Install Scripts bundled with a package</summary>
  8643. <function>doRunScripts</function>
  8644. <shortcut>rs</shortcut>
  8645. <options />
  8646. <doc>&lt;package&gt;
  8647. Run post-installation scripts in package &lt;package&gt;, if any exist.
  8648. </doc>
  8649. </run-scripts>
  8650. </commands><?php
  8651. /**
  8652. * PEAR_Common, the base class for the PEAR Installer
  8653. *
  8654. * PHP versions 4 and 5
  8655. *
  8656. * @category pear
  8657. * @package PEAR
  8658. * @author Stig Bakken <ssb@php.net>
  8659. * @author Tomas V. V. Cox <cox@idecnet.com>
  8660. * @author Greg Beaver <cellog@php.net>
  8661. * @copyright 1997-2009 The Authors
  8662. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  8663. * @link http://pear.php.net/package/PEAR
  8664. * @since File available since Release 0.1.0
  8665. * @deprecated File deprecated since Release 1.4.0a1
  8666. */
  8667. /**
  8668. * Include error handling
  8669. */
  8670. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  8671. /**
  8672. * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
  8673. */
  8674. define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
  8675. define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
  8676. define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/');
  8677. // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
  8678. define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
  8679. define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i');
  8680. // XXX far from perfect :-)
  8681. define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
  8682. ')(-([.0-9a-zA-Z]+))?');
  8683. define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
  8684. '\\z/');
  8685. define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
  8686. define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/');
  8687. // this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
  8688. define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
  8689. define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i');
  8690. define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
  8691. . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
  8692. define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i');
  8693. define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
  8694. . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
  8695. define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/');
  8696. /**
  8697. * List of temporary files and directories registered by
  8698. * PEAR_Common::addTempFile().
  8699. * @var array
  8700. */
  8701. $GLOBALS['_PEAR_Common_tempfiles'] = array();
  8702. /**
  8703. * Valid maintainer roles
  8704. * @var array
  8705. */
  8706. $GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
  8707. /**
  8708. * Valid release states
  8709. * @var array
  8710. */
  8711. $GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
  8712. /**
  8713. * Valid dependency types
  8714. * @var array
  8715. */
  8716. $GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
  8717. /**
  8718. * Valid dependency relations
  8719. * @var array
  8720. */
  8721. $GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
  8722. /**
  8723. * Valid file roles
  8724. * @var array
  8725. */
  8726. $GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
  8727. /**
  8728. * Valid replacement types
  8729. * @var array
  8730. */
  8731. $GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
  8732. /**
  8733. * Valid "provide" types
  8734. * @var array
  8735. */
  8736. $GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
  8737. /**
  8738. * Valid "provide" types
  8739. * @var array
  8740. */
  8741. $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
  8742. /**
  8743. * Class providing common functionality for PEAR administration classes.
  8744. * @category pear
  8745. * @package PEAR
  8746. * @author Stig Bakken <ssb@php.net>
  8747. * @author Tomas V. V. Cox <cox@idecnet.com>
  8748. * @author Greg Beaver <cellog@php.net>
  8749. * @copyright 1997-2009 The Authors
  8750. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  8751. * @version Release: 1.10.10
  8752. * @link http://pear.php.net/package/PEAR
  8753. * @since Class available since Release 1.4.0a1
  8754. * @deprecated This class will disappear, and its components will be spread
  8755. * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
  8756. */
  8757. class PEAR_Common extends PEAR
  8758. {
  8759. /**
  8760. * User Interface object (PEAR_Frontend_* class). If null,
  8761. * the log() method uses print.
  8762. * @var object
  8763. */
  8764. var $ui = null;
  8765. /**
  8766. * Configuration object (PEAR_Config).
  8767. * @var PEAR_Config
  8768. */
  8769. var $config = null;
  8770. /** stack of elements, gives some sort of XML context */
  8771. var $element_stack = array();
  8772. /** name of currently parsed XML element */
  8773. var $current_element;
  8774. /** array of attributes of the currently parsed XML element */
  8775. var $current_attributes = array();
  8776. /** assoc with information about a package */
  8777. var $pkginfo = array();
  8778. var $current_path = null;
  8779. /**
  8780. * Flag variable used to mark a valid package file
  8781. * @var boolean
  8782. * @access private
  8783. */
  8784. var $_validPackageFile;
  8785. /**
  8786. * PEAR_Common constructor
  8787. *
  8788. * @access public
  8789. */
  8790. function __construct()
  8791. {
  8792. parent::__construct();
  8793. $this->config = &PEAR_Config::singleton();
  8794. $this->debug = $this->config->get('verbose');
  8795. }
  8796. /**
  8797. * PEAR_Common destructor
  8798. *
  8799. * @access private
  8800. */
  8801. function _PEAR_Common()
  8802. {
  8803. // doesn't work due to bug #14744
  8804. //$tempfiles = $this->_tempfiles;
  8805. $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
  8806. while ($file = array_shift($tempfiles)) {
  8807. if (@is_dir($file)) {
  8808. if (!class_exists('System')) {
  8809. require_once 'phar://go-pear.phar/' . 'System.php';
  8810. }
  8811. System::rm(array('-rf', $file));
  8812. } elseif (file_exists($file)) {
  8813. unlink($file);
  8814. }
  8815. }
  8816. }
  8817. /**
  8818. * Register a temporary file or directory. When the destructor is
  8819. * executed, all registered temporary files and directories are
  8820. * removed.
  8821. *
  8822. * @param string $file name of file or directory
  8823. *
  8824. * @return void
  8825. *
  8826. * @access public
  8827. */
  8828. static function addTempFile($file)
  8829. {
  8830. if (!class_exists('PEAR_Frontend')) {
  8831. require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  8832. }
  8833. PEAR_Frontend::addTempFile($file);
  8834. }
  8835. /**
  8836. * Wrapper to System::mkDir(), creates a directory as well as
  8837. * any necessary parent directories.
  8838. *
  8839. * @param string $dir directory name
  8840. *
  8841. * @return bool TRUE on success, or a PEAR error
  8842. *
  8843. * @access public
  8844. */
  8845. function mkDirHier($dir)
  8846. {
  8847. // Only used in Installer - move it there ?
  8848. $this->log(2, "+ create dir $dir");
  8849. if (!class_exists('System')) {
  8850. require_once 'phar://go-pear.phar/' . 'System.php';
  8851. }
  8852. return System::mkDir(array('-p', $dir));
  8853. }
  8854. /**
  8855. * Logging method.
  8856. *
  8857. * @param int $level log level (0 is quiet, higher is noisier)
  8858. * @param string $msg message to write to the log
  8859. *
  8860. * @return void
  8861. */
  8862. public function log($level, $msg, $append_crlf = true)
  8863. {
  8864. if ($this->debug >= $level) {
  8865. if (!class_exists('PEAR_Frontend')) {
  8866. require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  8867. }
  8868. $ui = &PEAR_Frontend::singleton();
  8869. if (is_a($ui, 'PEAR_Frontend')) {
  8870. $ui->log($msg, $append_crlf);
  8871. } else {
  8872. print "$msg\n";
  8873. }
  8874. }
  8875. }
  8876. /**
  8877. * Create and register a temporary directory.
  8878. *
  8879. * @param string $tmpdir (optional) Directory to use as tmpdir.
  8880. * Will use system defaults (for example
  8881. * /tmp or c:\windows\temp) if not specified
  8882. *
  8883. * @return string name of created directory
  8884. *
  8885. * @access public
  8886. */
  8887. function mkTempDir($tmpdir = '')
  8888. {
  8889. $topt = $tmpdir ? array('-t', $tmpdir) : array();
  8890. $topt = array_merge($topt, array('-d', 'pear'));
  8891. if (!class_exists('System')) {
  8892. require_once 'phar://go-pear.phar/' . 'System.php';
  8893. }
  8894. if (!$tmpdir = System::mktemp($topt)) {
  8895. return false;
  8896. }
  8897. self::addTempFile($tmpdir);
  8898. return $tmpdir;
  8899. }
  8900. /**
  8901. * Set object that represents the frontend to be used.
  8902. *
  8903. * @param object Reference of the frontend object
  8904. * @return void
  8905. * @access public
  8906. */
  8907. function setFrontendObject(&$ui)
  8908. {
  8909. $this->ui = &$ui;
  8910. }
  8911. /**
  8912. * Return an array containing all of the states that are more stable than
  8913. * or equal to the passed in state
  8914. *
  8915. * @param string Release state
  8916. * @param boolean Determines whether to include $state in the list
  8917. * @return false|array False if $state is not a valid release state
  8918. */
  8919. static function betterStates($state, $include = false)
  8920. {
  8921. static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  8922. $i = array_search($state, $states);
  8923. if ($i === false) {
  8924. return false;
  8925. }
  8926. if ($include) {
  8927. $i--;
  8928. }
  8929. return array_slice($states, $i + 1);
  8930. }
  8931. /**
  8932. * Get the valid roles for a PEAR package maintainer
  8933. *
  8934. * @return array
  8935. */
  8936. public static function getUserRoles()
  8937. {
  8938. return $GLOBALS['_PEAR_Common_maintainer_roles'];
  8939. }
  8940. /**
  8941. * Get the valid package release states of packages
  8942. *
  8943. * @return array
  8944. */
  8945. public static function getReleaseStates()
  8946. {
  8947. return $GLOBALS['_PEAR_Common_release_states'];
  8948. }
  8949. /**
  8950. * Get the implemented dependency types (php, ext, pkg etc.)
  8951. *
  8952. * @return array
  8953. */
  8954. public static function getDependencyTypes()
  8955. {
  8956. return $GLOBALS['_PEAR_Common_dependency_types'];
  8957. }
  8958. /**
  8959. * Get the implemented dependency relations (has, lt, ge etc.)
  8960. *
  8961. * @return array
  8962. */
  8963. public static function getDependencyRelations()
  8964. {
  8965. return $GLOBALS['_PEAR_Common_dependency_relations'];
  8966. }
  8967. /**
  8968. * Get the implemented file roles
  8969. *
  8970. * @return array
  8971. */
  8972. public static function getFileRoles()
  8973. {
  8974. return $GLOBALS['_PEAR_Common_file_roles'];
  8975. }
  8976. /**
  8977. * Get the implemented file replacement types in
  8978. *
  8979. * @return array
  8980. */
  8981. public static function getReplacementTypes()
  8982. {
  8983. return $GLOBALS['_PEAR_Common_replacement_types'];
  8984. }
  8985. /**
  8986. * Get the implemented file replacement types in
  8987. *
  8988. * @return array
  8989. */
  8990. public static function getProvideTypes()
  8991. {
  8992. return $GLOBALS['_PEAR_Common_provide_types'];
  8993. }
  8994. /**
  8995. * Get the implemented file replacement types in
  8996. *
  8997. * @return array
  8998. */
  8999. public static function getScriptPhases()
  9000. {
  9001. return $GLOBALS['_PEAR_Common_script_phases'];
  9002. }
  9003. /**
  9004. * Test whether a string contains a valid package name.
  9005. *
  9006. * @param string $name the package name to test
  9007. *
  9008. * @return bool
  9009. *
  9010. * @access public
  9011. */
  9012. function validPackageName($name)
  9013. {
  9014. return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
  9015. }
  9016. /**
  9017. * Test whether a string contains a valid package version.
  9018. *
  9019. * @param string $ver the package version to test
  9020. *
  9021. * @return bool
  9022. *
  9023. * @access public
  9024. */
  9025. function validPackageVersion($ver)
  9026. {
  9027. return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
  9028. }
  9029. /**
  9030. * @param string $path relative or absolute include path
  9031. * @return boolean
  9032. */
  9033. public static function isIncludeable($path)
  9034. {
  9035. if (file_exists($path) && is_readable($path)) {
  9036. return true;
  9037. }
  9038. $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
  9039. foreach ($ipath as $include) {
  9040. $test = realpath($include . DIRECTORY_SEPARATOR . $path);
  9041. if (file_exists($test) && is_readable($test)) {
  9042. return true;
  9043. }
  9044. }
  9045. return false;
  9046. }
  9047. function _postProcessChecks($pf)
  9048. {
  9049. if (!PEAR::isError($pf)) {
  9050. return $this->_postProcessValidPackagexml($pf);
  9051. }
  9052. $errs = $pf->getUserinfo();
  9053. if (is_array($errs)) {
  9054. foreach ($errs as $error) {
  9055. $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  9056. }
  9057. }
  9058. return $pf;
  9059. }
  9060. /**
  9061. * Returns information about a package file. Expects the name of
  9062. * a gzipped tar file as input.
  9063. *
  9064. * @param string $file name of .tgz file
  9065. *
  9066. * @return array array with package information
  9067. *
  9068. * @access public
  9069. * @deprecated use PEAR_PackageFile->fromTgzFile() instead
  9070. *
  9071. */
  9072. function infoFromTgzFile($file)
  9073. {
  9074. $packagefile = new PEAR_PackageFile($this->config);
  9075. $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
  9076. return $this->_postProcessChecks($pf);
  9077. }
  9078. /**
  9079. * Returns information about a package file. Expects the name of
  9080. * a package xml file as input.
  9081. *
  9082. * @param string $descfile name of package xml file
  9083. *
  9084. * @return array array with package information
  9085. *
  9086. * @access public
  9087. * @deprecated use PEAR_PackageFile->fromPackageFile() instead
  9088. *
  9089. */
  9090. function infoFromDescriptionFile($descfile)
  9091. {
  9092. $packagefile = new PEAR_PackageFile($this->config);
  9093. $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
  9094. return $this->_postProcessChecks($pf);
  9095. }
  9096. /**
  9097. * Returns information about a package file. Expects the contents
  9098. * of a package xml file as input.
  9099. *
  9100. * @param string $data contents of package.xml file
  9101. *
  9102. * @return array array with package information
  9103. *
  9104. * @access public
  9105. * @deprecated use PEAR_PackageFile->fromXmlstring() instead
  9106. *
  9107. */
  9108. function infoFromString($data)
  9109. {
  9110. $packagefile = new PEAR_PackageFile($this->config);
  9111. $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
  9112. return $this->_postProcessChecks($pf);
  9113. }
  9114. /**
  9115. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  9116. * @return array
  9117. */
  9118. function _postProcessValidPackagexml(&$pf)
  9119. {
  9120. if (!is_a($pf, 'PEAR_PackageFile_v2')) {
  9121. $this->pkginfo = $pf->toArray();
  9122. return $this->pkginfo;
  9123. }
  9124. // sort of make this into a package.xml 1.0-style array
  9125. // changelog is not converted to old format.
  9126. $arr = $pf->toArray(true);
  9127. $arr = array_merge($arr, $arr['old']);
  9128. unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'],
  9129. $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'],
  9130. $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'],
  9131. $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'],
  9132. $arr['helper'], $arr['contributor']);
  9133. $arr['filelist'] = $pf->getFilelist();
  9134. $this->pkginfo = $arr;
  9135. return $arr;
  9136. }
  9137. /**
  9138. * Returns package information from different sources
  9139. *
  9140. * This method is able to extract information about a package
  9141. * from a .tgz archive or from a XML package definition file.
  9142. *
  9143. * @access public
  9144. * @param string Filename of the source ('package.xml', '<package>.tgz')
  9145. * @return string
  9146. * @deprecated use PEAR_PackageFile->fromAnyFile() instead
  9147. */
  9148. function infoFromAny($info)
  9149. {
  9150. if (is_string($info) && file_exists($info)) {
  9151. $packagefile = new PEAR_PackageFile($this->config);
  9152. $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  9153. if (PEAR::isError($pf)) {
  9154. $errs = $pf->getUserinfo();
  9155. if (is_array($errs)) {
  9156. foreach ($errs as $error) {
  9157. $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  9158. }
  9159. }
  9160. return $pf;
  9161. }
  9162. return $this->_postProcessValidPackagexml($pf);
  9163. }
  9164. return $info;
  9165. }
  9166. /**
  9167. * Return an XML document based on the package info (as returned
  9168. * by the PEAR_Common::infoFrom* methods).
  9169. *
  9170. * @param array $pkginfo package info
  9171. *
  9172. * @return string XML data
  9173. *
  9174. * @access public
  9175. * @deprecated use a PEAR_PackageFile_v* object's generator instead
  9176. */
  9177. function xmlFromInfo($pkginfo)
  9178. {
  9179. $config = &PEAR_Config::singleton();
  9180. $packagefile = new PEAR_PackageFile($config);
  9181. $pf = &$packagefile->fromArray($pkginfo);
  9182. $gen = &$pf->getDefaultGenerator();
  9183. return $gen->toXml(PEAR_VALIDATE_PACKAGING);
  9184. }
  9185. /**
  9186. * Validate XML package definition file.
  9187. *
  9188. * @param string $info Filename of the package archive or of the
  9189. * package definition file
  9190. * @param array $errors Array that will contain the errors
  9191. * @param array $warnings Array that will contain the warnings
  9192. * @param string $dir_prefix (optional) directory where source files
  9193. * may be found, or empty if they are not available
  9194. * @access public
  9195. * @return boolean
  9196. * @deprecated use the validation of PEAR_PackageFile objects
  9197. */
  9198. function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
  9199. {
  9200. $config = &PEAR_Config::singleton();
  9201. $packagefile = new PEAR_PackageFile($config);
  9202. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  9203. if (strpos($info, '<?xml') !== false) {
  9204. $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
  9205. } else {
  9206. $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  9207. }
  9208. PEAR::staticPopErrorHandling();
  9209. if (PEAR::isError($pf)) {
  9210. $errs = $pf->getUserinfo();
  9211. if (is_array($errs)) {
  9212. foreach ($errs as $error) {
  9213. if ($error['level'] == 'error') {
  9214. $errors[] = $error['message'];
  9215. } else {
  9216. $warnings[] = $error['message'];
  9217. }
  9218. }
  9219. }
  9220. return false;
  9221. }
  9222. return true;
  9223. }
  9224. /**
  9225. * Build a "provides" array from data returned by
  9226. * analyzeSourceCode(). The format of the built array is like
  9227. * this:
  9228. *
  9229. * array(
  9230. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  9231. * ...
  9232. * )
  9233. *
  9234. *
  9235. * @param array $srcinfo array with information about a source file
  9236. * as returned by the analyzeSourceCode() method.
  9237. *
  9238. * @return void
  9239. *
  9240. * @access public
  9241. *
  9242. */
  9243. function buildProvidesArray($srcinfo)
  9244. {
  9245. $file = basename($srcinfo['source_file']);
  9246. $pn = '';
  9247. if (isset($this->_packageName)) {
  9248. $pn = $this->_packageName;
  9249. }
  9250. $pnl = strlen($pn);
  9251. foreach ($srcinfo['declared_classes'] as $class) {
  9252. $key = "class;$class";
  9253. if (isset($this->pkginfo['provides'][$key])) {
  9254. continue;
  9255. }
  9256. $this->pkginfo['provides'][$key] =
  9257. array('file'=> $file, 'type' => 'class', 'name' => $class);
  9258. if (isset($srcinfo['inheritance'][$class])) {
  9259. $this->pkginfo['provides'][$key]['extends'] =
  9260. $srcinfo['inheritance'][$class];
  9261. }
  9262. }
  9263. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  9264. foreach ($methods as $method) {
  9265. $function = "$class::$method";
  9266. $key = "function;$function";
  9267. if ($method[0] == '_' || !strcasecmp($method, $class) ||
  9268. isset($this->pkginfo['provides'][$key])) {
  9269. continue;
  9270. }
  9271. $this->pkginfo['provides'][$key] =
  9272. array('file'=> $file, 'type' => 'function', 'name' => $function);
  9273. }
  9274. }
  9275. foreach ($srcinfo['declared_functions'] as $function) {
  9276. $key = "function;$function";
  9277. if ($function[0] == '_' || isset($this->pkginfo['provides'][$key])) {
  9278. continue;
  9279. }
  9280. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  9281. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  9282. }
  9283. $this->pkginfo['provides'][$key] =
  9284. array('file'=> $file, 'type' => 'function', 'name' => $function);
  9285. }
  9286. }
  9287. /**
  9288. * Analyze the source code of the given PHP file
  9289. *
  9290. * @param string Filename of the PHP file
  9291. * @return mixed
  9292. * @access public
  9293. */
  9294. static function analyzeSourceCode($file)
  9295. {
  9296. if (!class_exists('PEAR_PackageFile_v2_Validator')) {
  9297. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/Validator.php';
  9298. }
  9299. $a = new PEAR_PackageFile_v2_Validator;
  9300. return $a->analyzeSourceCode($file);
  9301. }
  9302. function detectDependencies($any, $status_callback = null)
  9303. {
  9304. if (!function_exists("token_get_all")) {
  9305. return false;
  9306. }
  9307. if (PEAR::isError($info = $this->infoFromAny($any))) {
  9308. return $this->raiseError($info);
  9309. }
  9310. if (!is_array($info)) {
  9311. return false;
  9312. }
  9313. $deps = array();
  9314. $used_c = $decl_c = $decl_f = $decl_m = array();
  9315. foreach ($info['filelist'] as $file => $fa) {
  9316. $tmp = $this->analyzeSourceCode($file);
  9317. $used_c = @array_merge($used_c, $tmp['used_classes']);
  9318. $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
  9319. $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
  9320. $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
  9321. $inheri = @array_merge($inheri, $tmp['inheritance']);
  9322. }
  9323. $used_c = array_unique($used_c);
  9324. $decl_c = array_unique($decl_c);
  9325. $undecl_c = array_diff($used_c, $decl_c);
  9326. return array('used_classes' => $used_c,
  9327. 'declared_classes' => $decl_c,
  9328. 'declared_methods' => $decl_m,
  9329. 'declared_functions' => $decl_f,
  9330. 'undeclared_classes' => $undecl_c,
  9331. 'inheritance' => $inheri,
  9332. );
  9333. }
  9334. /**
  9335. * Download a file through HTTP. Considers suggested file name in
  9336. * Content-disposition: header and can run a callback function for
  9337. * different events. The callback will be called with two
  9338. * parameters: the callback type, and parameters. The implemented
  9339. * callback types are:
  9340. *
  9341. * 'setup' called at the very beginning, parameter is a UI object
  9342. * that should be used for all output
  9343. * 'message' the parameter is a string with an informational message
  9344. * 'saveas' may be used to save with a different file name, the
  9345. * parameter is the filename that is about to be used.
  9346. * If a 'saveas' callback returns a non-empty string,
  9347. * that file name will be used as the filename instead.
  9348. * Note that $save_dir will not be affected by this, only
  9349. * the basename of the file.
  9350. * 'start' download is starting, parameter is number of bytes
  9351. * that are expected, or -1 if unknown
  9352. * 'bytesread' parameter is the number of bytes read so far
  9353. * 'done' download is complete, parameter is the total number
  9354. * of bytes read
  9355. * 'connfailed' if the TCP connection fails, this callback is called
  9356. * with array(host,port,errno,errmsg)
  9357. * 'writefailed' if writing to disk fails, this callback is called
  9358. * with array(destfile,errmsg)
  9359. *
  9360. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  9361. * setting), the proxy will be used.
  9362. *
  9363. * @param string $url the URL to download
  9364. * @param object $ui PEAR_Frontend_* instance
  9365. * @param object $config PEAR_Config instance
  9366. * @param string $save_dir (optional) directory to save file in
  9367. * @param mixed $callback (optional) function/method to call for status
  9368. * updates
  9369. * @param false|string|array $lastmodified header values to check against
  9370. * for caching
  9371. * use false to return the header
  9372. * values from this download
  9373. * @param false|array $accept Accept headers to send
  9374. * @param false|string $channel Channel to use for retrieving
  9375. * authentication
  9376. *
  9377. * @return mixed Returns the full path of the downloaded file or a PEAR
  9378. * error on failure. If the error is caused by
  9379. * socket-related errors, the error object will
  9380. * have the fsockopen error code available through
  9381. * getCode(). If caching is requested, then return the header
  9382. * values.
  9383. * If $lastmodified was given and the there are no changes,
  9384. * boolean false is returned.
  9385. *
  9386. * @access public
  9387. */
  9388. function downloadHttp(
  9389. $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
  9390. $accept = false, $channel = false
  9391. ) {
  9392. if (!class_exists('PEAR_Downloader')) {
  9393. require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php';
  9394. }
  9395. return PEAR_Downloader::_downloadHttp(
  9396. $this, $url, $ui, $save_dir, $callback, $lastmodified,
  9397. $accept, $channel
  9398. );
  9399. }
  9400. }
  9401. require_once 'phar://go-pear.phar/' . 'PEAR/Config.php';
  9402. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php';
  9403. <?php
  9404. /**
  9405. * PEAR_Config, customized configuration handling for the PEAR Installer
  9406. *
  9407. * PHP versions 4 and 5
  9408. *
  9409. * @category pear
  9410. * @package PEAR
  9411. * @author Stig Bakken <ssb@php.net>
  9412. * @author Greg Beaver <cellog@php.net>
  9413. * @copyright 1997-2009 The Authors
  9414. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  9415. * @link http://pear.php.net/package/PEAR
  9416. * @since File available since Release 0.1
  9417. */
  9418. /**
  9419. * Required for error handling
  9420. */
  9421. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  9422. require_once 'phar://go-pear.phar/' . 'PEAR/Registry.php';
  9423. require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php';
  9424. require_once 'phar://go-pear.phar/' . 'System.php';
  9425. /**
  9426. * Last created PEAR_Config instance.
  9427. * @var object
  9428. */
  9429. $GLOBALS['_PEAR_Config_instance'] = null;
  9430. if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
  9431. $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
  9432. } else {
  9433. $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
  9434. }
  9435. // Below we define constants with default values for all configuration
  9436. // parameters except username/password. All of them can have their
  9437. // defaults set through environment variables. The reason we use the
  9438. // PHP_ prefix is for some security, PHP protects environment
  9439. // variables starting with PHP_*.
  9440. // default channel and preferred mirror is based on whether we are invoked through
  9441. // the "pear" or the "pecl" command
  9442. if (!defined('PEAR_RUNTYPE')) {
  9443. define('PEAR_RUNTYPE', 'pear');
  9444. }
  9445. if (PEAR_RUNTYPE == 'pear') {
  9446. define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
  9447. } else {
  9448. define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
  9449. }
  9450. if (getenv('PHP_PEAR_SYSCONF_DIR')) {
  9451. define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
  9452. } elseif (getenv('SystemRoot')) {
  9453. define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
  9454. } else {
  9455. define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
  9456. }
  9457. // Default for master_server
  9458. if (getenv('PHP_PEAR_MASTER_SERVER')) {
  9459. define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
  9460. } else {
  9461. define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
  9462. }
  9463. // Default for http_proxy
  9464. if (getenv('PHP_PEAR_HTTP_PROXY')) {
  9465. define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
  9466. } elseif (getenv('http_proxy')) {
  9467. define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
  9468. } else {
  9469. define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
  9470. }
  9471. // Default for php_dir
  9472. if (getenv('PHP_PEAR_INSTALL_DIR')) {
  9473. define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
  9474. } else {
  9475. if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
  9476. define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
  9477. } else {
  9478. define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
  9479. }
  9480. }
  9481. // Default for metadata_dir
  9482. if (getenv('PHP_PEAR_METADATA_DIR')) {
  9483. define('PEAR_CONFIG_DEFAULT_METADATA_DIR', getenv('PHP_PEAR_METADATA_DIR'));
  9484. } else {
  9485. define('PEAR_CONFIG_DEFAULT_METADATA_DIR', '');
  9486. }
  9487. // Default for ext_dir
  9488. if (getenv('PHP_PEAR_EXTENSION_DIR')) {
  9489. define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
  9490. } else {
  9491. if (ini_get('extension_dir')) {
  9492. define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
  9493. } elseif (defined('PEAR_EXTENSION_DIR') &&
  9494. file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
  9495. define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
  9496. } elseif (defined('PHP_EXTENSION_DIR')) {
  9497. define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
  9498. } else {
  9499. define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
  9500. }
  9501. }
  9502. // Default for doc_dir
  9503. if (getenv('PHP_PEAR_DOC_DIR')) {
  9504. define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
  9505. } else {
  9506. define('PEAR_CONFIG_DEFAULT_DOC_DIR',
  9507. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
  9508. }
  9509. // Default for bin_dir
  9510. if (getenv('PHP_PEAR_BIN_DIR')) {
  9511. define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
  9512. } else {
  9513. define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
  9514. }
  9515. // Default for data_dir
  9516. if (getenv('PHP_PEAR_DATA_DIR')) {
  9517. define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
  9518. } else {
  9519. define('PEAR_CONFIG_DEFAULT_DATA_DIR',
  9520. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
  9521. }
  9522. // Default for cfg_dir
  9523. if (getenv('PHP_PEAR_CFG_DIR')) {
  9524. define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
  9525. } else {
  9526. define('PEAR_CONFIG_DEFAULT_CFG_DIR',
  9527. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
  9528. }
  9529. // Default for www_dir
  9530. if (getenv('PHP_PEAR_WWW_DIR')) {
  9531. define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
  9532. } else {
  9533. define('PEAR_CONFIG_DEFAULT_WWW_DIR',
  9534. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
  9535. }
  9536. // Default for man_dir
  9537. if (getenv('PHP_PEAR_MAN_DIR')) {
  9538. define('PEAR_CONFIG_DEFAULT_MAN_DIR', getenv('PHP_PEAR_MAN_DIR'));
  9539. } else {
  9540. if (defined('PHP_MANDIR')) { // Added in PHP5.3.7
  9541. define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_MANDIR);
  9542. } else {
  9543. define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_PREFIX . DIRECTORY_SEPARATOR .
  9544. 'local' . DIRECTORY_SEPARATOR .'man');
  9545. }
  9546. }
  9547. // Default for test_dir
  9548. if (getenv('PHP_PEAR_TEST_DIR')) {
  9549. define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
  9550. } else {
  9551. define('PEAR_CONFIG_DEFAULT_TEST_DIR',
  9552. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
  9553. }
  9554. // Default for temp_dir
  9555. if (getenv('PHP_PEAR_TEMP_DIR')) {
  9556. define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
  9557. } else {
  9558. define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
  9559. System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9560. DIRECTORY_SEPARATOR . 'temp');
  9561. }
  9562. // Default for cache_dir
  9563. if (getenv('PHP_PEAR_CACHE_DIR')) {
  9564. define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
  9565. } else {
  9566. define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
  9567. System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9568. DIRECTORY_SEPARATOR . 'cache');
  9569. }
  9570. // Default for download_dir
  9571. if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
  9572. define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
  9573. } else {
  9574. define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
  9575. System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9576. DIRECTORY_SEPARATOR . 'download');
  9577. }
  9578. // Default for php_bin
  9579. if (getenv('PHP_PEAR_PHP_BIN')) {
  9580. define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
  9581. } else {
  9582. define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
  9583. DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
  9584. }
  9585. // Default for verbose
  9586. if (getenv('PHP_PEAR_VERBOSE')) {
  9587. define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
  9588. } else {
  9589. define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
  9590. }
  9591. // Default for preferred_state
  9592. if (getenv('PHP_PEAR_PREFERRED_STATE')) {
  9593. define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
  9594. } else {
  9595. define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
  9596. }
  9597. // Default for umask
  9598. if (getenv('PHP_PEAR_UMASK')) {
  9599. define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
  9600. } else {
  9601. define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
  9602. }
  9603. // Default for cache_ttl
  9604. if (getenv('PHP_PEAR_CACHE_TTL')) {
  9605. define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
  9606. } else {
  9607. define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
  9608. }
  9609. // Default for sig_type
  9610. if (getenv('PHP_PEAR_SIG_TYPE')) {
  9611. define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
  9612. } else {
  9613. define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
  9614. }
  9615. // Default for sig_bin
  9616. if (getenv('PHP_PEAR_SIG_BIN')) {
  9617. define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
  9618. } else {
  9619. define('PEAR_CONFIG_DEFAULT_SIG_BIN',
  9620. System::which(
  9621. 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
  9622. }
  9623. // Default for sig_keydir
  9624. if (getenv('PHP_PEAR_SIG_KEYDIR')) {
  9625. define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
  9626. } else {
  9627. define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
  9628. PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
  9629. }
  9630. /**
  9631. * This is a class for storing configuration data, keeping track of
  9632. * which are system-defined, user-defined or defaulted.
  9633. * @category pear
  9634. * @package PEAR
  9635. * @author Stig Bakken <ssb@php.net>
  9636. * @author Greg Beaver <cellog@php.net>
  9637. * @copyright 1997-2009 The Authors
  9638. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  9639. * @version Release: 1.10.10
  9640. * @link http://pear.php.net/package/PEAR
  9641. * @since Class available since Release 0.1
  9642. */
  9643. class PEAR_Config extends PEAR
  9644. {
  9645. /**
  9646. * Array of config files used.
  9647. *
  9648. * @var array layer => config file
  9649. */
  9650. var $files = array(
  9651. 'system' => '',
  9652. 'user' => '',
  9653. );
  9654. var $layers = array();
  9655. /**
  9656. * Configuration data, two-dimensional array where the first
  9657. * dimension is the config layer ('user', 'system' and 'default'),
  9658. * and the second dimension is keyname => value.
  9659. *
  9660. * The order in the first dimension is important! Earlier
  9661. * layers will shadow later ones when a config value is
  9662. * requested (if a 'user' value exists, it will be returned first,
  9663. * then 'system' and finally 'default').
  9664. *
  9665. * @var array layer => array(keyname => value, ...)
  9666. */
  9667. var $configuration = array(
  9668. 'user' => array(),
  9669. 'system' => array(),
  9670. 'default' => array(),
  9671. );
  9672. /**
  9673. * Configuration values that can be set for a channel
  9674. *
  9675. * All other configuration values can only have a global value
  9676. * @var array
  9677. * @access private
  9678. */
  9679. var $_channelConfigInfo = array(
  9680. 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir',
  9681. 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username',
  9682. 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini'
  9683. );
  9684. /**
  9685. * Channels that can be accessed
  9686. * @see setChannels()
  9687. * @var array
  9688. * @access private
  9689. */
  9690. var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
  9691. /**
  9692. * This variable is used to control the directory values returned
  9693. * @see setInstallRoot();
  9694. * @var string|false
  9695. * @access private
  9696. */
  9697. var $_installRoot = false;
  9698. /**
  9699. * If requested, this will always refer to the registry
  9700. * contained in php_dir
  9701. * @var PEAR_Registry
  9702. */
  9703. var $_registry = array();
  9704. /**
  9705. * @var array
  9706. * @access private
  9707. */
  9708. var $_regInitialized = array();
  9709. /**
  9710. * @var bool
  9711. * @access private
  9712. */
  9713. var $_noRegistry = false;
  9714. /**
  9715. * amount of errors found while parsing config
  9716. * @var integer
  9717. * @access private
  9718. */
  9719. var $_errorsFound = 0;
  9720. var $_lastError = null;
  9721. /**
  9722. * Information about the configuration data. Stores the type,
  9723. * default value and a documentation string for each configuration
  9724. * value.
  9725. *
  9726. * @var array layer => array(infotype => value, ...)
  9727. */
  9728. var $configuration_info = array(
  9729. // Channels/Internet Access
  9730. 'default_channel' => array(
  9731. 'type' => 'string',
  9732. 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  9733. 'doc' => 'the default channel to use for all non explicit commands',
  9734. 'prompt' => 'Default Channel',
  9735. 'group' => 'Internet Access',
  9736. ),
  9737. 'preferred_mirror' => array(
  9738. 'type' => 'string',
  9739. 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  9740. 'doc' => 'the default server or mirror to use for channel actions',
  9741. 'prompt' => 'Default Channel Mirror',
  9742. 'group' => 'Internet Access',
  9743. ),
  9744. 'remote_config' => array(
  9745. 'type' => 'password',
  9746. 'default' => '',
  9747. 'doc' => 'ftp url of remote configuration file to use for synchronized install',
  9748. 'prompt' => 'Remote Configuration File',
  9749. 'group' => 'Internet Access',
  9750. ),
  9751. 'auto_discover' => array(
  9752. 'type' => 'integer',
  9753. 'default' => 0,
  9754. 'doc' => 'whether to automatically discover new channels',
  9755. 'prompt' => 'Auto-discover new Channels',
  9756. 'group' => 'Internet Access',
  9757. ),
  9758. // Internet Access
  9759. 'master_server' => array(
  9760. 'type' => 'string',
  9761. 'default' => 'pear.php.net',
  9762. 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
  9763. 'prompt' => 'PEAR server [DEPRECATED]',
  9764. 'group' => 'Internet Access',
  9765. ),
  9766. 'http_proxy' => array(
  9767. 'type' => 'string',
  9768. 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
  9769. 'doc' => 'HTTP proxy (host:port) to use when downloading packages',
  9770. 'prompt' => 'HTTP Proxy Server Address',
  9771. 'group' => 'Internet Access',
  9772. ),
  9773. // File Locations
  9774. 'php_dir' => array(
  9775. 'type' => 'directory',
  9776. 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
  9777. 'doc' => 'directory where .php files are installed',
  9778. 'prompt' => 'PEAR directory',
  9779. 'group' => 'File Locations',
  9780. ),
  9781. 'ext_dir' => array(
  9782. 'type' => 'directory',
  9783. 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
  9784. 'doc' => 'directory where loadable extensions are installed',
  9785. 'prompt' => 'PHP extension directory',
  9786. 'group' => 'File Locations',
  9787. ),
  9788. 'doc_dir' => array(
  9789. 'type' => 'directory',
  9790. 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
  9791. 'doc' => 'directory where documentation is installed',
  9792. 'prompt' => 'PEAR documentation directory',
  9793. 'group' => 'File Locations',
  9794. ),
  9795. 'bin_dir' => array(
  9796. 'type' => 'directory',
  9797. 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
  9798. 'doc' => 'directory where executables are installed',
  9799. 'prompt' => 'PEAR executables directory',
  9800. 'group' => 'File Locations',
  9801. ),
  9802. 'data_dir' => array(
  9803. 'type' => 'directory',
  9804. 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
  9805. 'doc' => 'directory where data files are installed',
  9806. 'prompt' => 'PEAR data directory',
  9807. 'group' => 'File Locations (Advanced)',
  9808. ),
  9809. 'cfg_dir' => array(
  9810. 'type' => 'directory',
  9811. 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR,
  9812. 'doc' => 'directory where modifiable configuration files are installed',
  9813. 'prompt' => 'PEAR configuration file directory',
  9814. 'group' => 'File Locations (Advanced)',
  9815. ),
  9816. 'www_dir' => array(
  9817. 'type' => 'directory',
  9818. 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR,
  9819. 'doc' => 'directory where www frontend files (html/js) are installed',
  9820. 'prompt' => 'PEAR www files directory',
  9821. 'group' => 'File Locations (Advanced)',
  9822. ),
  9823. 'man_dir' => array(
  9824. 'type' => 'directory',
  9825. 'default' => PEAR_CONFIG_DEFAULT_MAN_DIR,
  9826. 'doc' => 'directory where unix manual pages are installed',
  9827. 'prompt' => 'Systems manpage files directory',
  9828. 'group' => 'File Locations (Advanced)',
  9829. ),
  9830. 'test_dir' => array(
  9831. 'type' => 'directory',
  9832. 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
  9833. 'doc' => 'directory where regression tests are installed',
  9834. 'prompt' => 'PEAR test directory',
  9835. 'group' => 'File Locations (Advanced)',
  9836. ),
  9837. 'cache_dir' => array(
  9838. 'type' => 'directory',
  9839. 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
  9840. 'doc' => 'directory which is used for web service cache',
  9841. 'prompt' => 'PEAR Installer cache directory',
  9842. 'group' => 'File Locations (Advanced)',
  9843. ),
  9844. 'temp_dir' => array(
  9845. 'type' => 'directory',
  9846. 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
  9847. 'doc' => 'directory which is used for all temp files',
  9848. 'prompt' => 'PEAR Installer temp directory',
  9849. 'group' => 'File Locations (Advanced)',
  9850. ),
  9851. 'download_dir' => array(
  9852. 'type' => 'directory',
  9853. 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR,
  9854. 'doc' => 'directory which is used for all downloaded files',
  9855. 'prompt' => 'PEAR Installer download directory',
  9856. 'group' => 'File Locations (Advanced)',
  9857. ),
  9858. 'php_bin' => array(
  9859. 'type' => 'file',
  9860. 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
  9861. 'doc' => 'PHP CLI/CGI binary for executing scripts',
  9862. 'prompt' => 'PHP CLI/CGI binary',
  9863. 'group' => 'File Locations (Advanced)',
  9864. ),
  9865. 'php_prefix' => array(
  9866. 'type' => 'string',
  9867. 'default' => '',
  9868. 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs',
  9869. 'prompt' => '--program-prefix passed to PHP\'s ./configure',
  9870. 'group' => 'File Locations (Advanced)',
  9871. ),
  9872. 'php_suffix' => array(
  9873. 'type' => 'string',
  9874. 'default' => '',
  9875. 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs',
  9876. 'prompt' => '--program-suffix passed to PHP\'s ./configure',
  9877. 'group' => 'File Locations (Advanced)',
  9878. ),
  9879. 'php_ini' => array(
  9880. 'type' => 'file',
  9881. 'default' => '',
  9882. 'doc' => 'location of php.ini in which to enable PECL extensions on install',
  9883. 'prompt' => 'php.ini location',
  9884. 'group' => 'File Locations (Advanced)',
  9885. ),
  9886. 'metadata_dir' => array(
  9887. 'type' => 'directory',
  9888. 'default' => PEAR_CONFIG_DEFAULT_METADATA_DIR,
  9889. 'doc' => 'directory where metadata files are installed (registry, filemap, channels, ...)',
  9890. 'prompt' => 'PEAR metadata directory',
  9891. 'group' => 'File Locations (Advanced)',
  9892. ),
  9893. // Maintainers
  9894. 'username' => array(
  9895. 'type' => 'string',
  9896. 'default' => '',
  9897. 'doc' => '(maintainers) your PEAR account name',
  9898. 'prompt' => 'PEAR username (for maintainers)',
  9899. 'group' => 'Maintainers',
  9900. ),
  9901. 'password' => array(
  9902. 'type' => 'password',
  9903. 'default' => '',
  9904. 'doc' => '(maintainers) your PEAR account password',
  9905. 'prompt' => 'PEAR password (for maintainers)',
  9906. 'group' => 'Maintainers',
  9907. ),
  9908. // Advanced
  9909. 'verbose' => array(
  9910. 'type' => 'integer',
  9911. 'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
  9912. 'doc' => 'verbosity level
  9913. 0: really quiet
  9914. 1: somewhat quiet
  9915. 2: verbose
  9916. 3: debug',
  9917. 'prompt' => 'Debug Log Level',
  9918. 'group' => 'Advanced',
  9919. ),
  9920. 'preferred_state' => array(
  9921. 'type' => 'set',
  9922. 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
  9923. 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
  9924. 'valid_set' => array(
  9925. 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
  9926. 'prompt' => 'Preferred Package State',
  9927. 'group' => 'Advanced',
  9928. ),
  9929. 'umask' => array(
  9930. 'type' => 'mask',
  9931. 'default' => PEAR_CONFIG_DEFAULT_UMASK,
  9932. 'doc' => 'umask used when creating files (Unix-like systems only)',
  9933. 'prompt' => 'Unix file mask',
  9934. 'group' => 'Advanced',
  9935. ),
  9936. 'cache_ttl' => array(
  9937. 'type' => 'integer',
  9938. 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
  9939. 'doc' => 'amount of secs where the local cache is used and not updated',
  9940. 'prompt' => 'Cache TimeToLive',
  9941. 'group' => 'Advanced',
  9942. ),
  9943. 'sig_type' => array(
  9944. 'type' => 'set',
  9945. 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
  9946. 'doc' => 'which package signature mechanism to use',
  9947. 'valid_set' => array('gpg'),
  9948. 'prompt' => 'Package Signature Type',
  9949. 'group' => 'Maintainers',
  9950. ),
  9951. 'sig_bin' => array(
  9952. 'type' => 'string',
  9953. 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
  9954. 'doc' => 'which package signature mechanism to use',
  9955. 'prompt' => 'Signature Handling Program',
  9956. 'group' => 'Maintainers',
  9957. ),
  9958. 'sig_keyid' => array(
  9959. 'type' => 'string',
  9960. 'default' => '',
  9961. 'doc' => 'which key to use for signing with',
  9962. 'prompt' => 'Signature Key Id',
  9963. 'group' => 'Maintainers',
  9964. ),
  9965. 'sig_keydir' => array(
  9966. 'type' => 'directory',
  9967. 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
  9968. 'doc' => 'directory where signature keys are located',
  9969. 'prompt' => 'Signature Key Directory',
  9970. 'group' => 'Maintainers',
  9971. ),
  9972. // __channels is reserved - used for channel-specific configuration
  9973. );
  9974. /**
  9975. * Constructor.
  9976. *
  9977. * @param string file to read user-defined options from
  9978. * @param string file to read system-wide defaults from
  9979. * @param bool determines whether a registry object "follows"
  9980. * the value of php_dir (is automatically created
  9981. * and moved when php_dir is changed)
  9982. * @param bool if true, fails if configuration files cannot be loaded
  9983. *
  9984. * @access public
  9985. *
  9986. * @see PEAR_Config::singleton
  9987. */
  9988. function __construct($user_file = '', $system_file = '', $ftp_file = false,
  9989. $strict = true)
  9990. {
  9991. parent::__construct();
  9992. PEAR_Installer_Role::initializeConfig($this);
  9993. $sl = DIRECTORY_SEPARATOR;
  9994. if (empty($user_file)) {
  9995. if (OS_WINDOWS) {
  9996. $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
  9997. } else {
  9998. $user_file = getenv('HOME') . $sl . '.pearrc';
  9999. }
  10000. }
  10001. if (empty($system_file)) {
  10002. $system_file = PEAR_CONFIG_SYSCONFDIR . $sl;
  10003. if (OS_WINDOWS) {
  10004. $system_file .= 'pearsys.ini';
  10005. } else {
  10006. $system_file .= 'pear.conf';
  10007. }
  10008. }
  10009. $this->layers = array_keys($this->configuration);
  10010. $this->files['user'] = $user_file;
  10011. $this->files['system'] = $system_file;
  10012. if ($user_file && file_exists($user_file)) {
  10013. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  10014. $this->readConfigFile($user_file, 'user', $strict);
  10015. $this->popErrorHandling();
  10016. if ($this->_errorsFound > 0) {
  10017. return;
  10018. }
  10019. }
  10020. if ($system_file && @file_exists($system_file)) {
  10021. $this->mergeConfigFile($system_file, false, 'system', $strict);
  10022. if ($this->_errorsFound > 0) {
  10023. return;
  10024. }
  10025. }
  10026. if (!$ftp_file) {
  10027. $ftp_file = $this->get('remote_config');
  10028. }
  10029. if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
  10030. $this->readFTPConfigFile($ftp_file);
  10031. }
  10032. foreach ($this->configuration_info as $key => $info) {
  10033. $this->configuration['default'][$key] = $info['default'];
  10034. }
  10035. $this->_registry['default'] = new PEAR_Registry(
  10036. $this->configuration['default']['php_dir'], false, false,
  10037. $this->configuration['default']['metadata_dir']);
  10038. $this->_registry['default']->setConfig($this, false);
  10039. $this->_regInitialized['default'] = false;
  10040. //$GLOBALS['_PEAR_Config_instance'] = &$this;
  10041. }
  10042. /**
  10043. * Return the default locations of user and system configuration files
  10044. */
  10045. public static function getDefaultConfigFiles()
  10046. {
  10047. $sl = DIRECTORY_SEPARATOR;
  10048. if (OS_WINDOWS) {
  10049. return array(
  10050. 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
  10051. 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
  10052. );
  10053. }
  10054. return array(
  10055. 'user' => getenv('HOME') . $sl . '.pearrc',
  10056. 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
  10057. );
  10058. }
  10059. /**
  10060. * Static singleton method. If you want to keep only one instance
  10061. * of this class in use, this method will give you a reference to
  10062. * the last created PEAR_Config object if one exists, or create a
  10063. * new object.
  10064. *
  10065. * @param string (optional) file to read user-defined options from
  10066. * @param string (optional) file to read system-wide defaults from
  10067. *
  10068. * @return object an existing or new PEAR_Config instance
  10069. *
  10070. * @see PEAR_Config::PEAR_Config
  10071. */
  10072. public static function &singleton($user_file = '', $system_file = '', $strict = true)
  10073. {
  10074. if (is_object($GLOBALS['_PEAR_Config_instance'])) {
  10075. return $GLOBALS['_PEAR_Config_instance'];
  10076. }
  10077. $t_conf = new PEAR_Config($user_file, $system_file, false, $strict);
  10078. if ($t_conf->_errorsFound > 0) {
  10079. return $t_conf->lastError;
  10080. }
  10081. $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
  10082. return $GLOBALS['_PEAR_Config_instance'];
  10083. }
  10084. /**
  10085. * Determine whether any configuration files have been detected, and whether a
  10086. * registry object can be retrieved from this configuration.
  10087. * @return bool
  10088. * @since PEAR 1.4.0a1
  10089. */
  10090. function validConfiguration()
  10091. {
  10092. if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
  10093. return true;
  10094. }
  10095. return false;
  10096. }
  10097. /**
  10098. * Reads configuration data from a file. All existing values in
  10099. * the config layer are discarded and replaced with data from the
  10100. * file.
  10101. * @param string file to read from, if NULL or not specified, the
  10102. * last-used file for the same layer (second param) is used
  10103. * @param string config layer to insert data into ('user' or 'system')
  10104. * @return bool TRUE on success or a PEAR error on failure
  10105. */
  10106. function readConfigFile($file = null, $layer = 'user', $strict = true)
  10107. {
  10108. if (empty($this->files[$layer])) {
  10109. return $this->raiseError("unknown config layer `$layer'");
  10110. }
  10111. if ($file === null) {
  10112. $file = $this->files[$layer];
  10113. }
  10114. $data = $this->_readConfigDataFrom($file);
  10115. if (PEAR::isError($data)) {
  10116. if (!$strict) {
  10117. return true;
  10118. }
  10119. $this->_errorsFound++;
  10120. $this->lastError = $data;
  10121. return $data;
  10122. }
  10123. $this->files[$layer] = $file;
  10124. $this->_decodeInput($data);
  10125. $this->configuration[$layer] = $data;
  10126. $this->_setupChannels();
  10127. if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  10128. $this->_registry[$layer] = new PEAR_Registry(
  10129. $phpdir, false, false,
  10130. $this->get('metadata_dir', $layer, 'pear.php.net'));
  10131. $this->_registry[$layer]->setConfig($this, false);
  10132. $this->_regInitialized[$layer] = false;
  10133. } else {
  10134. unset($this->_registry[$layer]);
  10135. }
  10136. return true;
  10137. }
  10138. /**
  10139. * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
  10140. * @return true|PEAR_Error
  10141. */
  10142. function readFTPConfigFile($path)
  10143. {
  10144. do { // poor man's try
  10145. if (!class_exists('PEAR_FTP')) {
  10146. if (!class_exists('PEAR_Common')) {
  10147. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  10148. }
  10149. if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
  10150. require_once 'phar://go-pear.phar/' . 'PEAR/FTP.php';
  10151. }
  10152. }
  10153. if (!class_exists('PEAR_FTP')) {
  10154. return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
  10155. }
  10156. $this->_ftp = new PEAR_FTP;
  10157. $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
  10158. $e = $this->_ftp->init($path);
  10159. if (PEAR::isError($e)) {
  10160. $this->_ftp->popErrorHandling();
  10161. return $e;
  10162. }
  10163. $tmp = System::mktemp('-d');
  10164. PEAR_Common::addTempFile($tmp);
  10165. $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
  10166. 'pear.ini', false, FTP_BINARY);
  10167. if (PEAR::isError($e)) {
  10168. $this->_ftp->popErrorHandling();
  10169. return $e;
  10170. }
  10171. PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
  10172. $this->_ftp->disconnect();
  10173. $this->_ftp->popErrorHandling();
  10174. $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
  10175. $e = $this->readConfigFile(null, 'ftp');
  10176. if (PEAR::isError($e)) {
  10177. return $e;
  10178. }
  10179. $fail = array();
  10180. foreach ($this->configuration_info as $key => $val) {
  10181. if (in_array($this->getGroup($key),
  10182. array('File Locations', 'File Locations (Advanced)')) &&
  10183. $this->getType($key) == 'directory') {
  10184. // any directory configs must be set for this to work
  10185. if (!isset($this->configuration['ftp'][$key])) {
  10186. $fail[] = $key;
  10187. }
  10188. }
  10189. }
  10190. if (!count($fail)) {
  10191. return true;
  10192. }
  10193. $fail = '"' . implode('", "', $fail) . '"';
  10194. unset($this->files['ftp']);
  10195. unset($this->configuration['ftp']);
  10196. return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
  10197. 'directory configuration variables. These variables were not set: ' .
  10198. $fail);
  10199. } while (false); // poor man's catch
  10200. unset($this->files['ftp']);
  10201. return PEAR::raiseError('no remote host specified');
  10202. }
  10203. /**
  10204. * Reads the existing configurations and creates the _channels array from it
  10205. */
  10206. function _setupChannels()
  10207. {
  10208. $set = array_flip(array_values($this->_channels));
  10209. foreach ($this->configuration as $layer => $data) {
  10210. $i = 1000;
  10211. if (isset($data['__channels']) && is_array($data['__channels'])) {
  10212. foreach ($data['__channels'] as $channel => $info) {
  10213. $set[$channel] = $i++;
  10214. }
  10215. }
  10216. }
  10217. $this->_channels = array_values(array_flip($set));
  10218. $this->setChannels($this->_channels);
  10219. }
  10220. function deleteChannel($channel)
  10221. {
  10222. $ch = strtolower($channel);
  10223. foreach ($this->configuration as $layer => $data) {
  10224. if (isset($data['__channels']) && isset($data['__channels'][$ch])) {
  10225. unset($this->configuration[$layer]['__channels'][$ch]);
  10226. }
  10227. }
  10228. $this->_channels = array_flip($this->_channels);
  10229. unset($this->_channels[$ch]);
  10230. $this->_channels = array_flip($this->_channels);
  10231. }
  10232. /**
  10233. * Merges data into a config layer from a file. Does the same
  10234. * thing as readConfigFile, except it does not replace all
  10235. * existing values in the config layer.
  10236. * @param string file to read from
  10237. * @param bool whether to overwrite existing data (default TRUE)
  10238. * @param string config layer to insert data into ('user' or 'system')
  10239. * @param string if true, errors are returned if file opening fails
  10240. * @return bool TRUE on success or a PEAR error on failure
  10241. */
  10242. function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
  10243. {
  10244. if (empty($this->files[$layer])) {
  10245. return $this->raiseError("unknown config layer `$layer'");
  10246. }
  10247. if ($file === null) {
  10248. $file = $this->files[$layer];
  10249. }
  10250. $data = $this->_readConfigDataFrom($file);
  10251. if (PEAR::isError($data)) {
  10252. if (!$strict) {
  10253. return true;
  10254. }
  10255. $this->_errorsFound++;
  10256. $this->lastError = $data;
  10257. return $data;
  10258. }
  10259. $this->_decodeInput($data);
  10260. if ($override) {
  10261. $this->configuration[$layer] =
  10262. PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
  10263. } else {
  10264. $this->configuration[$layer] =
  10265. PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
  10266. }
  10267. $this->_setupChannels();
  10268. if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  10269. $this->_registry[$layer] = new PEAR_Registry(
  10270. $phpdir, false, false,
  10271. $this->get('metadata_dir', $layer, 'pear.php.net'));
  10272. $this->_registry[$layer]->setConfig($this, false);
  10273. $this->_regInitialized[$layer] = false;
  10274. } else {
  10275. unset($this->_registry[$layer]);
  10276. }
  10277. return true;
  10278. }
  10279. /**
  10280. * @param array
  10281. * @param array
  10282. * @return array
  10283. */
  10284. public static function arrayMergeRecursive($arr2, $arr1)
  10285. {
  10286. $ret = array();
  10287. foreach ($arr2 as $key => $data) {
  10288. if (!isset($arr1[$key])) {
  10289. $ret[$key] = $data;
  10290. unset($arr1[$key]);
  10291. continue;
  10292. }
  10293. if (is_array($data)) {
  10294. if (!is_array($arr1[$key])) {
  10295. $ret[$key] = $arr1[$key];
  10296. unset($arr1[$key]);
  10297. continue;
  10298. }
  10299. $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
  10300. unset($arr1[$key]);
  10301. }
  10302. }
  10303. return array_merge($ret, $arr1);
  10304. }
  10305. /**
  10306. * Writes data into a config layer from a file.
  10307. *
  10308. * @param string|null file to read from, or null for default
  10309. * @param string config layer to insert data into ('user' or
  10310. * 'system')
  10311. * @param string|null data to write to config file or null for internal data [DEPRECATED]
  10312. * @return bool TRUE on success or a PEAR error on failure
  10313. */
  10314. function writeConfigFile($file = null, $layer = 'user', $data = null)
  10315. {
  10316. $this->_lazyChannelSetup($layer);
  10317. if ($layer == 'both' || $layer == 'all') {
  10318. foreach ($this->files as $type => $file) {
  10319. $err = $this->writeConfigFile($file, $type, $data);
  10320. if (PEAR::isError($err)) {
  10321. return $err;
  10322. }
  10323. }
  10324. return true;
  10325. }
  10326. if (empty($this->files[$layer])) {
  10327. return $this->raiseError("unknown config file type `$layer'");
  10328. }
  10329. if ($file === null) {
  10330. $file = $this->files[$layer];
  10331. }
  10332. $data = ($data === null) ? $this->configuration[$layer] : $data;
  10333. $this->_encodeOutput($data);
  10334. $opt = array('-p', dirname($file));
  10335. if (!@System::mkDir($opt)) {
  10336. return $this->raiseError("could not create directory: " . dirname($file));
  10337. }
  10338. if (file_exists($file) && is_file($file) && !is_writeable($file)) {
  10339. return $this->raiseError("no write access to $file!");
  10340. }
  10341. $fp = @fopen($file, "w");
  10342. if (!$fp) {
  10343. return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
  10344. }
  10345. $contents = "#PEAR_Config 0.9\n" . serialize($data);
  10346. if (!@fwrite($fp, $contents)) {
  10347. return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
  10348. }
  10349. return true;
  10350. }
  10351. /**
  10352. * Reads configuration data from a file and returns the parsed data
  10353. * in an array.
  10354. *
  10355. * @param string file to read from
  10356. * @return array configuration data or a PEAR error on failure
  10357. * @access private
  10358. */
  10359. function _readConfigDataFrom($file)
  10360. {
  10361. $fp = false;
  10362. if (file_exists($file)) {
  10363. $fp = @fopen($file, "r");
  10364. }
  10365. if (!$fp) {
  10366. return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
  10367. }
  10368. $size = filesize($file);
  10369. fclose($fp);
  10370. $contents = file_get_contents($file);
  10371. if (empty($contents)) {
  10372. return $this->raiseError('Configuration file "' . $file . '" is empty');
  10373. }
  10374. $version = false;
  10375. if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
  10376. $version = $matches[1];
  10377. $contents = substr($contents, strlen($matches[0]));
  10378. } else {
  10379. // Museum config file
  10380. if (substr($contents,0,2) == 'a:') {
  10381. $version = '0.1';
  10382. }
  10383. }
  10384. if ($version && version_compare("$version", '1', '<')) {
  10385. // no '@', it is possible that unserialize
  10386. // raises a notice but it seems to block IO to
  10387. // STDOUT if a '@' is used and a notice is raise
  10388. $data = unserialize($contents);
  10389. if (!is_array($data) && !$data) {
  10390. if ($contents == serialize(false)) {
  10391. $data = array();
  10392. } else {
  10393. $err = $this->raiseError("PEAR_Config: bad data in $file");
  10394. return $err;
  10395. }
  10396. }
  10397. if (!is_array($data)) {
  10398. if (strlen(trim($contents)) > 0) {
  10399. $error = "PEAR_Config: bad data in $file";
  10400. $err = $this->raiseError($error);
  10401. return $err;
  10402. }
  10403. $data = array();
  10404. }
  10405. // add parsing of newer formats here...
  10406. } else {
  10407. $err = $this->raiseError("$file: unknown version `$version'");
  10408. return $err;
  10409. }
  10410. return $data;
  10411. }
  10412. /**
  10413. * Gets the file used for storing the config for a layer
  10414. *
  10415. * @param string $layer 'user' or 'system'
  10416. */
  10417. function getConfFile($layer)
  10418. {
  10419. return $this->files[$layer];
  10420. }
  10421. /**
  10422. * @param string Configuration class name, used for detecting duplicate calls
  10423. * @param array information on a role as parsed from its xml file
  10424. * @return true|PEAR_Error
  10425. * @access private
  10426. */
  10427. function _addConfigVars($class, $vars)
  10428. {
  10429. static $called = array();
  10430. if (isset($called[$class])) {
  10431. return;
  10432. }
  10433. $called[$class] = 1;
  10434. if (count($vars) > 3) {
  10435. return $this->raiseError('Roles can only define 3 new config variables or less');
  10436. }
  10437. foreach ($vars as $name => $var) {
  10438. if (!is_array($var)) {
  10439. return $this->raiseError('Configuration information must be an array');
  10440. }
  10441. if (!isset($var['type'])) {
  10442. return $this->raiseError('Configuration information must contain a type');
  10443. } elseif (!in_array($var['type'],
  10444. array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
  10445. return $this->raiseError(
  10446. 'Configuration type must be one of directory, file, string, ' .
  10447. 'mask, set, or password');
  10448. }
  10449. if (!isset($var['default'])) {
  10450. return $this->raiseError(
  10451. 'Configuration information must contain a default value ("default" index)');
  10452. }
  10453. if (is_array($var['default'])) {
  10454. $real_default = '';
  10455. foreach ($var['default'] as $config_var => $val) {
  10456. if (strpos($config_var, 'text') === 0) {
  10457. $real_default .= $val;
  10458. } elseif (strpos($config_var, 'constant') === 0) {
  10459. if (!defined($val)) {
  10460. return $this->raiseError(
  10461. 'Unknown constant "' . $val . '" requested in ' .
  10462. 'default value for configuration variable "' .
  10463. $name . '"');
  10464. }
  10465. $real_default .= constant($val);
  10466. } elseif (isset($this->configuration_info[$config_var])) {
  10467. $real_default .=
  10468. $this->configuration_info[$config_var]['default'];
  10469. } else {
  10470. return $this->raiseError(
  10471. 'Unknown request for "' . $config_var . '" value in ' .
  10472. 'default value for configuration variable "' .
  10473. $name . '"');
  10474. }
  10475. }
  10476. $var['default'] = $real_default;
  10477. }
  10478. if ($var['type'] == 'integer') {
  10479. $var['default'] = (integer) $var['default'];
  10480. }
  10481. if (!isset($var['doc'])) {
  10482. return $this->raiseError(
  10483. 'Configuration information must contain a summary ("doc" index)');
  10484. }
  10485. if (!isset($var['prompt'])) {
  10486. return $this->raiseError(
  10487. 'Configuration information must contain a simple prompt ("prompt" index)');
  10488. }
  10489. if (!isset($var['group'])) {
  10490. return $this->raiseError(
  10491. 'Configuration information must contain a simple group ("group" index)');
  10492. }
  10493. if (isset($this->configuration_info[$name])) {
  10494. return $this->raiseError('Configuration variable "' . $name .
  10495. '" already exists');
  10496. }
  10497. $this->configuration_info[$name] = $var;
  10498. // fix bug #7351: setting custom config variable in a channel fails
  10499. $this->_channelConfigInfo[] = $name;
  10500. }
  10501. return true;
  10502. }
  10503. /**
  10504. * Encodes/scrambles configuration data before writing to files.
  10505. * Currently, 'password' values will be base64-encoded as to avoid
  10506. * that people spot cleartext passwords by accident.
  10507. *
  10508. * @param array (reference) array to encode values in
  10509. * @return bool TRUE on success
  10510. * @access private
  10511. */
  10512. function _encodeOutput(&$data)
  10513. {
  10514. foreach ($data as $key => $value) {
  10515. if ($key == '__channels') {
  10516. foreach ($data['__channels'] as $channel => $blah) {
  10517. $this->_encodeOutput($data['__channels'][$channel]);
  10518. }
  10519. }
  10520. if (!isset($this->configuration_info[$key])) {
  10521. continue;
  10522. }
  10523. $type = $this->configuration_info[$key]['type'];
  10524. switch ($type) {
  10525. // we base64-encode passwords so they are at least
  10526. // not shown in plain by accident
  10527. case 'password': {
  10528. $data[$key] = base64_encode($data[$key]);
  10529. break;
  10530. }
  10531. case 'mask': {
  10532. $data[$key] = octdec($data[$key]);
  10533. break;
  10534. }
  10535. }
  10536. }
  10537. return true;
  10538. }
  10539. /**
  10540. * Decodes/unscrambles configuration data after reading from files.
  10541. *
  10542. * @param array (reference) array to encode values in
  10543. * @return bool TRUE on success
  10544. * @access private
  10545. *
  10546. * @see PEAR_Config::_encodeOutput
  10547. */
  10548. function _decodeInput(&$data)
  10549. {
  10550. if (!is_array($data)) {
  10551. return true;
  10552. }
  10553. foreach ($data as $key => $value) {
  10554. if ($key == '__channels') {
  10555. foreach ($data['__channels'] as $channel => $blah) {
  10556. $this->_decodeInput($data['__channels'][$channel]);
  10557. }
  10558. }
  10559. if (!isset($this->configuration_info[$key])) {
  10560. continue;
  10561. }
  10562. $type = $this->configuration_info[$key]['type'];
  10563. switch ($type) {
  10564. case 'password': {
  10565. $data[$key] = base64_decode($data[$key]);
  10566. break;
  10567. }
  10568. case 'mask': {
  10569. $data[$key] = decoct($data[$key]);
  10570. break;
  10571. }
  10572. }
  10573. }
  10574. return true;
  10575. }
  10576. /**
  10577. * Retrieve the default channel.
  10578. *
  10579. * On startup, channels are not initialized, so if the default channel is not
  10580. * pear.php.net, then initialize the config.
  10581. * @param string registry layer
  10582. * @return string|false
  10583. */
  10584. function getDefaultChannel($layer = null)
  10585. {
  10586. $ret = false;
  10587. if ($layer === null) {
  10588. foreach ($this->layers as $layer) {
  10589. if (isset($this->configuration[$layer]['default_channel'])) {
  10590. $ret = $this->configuration[$layer]['default_channel'];
  10591. break;
  10592. }
  10593. }
  10594. } elseif (isset($this->configuration[$layer]['default_channel'])) {
  10595. $ret = $this->configuration[$layer]['default_channel'];
  10596. }
  10597. if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
  10598. $ret = 'pecl.php.net';
  10599. }
  10600. if ($ret) {
  10601. if ($ret != 'pear.php.net') {
  10602. $this->_lazyChannelSetup();
  10603. }
  10604. return $ret;
  10605. }
  10606. return PEAR_CONFIG_DEFAULT_CHANNEL;
  10607. }
  10608. /**
  10609. * Returns a configuration value, prioritizing layers as per the
  10610. * layers property.
  10611. *
  10612. * @param string config key
  10613. * @return mixed the config value, or NULL if not found
  10614. * @access public
  10615. */
  10616. function get($key, $layer = null, $channel = false)
  10617. {
  10618. if (!isset($this->configuration_info[$key])) {
  10619. return null;
  10620. }
  10621. if ($key == '__channels') {
  10622. return null;
  10623. }
  10624. if ($key == 'default_channel') {
  10625. return $this->getDefaultChannel($layer);
  10626. }
  10627. if (!$channel) {
  10628. $channel = $this->getDefaultChannel();
  10629. } elseif ($channel != 'pear.php.net') {
  10630. $this->_lazyChannelSetup();
  10631. }
  10632. $channel = strtolower($channel);
  10633. $test = (in_array($key, $this->_channelConfigInfo)) ?
  10634. $this->_getChannelValue($key, $layer, $channel) :
  10635. null;
  10636. if ($test !== null) {
  10637. if ($this->_installRoot) {
  10638. if (in_array($this->getGroup($key),
  10639. array('File Locations', 'File Locations (Advanced)')) &&
  10640. $this->getType($key) == 'directory') {
  10641. return $this->_prependPath($test, $this->_installRoot);
  10642. }
  10643. }
  10644. return $test;
  10645. }
  10646. if ($layer === null) {
  10647. foreach ($this->layers as $layer) {
  10648. if (isset($this->configuration[$layer][$key])) {
  10649. $test = $this->configuration[$layer][$key];
  10650. if ($this->_installRoot) {
  10651. if (in_array($this->getGroup($key),
  10652. array('File Locations', 'File Locations (Advanced)')) &&
  10653. $this->getType($key) == 'directory') {
  10654. return $this->_prependPath($test, $this->_installRoot);
  10655. }
  10656. }
  10657. if ($key == 'preferred_mirror') {
  10658. $reg = &$this->getRegistry();
  10659. if (is_object($reg)) {
  10660. $chan = $reg->getChannel($channel);
  10661. if (PEAR::isError($chan)) {
  10662. return $channel;
  10663. }
  10664. if (!$chan->getMirror($test) && $chan->getName() != $test) {
  10665. return $channel; // mirror does not exist
  10666. }
  10667. }
  10668. }
  10669. return $test;
  10670. }
  10671. }
  10672. } elseif (isset($this->configuration[$layer][$key])) {
  10673. $test = $this->configuration[$layer][$key];
  10674. if ($this->_installRoot) {
  10675. if (in_array($this->getGroup($key),
  10676. array('File Locations', 'File Locations (Advanced)')) &&
  10677. $this->getType($key) == 'directory') {
  10678. return $this->_prependPath($test, $this->_installRoot);
  10679. }
  10680. }
  10681. if ($key == 'preferred_mirror') {
  10682. $reg = &$this->getRegistry();
  10683. if (is_object($reg)) {
  10684. $chan = $reg->getChannel($channel);
  10685. if (PEAR::isError($chan)) {
  10686. return $channel;
  10687. }
  10688. if (!$chan->getMirror($test) && $chan->getName() != $test) {
  10689. return $channel; // mirror does not exist
  10690. }
  10691. }
  10692. }
  10693. return $test;
  10694. }
  10695. return null;
  10696. }
  10697. /**
  10698. * Returns a channel-specific configuration value, prioritizing layers as per the
  10699. * layers property.
  10700. *
  10701. * @param string config key
  10702. * @return mixed the config value, or NULL if not found
  10703. * @access private
  10704. */
  10705. function _getChannelValue($key, $layer, $channel)
  10706. {
  10707. if ($key == '__channels' || $channel == 'pear.php.net') {
  10708. return null;
  10709. }
  10710. $ret = null;
  10711. if ($layer === null) {
  10712. foreach ($this->layers as $ilayer) {
  10713. if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
  10714. $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
  10715. break;
  10716. }
  10717. }
  10718. } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  10719. $ret = $this->configuration[$layer]['__channels'][$channel][$key];
  10720. }
  10721. if ($key != 'preferred_mirror') {
  10722. return $ret;
  10723. }
  10724. if ($ret !== null) {
  10725. $reg = &$this->getRegistry($layer);
  10726. if (is_object($reg)) {
  10727. $chan = $reg->getChannel($channel);
  10728. if (PEAR::isError($chan)) {
  10729. return $channel;
  10730. }
  10731. if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
  10732. return $channel; // mirror does not exist
  10733. }
  10734. }
  10735. return $ret;
  10736. }
  10737. if ($channel != $this->getDefaultChannel($layer)) {
  10738. return $channel; // we must use the channel name as the preferred mirror
  10739. // if the user has not chosen an alternate
  10740. }
  10741. return $this->getDefaultChannel($layer);
  10742. }
  10743. /**
  10744. * Set a config value in a specific layer (defaults to 'user').
  10745. * Enforces the types defined in the configuration_info array. An
  10746. * integer config variable will be cast to int, and a set config
  10747. * variable will be validated against its legal values.
  10748. *
  10749. * @param string config key
  10750. * @param string config value
  10751. * @param string (optional) config layer
  10752. * @param string channel to set this value for, or null for global value
  10753. * @return bool TRUE on success, FALSE on failure
  10754. */
  10755. function set($key, $value, $layer = 'user', $channel = false)
  10756. {
  10757. if ($key == '__channels') {
  10758. return false;
  10759. }
  10760. if (!isset($this->configuration[$layer])) {
  10761. return false;
  10762. }
  10763. if ($key == 'default_channel') {
  10764. // can only set this value globally
  10765. $channel = 'pear.php.net';
  10766. if ($value != 'pear.php.net') {
  10767. $this->_lazyChannelSetup($layer);
  10768. }
  10769. }
  10770. if ($key == 'preferred_mirror') {
  10771. if ($channel == '__uri') {
  10772. return false; // can't set the __uri pseudo-channel's mirror
  10773. }
  10774. $reg = &$this->getRegistry($layer);
  10775. if (is_object($reg)) {
  10776. $chan = $reg->getChannel($channel ? $channel : 'pear.php.net');
  10777. if (PEAR::isError($chan)) {
  10778. return false;
  10779. }
  10780. if (!$chan->getMirror($value) && $chan->getName() != $value) {
  10781. return false; // mirror does not exist
  10782. }
  10783. }
  10784. }
  10785. if (!isset($this->configuration_info[$key])) {
  10786. return false;
  10787. }
  10788. extract($this->configuration_info[$key]);
  10789. switch ($type) {
  10790. case 'integer':
  10791. $value = (int)$value;
  10792. break;
  10793. case 'set': {
  10794. // If a valid_set is specified, require the value to
  10795. // be in the set. If there is no valid_set, accept
  10796. // any value.
  10797. if ($valid_set) {
  10798. reset($valid_set);
  10799. if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
  10800. (key($valid_set) !== 0 && empty($valid_set[$value])))
  10801. {
  10802. return false;
  10803. }
  10804. }
  10805. break;
  10806. }
  10807. }
  10808. if (!$channel) {
  10809. $channel = $this->get('default_channel', null, 'pear.php.net');
  10810. }
  10811. if (!in_array($channel, $this->_channels)) {
  10812. $this->_lazyChannelSetup($layer);
  10813. $reg = &$this->getRegistry($layer);
  10814. if ($reg) {
  10815. $channel = $reg->channelName($channel);
  10816. }
  10817. if (!in_array($channel, $this->_channels)) {
  10818. return false;
  10819. }
  10820. }
  10821. if ($channel != 'pear.php.net') {
  10822. if (in_array($key, $this->_channelConfigInfo)) {
  10823. $this->configuration[$layer]['__channels'][$channel][$key] = $value;
  10824. return true;
  10825. }
  10826. return false;
  10827. }
  10828. if ($key == 'default_channel') {
  10829. if (!isset($reg)) {
  10830. $reg = &$this->getRegistry($layer);
  10831. if (!$reg) {
  10832. $reg = &$this->getRegistry();
  10833. }
  10834. }
  10835. if ($reg) {
  10836. $value = $reg->channelName($value);
  10837. }
  10838. if (!$value) {
  10839. return false;
  10840. }
  10841. }
  10842. $this->configuration[$layer][$key] = $value;
  10843. if ($key == 'php_dir' && !$this->_noRegistry) {
  10844. if (!isset($this->_registry[$layer]) ||
  10845. $value != $this->_registry[$layer]->install_dir) {
  10846. $this->_registry[$layer] = new PEAR_Registry($value);
  10847. $this->_regInitialized[$layer] = false;
  10848. $this->_registry[$layer]->setConfig($this, false);
  10849. }
  10850. }
  10851. return true;
  10852. }
  10853. function _lazyChannelSetup($uselayer = false)
  10854. {
  10855. if ($this->_noRegistry) {
  10856. return;
  10857. }
  10858. $merge = false;
  10859. foreach ($this->_registry as $layer => $p) {
  10860. if ($uselayer && $uselayer != $layer) {
  10861. continue;
  10862. }
  10863. if (!$this->_regInitialized[$layer]) {
  10864. if ($layer == 'default' && isset($this->_registry['user']) ||
  10865. isset($this->_registry['system'])) {
  10866. // only use the default registry if there are no alternatives
  10867. continue;
  10868. }
  10869. if (!is_object($this->_registry[$layer])) {
  10870. if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
  10871. $this->_registry[$layer] = new PEAR_Registry(
  10872. $phpdir, false, false,
  10873. $this->get('metadata_dir', $layer, 'pear.php.net'));
  10874. $this->_registry[$layer]->setConfig($this, false);
  10875. $this->_regInitialized[$layer] = false;
  10876. } else {
  10877. unset($this->_registry[$layer]);
  10878. return;
  10879. }
  10880. }
  10881. $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
  10882. $this->_regInitialized[$layer] = true;
  10883. $merge = true;
  10884. }
  10885. }
  10886. }
  10887. /**
  10888. * Set the list of channels.
  10889. *
  10890. * This should be set via a call to {@link PEAR_Registry::listChannels()}
  10891. * @param array
  10892. * @param bool
  10893. * @return bool success of operation
  10894. */
  10895. function setChannels($channels, $merge = false)
  10896. {
  10897. if (!is_array($channels)) {
  10898. return false;
  10899. }
  10900. if ($merge) {
  10901. $this->_channels = array_merge($this->_channels, $channels);
  10902. } else {
  10903. $this->_channels = $channels;
  10904. }
  10905. foreach ($channels as $channel) {
  10906. $channel = strtolower($channel);
  10907. if ($channel == 'pear.php.net') {
  10908. continue;
  10909. }
  10910. foreach ($this->layers as $layer) {
  10911. if (!isset($this->configuration[$layer]['__channels'])) {
  10912. $this->configuration[$layer]['__channels'] = array();
  10913. }
  10914. if (!isset($this->configuration[$layer]['__channels'][$channel])
  10915. || !is_array($this->configuration[$layer]['__channels'][$channel])) {
  10916. $this->configuration[$layer]['__channels'][$channel] = array();
  10917. }
  10918. }
  10919. }
  10920. return true;
  10921. }
  10922. /**
  10923. * Get the type of a config value.
  10924. *
  10925. * @param string config key
  10926. *
  10927. * @return string type, one of "string", "integer", "file",
  10928. * "directory", "set" or "password".
  10929. *
  10930. * @access public
  10931. *
  10932. */
  10933. function getType($key)
  10934. {
  10935. if (isset($this->configuration_info[$key])) {
  10936. return $this->configuration_info[$key]['type'];
  10937. }
  10938. return false;
  10939. }
  10940. /**
  10941. * Get the documentation for a config value.
  10942. *
  10943. * @param string config key
  10944. * @return string documentation string
  10945. *
  10946. * @access public
  10947. *
  10948. */
  10949. function getDocs($key)
  10950. {
  10951. if (isset($this->configuration_info[$key])) {
  10952. return $this->configuration_info[$key]['doc'];
  10953. }
  10954. return false;
  10955. }
  10956. /**
  10957. * Get the short documentation for a config value.
  10958. *
  10959. * @param string config key
  10960. * @return string short documentation string
  10961. *
  10962. * @access public
  10963. *
  10964. */
  10965. function getPrompt($key)
  10966. {
  10967. if (isset($this->configuration_info[$key])) {
  10968. return $this->configuration_info[$key]['prompt'];
  10969. }
  10970. return false;
  10971. }
  10972. /**
  10973. * Get the parameter group for a config key.
  10974. *
  10975. * @param string config key
  10976. * @return string parameter group
  10977. *
  10978. * @access public
  10979. *
  10980. */
  10981. function getGroup($key)
  10982. {
  10983. if (isset($this->configuration_info[$key])) {
  10984. return $this->configuration_info[$key]['group'];
  10985. }
  10986. return false;
  10987. }
  10988. /**
  10989. * Get the list of parameter groups.
  10990. *
  10991. * @return array list of parameter groups
  10992. *
  10993. * @access public
  10994. *
  10995. */
  10996. function getGroups()
  10997. {
  10998. $tmp = array();
  10999. foreach ($this->configuration_info as $key => $info) {
  11000. $tmp[$info['group']] = 1;
  11001. }
  11002. return array_keys($tmp);
  11003. }
  11004. /**
  11005. * Get the list of the parameters in a group.
  11006. *
  11007. * @param string $group parameter group
  11008. * @return array list of parameters in $group
  11009. *
  11010. * @access public
  11011. *
  11012. */
  11013. function getGroupKeys($group)
  11014. {
  11015. $keys = array();
  11016. foreach ($this->configuration_info as $key => $info) {
  11017. if ($info['group'] == $group) {
  11018. $keys[] = $key;
  11019. }
  11020. }
  11021. return $keys;
  11022. }
  11023. /**
  11024. * Get the list of allowed set values for a config value. Returns
  11025. * NULL for config values that are not sets.
  11026. *
  11027. * @param string config key
  11028. * @return array enumerated array of set values, or NULL if the
  11029. * config key is unknown or not a set
  11030. *
  11031. * @access public
  11032. *
  11033. */
  11034. function getSetValues($key)
  11035. {
  11036. if (isset($this->configuration_info[$key]) &&
  11037. isset($this->configuration_info[$key]['type']) &&
  11038. $this->configuration_info[$key]['type'] == 'set')
  11039. {
  11040. $valid_set = $this->configuration_info[$key]['valid_set'];
  11041. reset($valid_set);
  11042. if (key($valid_set) === 0) {
  11043. return $valid_set;
  11044. }
  11045. return array_keys($valid_set);
  11046. }
  11047. return null;
  11048. }
  11049. /**
  11050. * Get all the current config keys.
  11051. *
  11052. * @return array simple array of config keys
  11053. *
  11054. * @access public
  11055. */
  11056. function getKeys()
  11057. {
  11058. $keys = array();
  11059. foreach ($this->layers as $layer) {
  11060. $test = $this->configuration[$layer];
  11061. if (isset($test['__channels'])) {
  11062. foreach ($test['__channels'] as $channel => $configs) {
  11063. $keys = array_merge($keys, $configs);
  11064. }
  11065. }
  11066. unset($test['__channels']);
  11067. $keys = array_merge($keys, $test);
  11068. }
  11069. return array_keys($keys);
  11070. }
  11071. /**
  11072. * Remove the a config key from a specific config layer.
  11073. *
  11074. * @param string config key
  11075. * @param string (optional) config layer
  11076. * @param string (optional) channel (defaults to default channel)
  11077. * @return bool TRUE on success, FALSE on failure
  11078. *
  11079. * @access public
  11080. */
  11081. function remove($key, $layer = 'user', $channel = null)
  11082. {
  11083. if ($channel === null) {
  11084. $channel = $this->getDefaultChannel();
  11085. }
  11086. if ($channel !== 'pear.php.net') {
  11087. if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  11088. unset($this->configuration[$layer]['__channels'][$channel][$key]);
  11089. return true;
  11090. }
  11091. }
  11092. if (isset($this->configuration[$layer][$key])) {
  11093. unset($this->configuration[$layer][$key]);
  11094. return true;
  11095. }
  11096. return false;
  11097. }
  11098. /**
  11099. * Temporarily remove an entire config layer. USE WITH CARE!
  11100. *
  11101. * @param string config key
  11102. * @param string (optional) config layer
  11103. * @return bool TRUE on success, FALSE on failure
  11104. *
  11105. * @access public
  11106. */
  11107. function removeLayer($layer)
  11108. {
  11109. if (isset($this->configuration[$layer])) {
  11110. $this->configuration[$layer] = array();
  11111. return true;
  11112. }
  11113. return false;
  11114. }
  11115. /**
  11116. * Stores configuration data in a layer.
  11117. *
  11118. * @param string config layer to store
  11119. * @return bool TRUE on success, or PEAR error on failure
  11120. *
  11121. * @access public
  11122. */
  11123. function store($layer = 'user', $data = null)
  11124. {
  11125. return $this->writeConfigFile(null, $layer, $data);
  11126. }
  11127. /**
  11128. * Tells what config layer that gets to define a key.
  11129. *
  11130. * @param string config key
  11131. * @param boolean return the defining channel
  11132. *
  11133. * @return string|array the config layer, or an empty string if not found.
  11134. *
  11135. * if $returnchannel, the return is an array array('layer' => layername,
  11136. * 'channel' => channelname), or an empty string if not found
  11137. *
  11138. * @access public
  11139. */
  11140. function definedBy($key, $returnchannel = false)
  11141. {
  11142. foreach ($this->layers as $layer) {
  11143. $channel = $this->getDefaultChannel();
  11144. if ($channel !== 'pear.php.net') {
  11145. if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  11146. if ($returnchannel) {
  11147. return array('layer' => $layer, 'channel' => $channel);
  11148. }
  11149. return $layer;
  11150. }
  11151. }
  11152. if (isset($this->configuration[$layer][$key])) {
  11153. if ($returnchannel) {
  11154. return array('layer' => $layer, 'channel' => 'pear.php.net');
  11155. }
  11156. return $layer;
  11157. }
  11158. }
  11159. return '';
  11160. }
  11161. /**
  11162. * Tells whether a given key exists as a config value.
  11163. *
  11164. * @param string config key
  11165. * @return bool whether <config key> exists in this object
  11166. *
  11167. * @access public
  11168. */
  11169. function isDefined($key)
  11170. {
  11171. foreach ($this->layers as $layer) {
  11172. if (isset($this->configuration[$layer][$key])) {
  11173. return true;
  11174. }
  11175. }
  11176. return false;
  11177. }
  11178. /**
  11179. * Tells whether a given config layer exists.
  11180. *
  11181. * @param string config layer
  11182. * @return bool whether <config layer> exists in this object
  11183. *
  11184. * @access public
  11185. */
  11186. function isDefinedLayer($layer)
  11187. {
  11188. return isset($this->configuration[$layer]);
  11189. }
  11190. /**
  11191. * Returns the layers defined (except the 'default' one)
  11192. *
  11193. * @return array of the defined layers
  11194. */
  11195. function getLayers()
  11196. {
  11197. $cf = $this->configuration;
  11198. unset($cf['default']);
  11199. return array_keys($cf);
  11200. }
  11201. function apiVersion()
  11202. {
  11203. return '1.1';
  11204. }
  11205. /**
  11206. * @return PEAR_Registry
  11207. */
  11208. function &getRegistry($use = null)
  11209. {
  11210. $layer = $use === null ? 'user' : $use;
  11211. if (isset($this->_registry[$layer])) {
  11212. return $this->_registry[$layer];
  11213. } elseif ($use === null && isset($this->_registry['system'])) {
  11214. return $this->_registry['system'];
  11215. } elseif ($use === null && isset($this->_registry['default'])) {
  11216. return $this->_registry['default'];
  11217. } elseif ($use) {
  11218. $a = false;
  11219. return $a;
  11220. }
  11221. // only go here if null was passed in
  11222. echo "CRITICAL ERROR: Registry could not be initialized from any value";
  11223. exit(1);
  11224. }
  11225. /**
  11226. * This is to allow customization like the use of installroot
  11227. * @param PEAR_Registry
  11228. * @return bool
  11229. */
  11230. function setRegistry(&$reg, $layer = 'user')
  11231. {
  11232. if ($this->_noRegistry) {
  11233. return false;
  11234. }
  11235. if (!in_array($layer, array('user', 'system'))) {
  11236. return false;
  11237. }
  11238. $this->_registry[$layer] = &$reg;
  11239. if (is_object($reg)) {
  11240. $this->_registry[$layer]->setConfig($this, false);
  11241. }
  11242. return true;
  11243. }
  11244. function noRegistry()
  11245. {
  11246. $this->_noRegistry = true;
  11247. }
  11248. /**
  11249. * @return PEAR_REST
  11250. */
  11251. function &getREST($version, $options = array())
  11252. {
  11253. $version = str_replace('.', '', $version);
  11254. if (!class_exists($class = 'PEAR_REST_' . $version)) {
  11255. require_once 'phar://go-pear.phar/' . 'PEAR/REST/' . $version . '.php';
  11256. }
  11257. $remote = new $class($this, $options);
  11258. return $remote;
  11259. }
  11260. /**
  11261. * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a
  11262. * remote configuration file has been specified
  11263. * @return PEAR_FTP|false
  11264. */
  11265. function &getFTP()
  11266. {
  11267. if (isset($this->_ftp)) {
  11268. return $this->_ftp;
  11269. }
  11270. $a = false;
  11271. return $a;
  11272. }
  11273. static function _prependPath($path, $prepend)
  11274. {
  11275. if (strlen($prepend) > 0) {
  11276. if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  11277. if (preg_match('/^[a-z]:/i', $prepend)) {
  11278. $prepend = substr($prepend, 2);
  11279. } elseif ($prepend[0] != '\\') {
  11280. $prepend = "\\$prepend";
  11281. }
  11282. $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  11283. } else {
  11284. $path = $prepend . $path;
  11285. }
  11286. }
  11287. return $path;
  11288. }
  11289. /**
  11290. * @param string|false installation directory to prepend to all _dir variables, or false to
  11291. * disable
  11292. */
  11293. function setInstallRoot($root)
  11294. {
  11295. if (substr($root, -1) == DIRECTORY_SEPARATOR) {
  11296. $root = substr($root, 0, -1);
  11297. }
  11298. $old = $this->_installRoot;
  11299. $this->_installRoot = $root;
  11300. if (($old != $root) && !$this->_noRegistry) {
  11301. foreach (array_keys($this->_registry) as $layer) {
  11302. if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
  11303. continue;
  11304. }
  11305. $this->_registry[$layer] =
  11306. new PEAR_Registry(
  11307. $this->get('php_dir', $layer, 'pear.php.net'), false, false,
  11308. $this->get('metadata_dir', $layer, 'pear.php.net'));
  11309. $this->_registry[$layer]->setConfig($this, false);
  11310. $this->_regInitialized[$layer] = false;
  11311. }
  11312. }
  11313. }
  11314. }
  11315. <?php
  11316. /**
  11317. * PEAR_Dependency2, advanced dependency validation
  11318. *
  11319. * PHP versions 4 and 5
  11320. *
  11321. * @category pear
  11322. * @package PEAR
  11323. * @author Greg Beaver <cellog@php.net>
  11324. * @copyright 1997-2009 The Authors
  11325. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  11326. * @link http://pear.php.net/package/PEAR
  11327. * @since File available since Release 1.4.0a1
  11328. */
  11329. /**
  11330. * Required for the PEAR_VALIDATE_* constants
  11331. */
  11332. require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  11333. /**
  11334. * Dependency check for PEAR packages
  11335. *
  11336. * This class handles both version 1.0 and 2.0 dependencies
  11337. * WARNING: *any* changes to this class must be duplicated in the
  11338. * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
  11339. * or unit tests will not actually validate the changes
  11340. * @category pear
  11341. * @package PEAR
  11342. * @author Greg Beaver <cellog@php.net>
  11343. * @copyright 1997-2009 The Authors
  11344. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  11345. * @version Release: 1.10.10
  11346. * @link http://pear.php.net/package/PEAR
  11347. * @since Class available since Release 1.4.0a1
  11348. */
  11349. class PEAR_Dependency2
  11350. {
  11351. /**
  11352. * One of the PEAR_VALIDATE_* states
  11353. * @see PEAR_VALIDATE_NORMAL
  11354. * @var integer
  11355. */
  11356. var $_state;
  11357. /**
  11358. * Command-line options to install/upgrade/uninstall commands
  11359. * @param array
  11360. */
  11361. var $_options;
  11362. /**
  11363. * @var OS_Guess
  11364. */
  11365. var $_os;
  11366. /**
  11367. * @var PEAR_Registry
  11368. */
  11369. var $_registry;
  11370. /**
  11371. * @var PEAR_Config
  11372. */
  11373. var $_config;
  11374. /**
  11375. * @var PEAR_DependencyDB
  11376. */
  11377. var $_dependencydb;
  11378. /**
  11379. * Output of PEAR_Registry::parsedPackageName()
  11380. * @var array
  11381. */
  11382. var $_currentPackage;
  11383. /**
  11384. * @param PEAR_Config
  11385. * @param array installation options
  11386. * @param array format of PEAR_Registry::parsedPackageName()
  11387. * @param int installation state (one of PEAR_VALIDATE_*)
  11388. */
  11389. function __construct(&$config, $installoptions, $package,
  11390. $state = PEAR_VALIDATE_INSTALLING)
  11391. {
  11392. $this->_config = &$config;
  11393. if (!class_exists('PEAR_DependencyDB')) {
  11394. require_once 'phar://go-pear.phar/' . 'PEAR/DependencyDB.php';
  11395. }
  11396. if (isset($installoptions['packagingroot'])) {
  11397. // make sure depdb is in the right location
  11398. $config->setInstallRoot($installoptions['packagingroot']);
  11399. }
  11400. $this->_registry = &$config->getRegistry();
  11401. $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
  11402. if (isset($installoptions['packagingroot'])) {
  11403. $config->setInstallRoot(false);
  11404. }
  11405. $this->_options = $installoptions;
  11406. $this->_state = $state;
  11407. if (!class_exists('OS_Guess')) {
  11408. require_once 'phar://go-pear.phar/' . 'OS/Guess.php';
  11409. }
  11410. $this->_os = new OS_Guess;
  11411. $this->_currentPackage = $package;
  11412. }
  11413. static function _getExtraString($dep)
  11414. {
  11415. $extra = ' (';
  11416. if (isset($dep['uri'])) {
  11417. return '';
  11418. }
  11419. if (isset($dep['recommended'])) {
  11420. $extra .= 'recommended version ' . $dep['recommended'];
  11421. } else {
  11422. if (isset($dep['min'])) {
  11423. $extra .= 'version >= ' . $dep['min'];
  11424. }
  11425. if (isset($dep['max'])) {
  11426. if ($extra != ' (') {
  11427. $extra .= ', ';
  11428. }
  11429. $extra .= 'version <= ' . $dep['max'];
  11430. }
  11431. if (isset($dep['exclude'])) {
  11432. if (!is_array($dep['exclude'])) {
  11433. $dep['exclude'] = array($dep['exclude']);
  11434. }
  11435. if ($extra != ' (') {
  11436. $extra .= ', ';
  11437. }
  11438. $extra .= 'excluded versions: ';
  11439. foreach ($dep['exclude'] as $i => $exclude) {
  11440. if ($i) {
  11441. $extra .= ', ';
  11442. }
  11443. $extra .= $exclude;
  11444. }
  11445. }
  11446. }
  11447. $extra .= ')';
  11448. if ($extra == ' ()') {
  11449. $extra = '';
  11450. }
  11451. return $extra;
  11452. }
  11453. /**
  11454. * This makes unit-testing a heck of a lot easier
  11455. */
  11456. function getPHP_OS()
  11457. {
  11458. return PHP_OS;
  11459. }
  11460. /**
  11461. * This makes unit-testing a heck of a lot easier
  11462. */
  11463. function getsysname()
  11464. {
  11465. return $this->_os->getSysname();
  11466. }
  11467. /**
  11468. * Specify a dependency on an OS. Use arch for detailed os/processor information
  11469. *
  11470. * There are two generic OS dependencies that will be the most common, unix and windows.
  11471. * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
  11472. */
  11473. function validateOsDependency($dep)
  11474. {
  11475. if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11476. return true;
  11477. }
  11478. if ($dep['name'] == '*') {
  11479. return true;
  11480. }
  11481. $not = isset($dep['conflicts']) ? true : false;
  11482. switch (strtolower($dep['name'])) {
  11483. case 'windows' :
  11484. if ($not) {
  11485. if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
  11486. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11487. return $this->raiseError("Cannot install %s on Windows");
  11488. }
  11489. return $this->warning("warning: Cannot install %s on Windows");
  11490. }
  11491. } else {
  11492. if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
  11493. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11494. return $this->raiseError("Can only install %s on Windows");
  11495. }
  11496. return $this->warning("warning: Can only install %s on Windows");
  11497. }
  11498. }
  11499. break;
  11500. case 'unix' :
  11501. $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
  11502. if ($not) {
  11503. if (in_array($this->getSysname(), $unices)) {
  11504. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11505. return $this->raiseError("Cannot install %s on any Unix system");
  11506. }
  11507. return $this->warning( "warning: Cannot install %s on any Unix system");
  11508. }
  11509. } else {
  11510. if (!in_array($this->getSysname(), $unices)) {
  11511. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11512. return $this->raiseError("Can only install %s on a Unix system");
  11513. }
  11514. return $this->warning("warning: Can only install %s on a Unix system");
  11515. }
  11516. }
  11517. break;
  11518. default :
  11519. if ($not) {
  11520. if (strtolower($dep['name']) == strtolower($this->getSysname())) {
  11521. if (!isset($this->_options['nodeps']) &&
  11522. !isset($this->_options['force'])) {
  11523. return $this->raiseError('Cannot install %s on ' . $dep['name'] .
  11524. ' operating system');
  11525. }
  11526. return $this->warning('warning: Cannot install %s on ' .
  11527. $dep['name'] . ' operating system');
  11528. }
  11529. } else {
  11530. if (strtolower($dep['name']) != strtolower($this->getSysname())) {
  11531. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11532. return $this->raiseError('Cannot install %s on ' .
  11533. $this->getSysname() .
  11534. ' operating system, can only install on ' . $dep['name']);
  11535. }
  11536. return $this->warning('warning: Cannot install %s on ' .
  11537. $this->getSysname() .
  11538. ' operating system, can only install on ' . $dep['name']);
  11539. }
  11540. }
  11541. }
  11542. return true;
  11543. }
  11544. /**
  11545. * This makes unit-testing a heck of a lot easier
  11546. */
  11547. function matchSignature($pattern)
  11548. {
  11549. return $this->_os->matchSignature($pattern);
  11550. }
  11551. /**
  11552. * Specify a complex dependency on an OS/processor/kernel version,
  11553. * Use OS for simple operating system dependency.
  11554. *
  11555. * This is the only dependency that accepts an eregable pattern. The pattern
  11556. * will be matched against the php_uname() output parsed by OS_Guess
  11557. */
  11558. function validateArchDependency($dep)
  11559. {
  11560. if ($this->_state != PEAR_VALIDATE_INSTALLING) {
  11561. return true;
  11562. }
  11563. $not = isset($dep['conflicts']) ? true : false;
  11564. if (!$this->matchSignature($dep['pattern'])) {
  11565. if (!$not) {
  11566. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11567. return $this->raiseError('%s Architecture dependency failed, does not ' .
  11568. 'match "' . $dep['pattern'] . '"');
  11569. }
  11570. return $this->warning('warning: %s Architecture dependency failed, does ' .
  11571. 'not match "' . $dep['pattern'] . '"');
  11572. }
  11573. return true;
  11574. }
  11575. if ($not) {
  11576. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11577. return $this->raiseError('%s Architecture dependency failed, required "' .
  11578. $dep['pattern'] . '"');
  11579. }
  11580. return $this->warning('warning: %s Architecture dependency failed, ' .
  11581. 'required "' . $dep['pattern'] . '"');
  11582. }
  11583. return true;
  11584. }
  11585. /**
  11586. * This makes unit-testing a heck of a lot easier
  11587. */
  11588. function extension_loaded($name)
  11589. {
  11590. return extension_loaded($name);
  11591. }
  11592. /**
  11593. * This makes unit-testing a heck of a lot easier
  11594. */
  11595. function phpversion($name = null)
  11596. {
  11597. if ($name !== null) {
  11598. return phpversion($name);
  11599. }
  11600. return phpversion();
  11601. }
  11602. function validateExtensionDependency($dep, $required = true)
  11603. {
  11604. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11605. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11606. return true;
  11607. }
  11608. $loaded = $this->extension_loaded($dep['name']);
  11609. $extra = self::_getExtraString($dep);
  11610. if (isset($dep['exclude'])) {
  11611. if (!is_array($dep['exclude'])) {
  11612. $dep['exclude'] = array($dep['exclude']);
  11613. }
  11614. }
  11615. if (!isset($dep['min']) && !isset($dep['max']) &&
  11616. !isset($dep['recommended']) && !isset($dep['exclude'])
  11617. ) {
  11618. if ($loaded) {
  11619. if (isset($dep['conflicts'])) {
  11620. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11621. return $this->raiseError('%s conflicts with PHP extension "' .
  11622. $dep['name'] . '"' . $extra);
  11623. }
  11624. return $this->warning('warning: %s conflicts with PHP extension "' .
  11625. $dep['name'] . '"' . $extra);
  11626. }
  11627. return true;
  11628. }
  11629. if (isset($dep['conflicts'])) {
  11630. return true;
  11631. }
  11632. if ($required) {
  11633. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11634. return $this->raiseError('%s requires PHP extension "' .
  11635. $dep['name'] . '"' . $extra);
  11636. }
  11637. return $this->warning('warning: %s requires PHP extension "' .
  11638. $dep['name'] . '"' . $extra);
  11639. }
  11640. return $this->warning('%s can optionally use PHP extension "' .
  11641. $dep['name'] . '"' . $extra);
  11642. }
  11643. if (!$loaded) {
  11644. if (isset($dep['conflicts'])) {
  11645. return true;
  11646. }
  11647. if (!$required) {
  11648. return $this->warning('%s can optionally use PHP extension "' .
  11649. $dep['name'] . '"' . $extra);
  11650. }
  11651. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11652. return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  11653. '"' . $extra);
  11654. }
  11655. return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  11656. '"' . $extra);
  11657. }
  11658. $version = (string) $this->phpversion($dep['name']);
  11659. if (empty($version)) {
  11660. $version = '0';
  11661. }
  11662. $fail = false;
  11663. if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) {
  11664. $fail = true;
  11665. }
  11666. if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) {
  11667. $fail = true;
  11668. }
  11669. if ($fail && !isset($dep['conflicts'])) {
  11670. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11671. return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  11672. '"' . $extra . ', installed version is ' . $version);
  11673. }
  11674. return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  11675. '"' . $extra . ', installed version is ' . $version);
  11676. } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
  11677. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11678. return $this->raiseError('%s conflicts with PHP extension "' .
  11679. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11680. }
  11681. return $this->warning('warning: %s conflicts with PHP extension "' .
  11682. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11683. }
  11684. if (isset($dep['exclude'])) {
  11685. foreach ($dep['exclude'] as $exclude) {
  11686. if (version_compare($version, $exclude, '==')) {
  11687. if (isset($dep['conflicts'])) {
  11688. continue;
  11689. }
  11690. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11691. return $this->raiseError('%s is not compatible with PHP extension "' .
  11692. $dep['name'] . '" version ' .
  11693. $exclude);
  11694. }
  11695. return $this->warning('warning: %s is not compatible with PHP extension "' .
  11696. $dep['name'] . '" version ' .
  11697. $exclude);
  11698. } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  11699. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11700. return $this->raiseError('%s conflicts with PHP extension "' .
  11701. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11702. }
  11703. return $this->warning('warning: %s conflicts with PHP extension "' .
  11704. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11705. }
  11706. }
  11707. }
  11708. if (isset($dep['recommended'])) {
  11709. if (version_compare($version, $dep['recommended'], '==')) {
  11710. return true;
  11711. }
  11712. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11713. return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
  11714. ' version "' . $version . '"' .
  11715. ' is not the recommended version "' . $dep['recommended'] .
  11716. '", but may be compatible, use --force to install');
  11717. }
  11718. return $this->warning('warning: %s dependency: PHP extension ' .
  11719. $dep['name'] . ' version "' . $version . '"' .
  11720. ' is not the recommended version "' . $dep['recommended'].'"');
  11721. }
  11722. return true;
  11723. }
  11724. function validatePhpDependency($dep)
  11725. {
  11726. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11727. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11728. return true;
  11729. }
  11730. $version = $this->phpversion();
  11731. $extra = self::_getExtraString($dep);
  11732. if (isset($dep['exclude'])) {
  11733. if (!is_array($dep['exclude'])) {
  11734. $dep['exclude'] = array($dep['exclude']);
  11735. }
  11736. }
  11737. if (isset($dep['min'])) {
  11738. if (!version_compare($version, $dep['min'], '>=')) {
  11739. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11740. return $this->raiseError('%s requires PHP' .
  11741. $extra . ', installed version is ' . $version);
  11742. }
  11743. return $this->warning('warning: %s requires PHP' .
  11744. $extra . ', installed version is ' . $version);
  11745. }
  11746. }
  11747. if (isset($dep['max'])) {
  11748. if (!version_compare($version, $dep['max'], '<=')) {
  11749. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11750. return $this->raiseError('%s requires PHP' .
  11751. $extra . ', installed version is ' . $version);
  11752. }
  11753. return $this->warning('warning: %s requires PHP' .
  11754. $extra . ', installed version is ' . $version);
  11755. }
  11756. }
  11757. if (isset($dep['exclude'])) {
  11758. foreach ($dep['exclude'] as $exclude) {
  11759. if (version_compare($version, $exclude, '==')) {
  11760. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11761. return $this->raiseError('%s is not compatible with PHP version ' .
  11762. $exclude);
  11763. }
  11764. return $this->warning(
  11765. 'warning: %s is not compatible with PHP version ' .
  11766. $exclude);
  11767. }
  11768. }
  11769. }
  11770. return true;
  11771. }
  11772. /**
  11773. * This makes unit-testing a heck of a lot easier
  11774. */
  11775. function getPEARVersion()
  11776. {
  11777. return '1.10.10';
  11778. }
  11779. function validatePearinstallerDependency($dep)
  11780. {
  11781. $pearversion = $this->getPEARVersion();
  11782. $extra = self::_getExtraString($dep);
  11783. if (isset($dep['exclude'])) {
  11784. if (!is_array($dep['exclude'])) {
  11785. $dep['exclude'] = array($dep['exclude']);
  11786. }
  11787. }
  11788. if (version_compare($pearversion, $dep['min'], '<')) {
  11789. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11790. return $this->raiseError('%s requires PEAR Installer' . $extra .
  11791. ', installed version is ' . $pearversion);
  11792. }
  11793. return $this->warning('warning: %s requires PEAR Installer' . $extra .
  11794. ', installed version is ' . $pearversion);
  11795. }
  11796. if (isset($dep['max'])) {
  11797. if (version_compare($pearversion, $dep['max'], '>')) {
  11798. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11799. return $this->raiseError('%s requires PEAR Installer' . $extra .
  11800. ', installed version is ' . $pearversion);
  11801. }
  11802. return $this->warning('warning: %s requires PEAR Installer' . $extra .
  11803. ', installed version is ' . $pearversion);
  11804. }
  11805. }
  11806. if (isset($dep['exclude'])) {
  11807. if (!isset($dep['exclude'][0])) {
  11808. $dep['exclude'] = array($dep['exclude']);
  11809. }
  11810. foreach ($dep['exclude'] as $exclude) {
  11811. if (version_compare($exclude, $pearversion, '==')) {
  11812. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11813. return $this->raiseError('%s is not compatible with PEAR Installer ' .
  11814. 'version ' . $exclude);
  11815. }
  11816. return $this->warning('warning: %s is not compatible with PEAR ' .
  11817. 'Installer version ' . $exclude);
  11818. }
  11819. }
  11820. }
  11821. return true;
  11822. }
  11823. function validateSubpackageDependency($dep, $required, $params)
  11824. {
  11825. return $this->validatePackageDependency($dep, $required, $params);
  11826. }
  11827. /**
  11828. * @param array dependency information (2.0 format)
  11829. * @param boolean whether this is a required dependency
  11830. * @param array a list of downloaded packages to be installed, if any
  11831. * @param boolean if true, then deps on pear.php.net that fail will also check
  11832. * against pecl.php.net packages to accommodate extensions that have
  11833. * moved to pecl.php.net from pear.php.net
  11834. */
  11835. function validatePackageDependency($dep, $required, $params, $depv1 = false)
  11836. {
  11837. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11838. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11839. return true;
  11840. }
  11841. if (isset($dep['providesextension'])) {
  11842. if ($this->extension_loaded($dep['providesextension'])) {
  11843. $save = $dep;
  11844. $subdep = $dep;
  11845. $subdep['name'] = $subdep['providesextension'];
  11846. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  11847. $ret = $this->validateExtensionDependency($subdep, $required);
  11848. PEAR::popErrorHandling();
  11849. if (!PEAR::isError($ret)) {
  11850. return true;
  11851. }
  11852. }
  11853. }
  11854. if ($this->_state == PEAR_VALIDATE_INSTALLING) {
  11855. return $this->_validatePackageInstall($dep, $required, $depv1);
  11856. }
  11857. if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
  11858. return $this->_validatePackageDownload($dep, $required, $params, $depv1);
  11859. }
  11860. }
  11861. function _validatePackageDownload($dep, $required, $params, $depv1 = false)
  11862. {
  11863. $dep['package'] = $dep['name'];
  11864. if (isset($dep['uri'])) {
  11865. $dep['channel'] = '__uri';
  11866. }
  11867. $depname = $this->_registry->parsedPackageNameToString($dep, true);
  11868. $found = false;
  11869. foreach ($params as $param) {
  11870. if ($param->isEqual(
  11871. array('package' => $dep['name'],
  11872. 'channel' => $dep['channel']))) {
  11873. $found = true;
  11874. break;
  11875. }
  11876. if ($depv1 && $dep['channel'] == 'pear.php.net') {
  11877. if ($param->isEqual(
  11878. array('package' => $dep['name'],
  11879. 'channel' => 'pecl.php.net'))) {
  11880. $found = true;
  11881. break;
  11882. }
  11883. }
  11884. }
  11885. if (!$found && isset($dep['providesextension'])) {
  11886. foreach ($params as $param) {
  11887. if ($param->isExtension($dep['providesextension'])) {
  11888. $found = true;
  11889. break;
  11890. }
  11891. }
  11892. }
  11893. if ($found) {
  11894. $version = $param->getVersion();
  11895. $installed = false;
  11896. $downloaded = true;
  11897. } else {
  11898. if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
  11899. $installed = true;
  11900. $downloaded = false;
  11901. $version = $this->_registry->packageinfo($dep['name'], 'version',
  11902. $dep['channel']);
  11903. } else {
  11904. if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
  11905. 'pear.php.net')) {
  11906. $installed = true;
  11907. $downloaded = false;
  11908. $version = $this->_registry->packageinfo($dep['name'], 'version',
  11909. 'pear.php.net');
  11910. } else {
  11911. $version = 'not installed or downloaded';
  11912. $installed = false;
  11913. $downloaded = false;
  11914. }
  11915. }
  11916. }
  11917. $extra = self::_getExtraString($dep);
  11918. if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
  11919. $dep['exclude'] = array($dep['exclude']);
  11920. }
  11921. if (!isset($dep['min']) && !isset($dep['max']) &&
  11922. !isset($dep['recommended']) && !isset($dep['exclude'])
  11923. ) {
  11924. if ($installed || $downloaded) {
  11925. $installed = $installed ? 'installed' : 'downloaded';
  11926. if (isset($dep['conflicts'])) {
  11927. $rest = '';
  11928. if ($version) {
  11929. $rest = ", $installed version is " . $version;
  11930. }
  11931. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11932. return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest);
  11933. }
  11934. return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest);
  11935. }
  11936. return true;
  11937. }
  11938. if (isset($dep['conflicts'])) {
  11939. return true;
  11940. }
  11941. if ($required) {
  11942. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11943. return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
  11944. }
  11945. return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
  11946. }
  11947. return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
  11948. }
  11949. if (!$installed && !$downloaded) {
  11950. if (isset($dep['conflicts'])) {
  11951. return true;
  11952. }
  11953. if ($required) {
  11954. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11955. return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
  11956. }
  11957. return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
  11958. }
  11959. return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
  11960. }
  11961. $fail = false;
  11962. if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) {
  11963. $fail = true;
  11964. }
  11965. if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) {
  11966. $fail = true;
  11967. }
  11968. if ($fail && !isset($dep['conflicts'])) {
  11969. $installed = $installed ? 'installed' : 'downloaded';
  11970. $dep['package'] = $dep['name'];
  11971. $dep = $this->_registry->parsedPackageNameToString($dep, true);
  11972. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11973. return $this->raiseError('%s requires package "' . $depname . '"' .
  11974. $extra . ", $installed version is " . $version);
  11975. }
  11976. return $this->warning('warning: %s requires package "' . $depname . '"' .
  11977. $extra . ", $installed version is " . $version);
  11978. } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
  11979. isset($dep['conflicts']) && !isset($dep['exclude'])) {
  11980. $installed = $installed ? 'installed' : 'downloaded';
  11981. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11982. return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
  11983. ", $installed version is " . $version);
  11984. }
  11985. return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  11986. $extra . ", $installed version is " . $version);
  11987. }
  11988. if (isset($dep['exclude'])) {
  11989. $installed = $installed ? 'installed' : 'downloaded';
  11990. foreach ($dep['exclude'] as $exclude) {
  11991. if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
  11992. if (!isset($this->_options['nodeps']) &&
  11993. !isset($this->_options['force'])
  11994. ) {
  11995. return $this->raiseError('%s is not compatible with ' .
  11996. $installed . ' package "' .
  11997. $depname . '" version ' .
  11998. $exclude);
  11999. }
  12000. return $this->warning('warning: %s is not compatible with ' .
  12001. $installed . ' package "' .
  12002. $depname . '" version ' .
  12003. $exclude);
  12004. } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  12005. $installed = $installed ? 'installed' : 'downloaded';
  12006. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12007. return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  12008. $extra . ", $installed version is " . $version);
  12009. }
  12010. return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  12011. $extra . ", $installed version is " . $version);
  12012. }
  12013. }
  12014. }
  12015. if (isset($dep['recommended'])) {
  12016. $installed = $installed ? 'installed' : 'downloaded';
  12017. if (version_compare($version, $dep['recommended'], '==')) {
  12018. return true;
  12019. }
  12020. if (!$found && $installed) {
  12021. $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
  12022. }
  12023. if ($param) {
  12024. $found = false;
  12025. foreach ($params as $parent) {
  12026. if ($parent->isEqual($this->_currentPackage)) {
  12027. $found = true;
  12028. break;
  12029. }
  12030. }
  12031. if ($found) {
  12032. if ($param->isCompatible($parent)) {
  12033. return true;
  12034. }
  12035. } else { // this is for validPackage() calls
  12036. $parent = $this->_registry->getPackage($this->_currentPackage['package'],
  12037. $this->_currentPackage['channel']);
  12038. if ($parent !== null && $param->isCompatible($parent)) {
  12039. return true;
  12040. }
  12041. }
  12042. }
  12043. if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
  12044. !isset($this->_options['loose'])
  12045. ) {
  12046. return $this->raiseError('%s dependency package "' . $depname .
  12047. '" ' . $installed . ' version ' . $version .
  12048. ' is not the recommended version ' . $dep['recommended'] .
  12049. ', but may be compatible, use --force to install');
  12050. }
  12051. return $this->warning('warning: %s dependency package "' . $depname .
  12052. '" ' . $installed . ' version ' . $version .
  12053. ' is not the recommended version ' . $dep['recommended']);
  12054. }
  12055. return true;
  12056. }
  12057. function _validatePackageInstall($dep, $required, $depv1 = false)
  12058. {
  12059. return $this->_validatePackageDownload($dep, $required, array(), $depv1);
  12060. }
  12061. /**
  12062. * Verify that uninstalling packages passed in to command line is OK.
  12063. *
  12064. * @param PEAR_Installer $dl
  12065. * @return PEAR_Error|true
  12066. */
  12067. function validatePackageUninstall(&$dl)
  12068. {
  12069. if (PEAR::isError($this->_dependencydb)) {
  12070. return $this->_dependencydb;
  12071. }
  12072. $params = array();
  12073. // construct an array of "downloaded" packages to fool the package dependency checker
  12074. // into using these to validate uninstalls of circular dependencies
  12075. $downloaded = &$dl->getUninstallPackages();
  12076. foreach ($downloaded as $i => $pf) {
  12077. if (!class_exists('PEAR_Downloader_Package')) {
  12078. require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php';
  12079. }
  12080. $dp = new PEAR_Downloader_Package($dl);
  12081. $dp->setPackageFile($downloaded[$i]);
  12082. $params[$i] = $dp;
  12083. }
  12084. // check cache
  12085. $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' .
  12086. strtolower($this->_currentPackage['package']);
  12087. if (isset($dl->___uninstall_package_cache)) {
  12088. $badpackages = $dl->___uninstall_package_cache;
  12089. if (isset($badpackages[$memyselfandI]['warnings'])) {
  12090. foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  12091. $dl->log(0, $warning[0]);
  12092. }
  12093. }
  12094. if (isset($badpackages[$memyselfandI]['errors'])) {
  12095. foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  12096. if (is_array($error)) {
  12097. $dl->log(0, $error[0]);
  12098. } else {
  12099. $dl->log(0, $error->getMessage());
  12100. }
  12101. }
  12102. if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  12103. return $this->warning(
  12104. 'warning: %s should not be uninstalled, other installed packages depend ' .
  12105. 'on this package');
  12106. }
  12107. return $this->raiseError(
  12108. '%s cannot be uninstalled, other installed packages depend on this package');
  12109. }
  12110. return true;
  12111. }
  12112. // first, list the immediate parents of each package to be uninstalled
  12113. $perpackagelist = array();
  12114. $allparents = array();
  12115. foreach ($params as $i => $param) {
  12116. $a = array(
  12117. 'channel' => strtolower($param->getChannel()),
  12118. 'package' => strtolower($param->getPackage())
  12119. );
  12120. $deps = $this->_dependencydb->getDependentPackages($a);
  12121. if ($deps) {
  12122. foreach ($deps as $d) {
  12123. $pardeps = $this->_dependencydb->getDependencies($d);
  12124. foreach ($pardeps as $dep) {
  12125. if (strtolower($dep['dep']['channel']) == $a['channel'] &&
  12126. strtolower($dep['dep']['name']) == $a['package']) {
  12127. if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) {
  12128. $perpackagelist[$a['channel'] . '/' . $a['package']] = array();
  12129. }
  12130. $perpackagelist[$a['channel'] . '/' . $a['package']][]
  12131. = array($d['channel'] . '/' . $d['package'], $dep);
  12132. if (!isset($allparents[$d['channel'] . '/' . $d['package']])) {
  12133. $allparents[$d['channel'] . '/' . $d['package']] = array();
  12134. }
  12135. if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) {
  12136. $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array();
  12137. }
  12138. $allparents[$d['channel'] . '/' . $d['package']]
  12139. [$a['channel'] . '/' . $a['package']][]
  12140. = array($d, $dep);
  12141. }
  12142. }
  12143. }
  12144. }
  12145. }
  12146. // next, remove any packages from the parents list that are not installed
  12147. $remove = array();
  12148. foreach ($allparents as $parent => $d1) {
  12149. foreach ($d1 as $d) {
  12150. if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) {
  12151. continue;
  12152. }
  12153. $remove[$parent] = true;
  12154. }
  12155. }
  12156. // next remove any packages from the parents list that are not passed in for
  12157. // uninstallation
  12158. foreach ($allparents as $parent => $d1) {
  12159. foreach ($d1 as $d) {
  12160. foreach ($params as $param) {
  12161. if (strtolower($param->getChannel()) == $d[0][0]['channel'] &&
  12162. strtolower($param->getPackage()) == $d[0][0]['package']) {
  12163. // found it
  12164. continue 3;
  12165. }
  12166. }
  12167. $remove[$parent] = true;
  12168. }
  12169. }
  12170. // remove all packages whose dependencies fail
  12171. // save which ones failed for error reporting
  12172. $badchildren = array();
  12173. do {
  12174. $fail = false;
  12175. foreach ($remove as $package => $unused) {
  12176. if (!isset($allparents[$package])) {
  12177. continue;
  12178. }
  12179. foreach ($allparents[$package] as $kid => $d1) {
  12180. foreach ($d1 as $depinfo) {
  12181. if ($depinfo[1]['type'] != 'optional') {
  12182. if (isset($badchildren[$kid])) {
  12183. continue;
  12184. }
  12185. $badchildren[$kid] = true;
  12186. $remove[$kid] = true;
  12187. $fail = true;
  12188. continue 2;
  12189. }
  12190. }
  12191. }
  12192. if ($fail) {
  12193. // start over, we removed some children
  12194. continue 2;
  12195. }
  12196. }
  12197. } while ($fail);
  12198. // next, construct the list of packages that can't be uninstalled
  12199. $badpackages = array();
  12200. $save = $this->_currentPackage;
  12201. foreach ($perpackagelist as $package => $packagedeps) {
  12202. foreach ($packagedeps as $parent) {
  12203. if (!isset($remove[$parent[0]])) {
  12204. continue;
  12205. }
  12206. $packagename = $this->_registry->parsePackageName($parent[0]);
  12207. $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']);
  12208. $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']);
  12209. $packagename['package'] = $pa->getPackage();
  12210. $this->_currentPackage = $packagename;
  12211. // parent is not present in uninstall list, make sure we can actually
  12212. // uninstall it (parent dep is optional)
  12213. $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']);
  12214. $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']);
  12215. $parentname['package'] = $pa->getPackage();
  12216. $parent[1]['dep']['package'] = $parentname['package'];
  12217. $parent[1]['dep']['channel'] = $parentname['channel'];
  12218. if ($parent[1]['type'] == 'optional') {
  12219. $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl);
  12220. if ($test !== true) {
  12221. $badpackages[$package]['warnings'][] = $test;
  12222. }
  12223. } else {
  12224. $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl);
  12225. if ($test !== true) {
  12226. $badpackages[$package]['errors'][] = $test;
  12227. }
  12228. }
  12229. }
  12230. }
  12231. $this->_currentPackage = $save;
  12232. $dl->___uninstall_package_cache = $badpackages;
  12233. if (isset($badpackages[$memyselfandI])) {
  12234. if (isset($badpackages[$memyselfandI]['warnings'])) {
  12235. foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  12236. $dl->log(0, $warning[0]);
  12237. }
  12238. }
  12239. if (isset($badpackages[$memyselfandI]['errors'])) {
  12240. foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  12241. if (is_array($error)) {
  12242. $dl->log(0, $error[0]);
  12243. } else {
  12244. $dl->log(0, $error->getMessage());
  12245. }
  12246. }
  12247. if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  12248. return $this->warning(
  12249. 'warning: %s should not be uninstalled, other installed packages depend ' .
  12250. 'on this package');
  12251. }
  12252. return $this->raiseError(
  12253. '%s cannot be uninstalled, other installed packages depend on this package');
  12254. }
  12255. }
  12256. return true;
  12257. }
  12258. function _validatePackageUninstall($dep, $required, $dl)
  12259. {
  12260. $depname = $this->_registry->parsedPackageNameToString($dep, true);
  12261. $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']);
  12262. if (!$version) {
  12263. return true;
  12264. }
  12265. $extra = self::_getExtraString($dep);
  12266. if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
  12267. $dep['exclude'] = array($dep['exclude']);
  12268. }
  12269. if (isset($dep['conflicts'])) {
  12270. return true; // uninstall OK - these packages conflict (probably installed with --force)
  12271. }
  12272. if (!isset($dep['min']) && !isset($dep['max'])) {
  12273. if (!$required) {
  12274. return $this->warning('"' . $depname . '" can be optionally used by ' .
  12275. 'installed package %s' . $extra);
  12276. }
  12277. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12278. return $this->raiseError('"' . $depname . '" is required by ' .
  12279. 'installed package %s' . $extra);
  12280. }
  12281. return $this->warning('warning: "' . $depname . '" is required by ' .
  12282. 'installed package %s' . $extra);
  12283. }
  12284. $fail = false;
  12285. if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) {
  12286. $fail = true;
  12287. }
  12288. if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) {
  12289. $fail = true;
  12290. }
  12291. // we re-use this variable, preserve the original value
  12292. $saverequired = $required;
  12293. if (!$required) {
  12294. return $this->warning($depname . $extra . ' can be optionally used by installed package' .
  12295. ' "%s"');
  12296. }
  12297. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12298. return $this->raiseError($depname . $extra . ' is required by installed package' .
  12299. ' "%s"');
  12300. }
  12301. return $this->raiseError('warning: ' . $depname . $extra .
  12302. ' is required by installed package "%s"');
  12303. }
  12304. /**
  12305. * validate a downloaded package against installed packages
  12306. *
  12307. * As of PEAR 1.4.3, this will only validate
  12308. *
  12309. * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  12310. * $pkg package identifier (either
  12311. * array('package' => blah, 'channel' => blah) or an array with
  12312. * index 'info' referencing an object)
  12313. * @param PEAR_Downloader $dl
  12314. * @param array $params full list of packages to install
  12315. * @return true|PEAR_Error
  12316. */
  12317. function validatePackage($pkg, &$dl, $params = array())
  12318. {
  12319. if (is_array($pkg) && isset($pkg['info'])) {
  12320. $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
  12321. } else {
  12322. $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
  12323. }
  12324. $fail = false;
  12325. if ($deps) {
  12326. if (!class_exists('PEAR_Downloader_Package')) {
  12327. require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php';
  12328. }
  12329. $dp = new PEAR_Downloader_Package($dl);
  12330. if (is_object($pkg)) {
  12331. $dp->setPackageFile($pkg);
  12332. } else {
  12333. $dp->setDownloadURL($pkg);
  12334. }
  12335. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  12336. foreach ($deps as $channel => $info) {
  12337. foreach ($info as $package => $ds) {
  12338. foreach ($params as $packd) {
  12339. if (strtolower($packd->getPackage()) == strtolower($package) &&
  12340. $packd->getChannel() == $channel) {
  12341. $dl->log(3, 'skipping installed package check of "' .
  12342. $this->_registry->parsedPackageNameToString(
  12343. array('channel' => $channel, 'package' => $package),
  12344. true) .
  12345. '", version "' . $packd->getVersion() . '" will be ' .
  12346. 'downloaded and installed');
  12347. continue 2; // jump to next package
  12348. }
  12349. }
  12350. foreach ($ds as $d) {
  12351. $checker = new PEAR_Dependency2($this->_config, $this->_options,
  12352. array('channel' => $channel, 'package' => $package), $this->_state);
  12353. $dep = $d['dep'];
  12354. $required = $d['type'] == 'required';
  12355. $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
  12356. if (is_array($ret)) {
  12357. $dl->log(0, $ret[0]);
  12358. } elseif (PEAR::isError($ret)) {
  12359. $dl->log(0, $ret->getMessage());
  12360. $fail = true;
  12361. }
  12362. }
  12363. }
  12364. }
  12365. PEAR::popErrorHandling();
  12366. }
  12367. if ($fail) {
  12368. return $this->raiseError(
  12369. '%s cannot be installed, conflicts with installed packages');
  12370. }
  12371. return true;
  12372. }
  12373. /**
  12374. * validate a package.xml 1.0 dependency
  12375. */
  12376. function validateDependency1($dep, $params = array())
  12377. {
  12378. if (!isset($dep['optional'])) {
  12379. $dep['optional'] = 'no';
  12380. }
  12381. list($newdep, $type) = self::normalizeDep($dep);
  12382. if (!$newdep) {
  12383. return $this->raiseError("Invalid Dependency");
  12384. }
  12385. if (method_exists($this, "validate{$type}Dependency")) {
  12386. return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
  12387. $params, true);
  12388. }
  12389. }
  12390. /**
  12391. * Convert a 1.0 dep into a 2.0 dep
  12392. */
  12393. static function normalizeDep($dep)
  12394. {
  12395. $types = array(
  12396. 'pkg' => 'Package',
  12397. 'ext' => 'Extension',
  12398. 'os' => 'Os',
  12399. 'php' => 'Php'
  12400. );
  12401. if (!isset($types[$dep['type']])) {
  12402. return array(false, false);
  12403. }
  12404. $type = $types[$dep['type']];
  12405. $newdep = array();
  12406. switch ($type) {
  12407. case 'Package' :
  12408. $newdep['channel'] = 'pear.php.net';
  12409. case 'Extension' :
  12410. case 'Os' :
  12411. $newdep['name'] = $dep['name'];
  12412. break;
  12413. }
  12414. $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
  12415. switch ($dep['rel']) {
  12416. case 'has' :
  12417. return array($newdep, $type);
  12418. break;
  12419. case 'not' :
  12420. $newdep['conflicts'] = true;
  12421. break;
  12422. case '>=' :
  12423. case '>' :
  12424. $newdep['min'] = $dep['version'];
  12425. if ($dep['rel'] == '>') {
  12426. $newdep['exclude'] = $dep['version'];
  12427. }
  12428. break;
  12429. case '<=' :
  12430. case '<' :
  12431. $newdep['max'] = $dep['version'];
  12432. if ($dep['rel'] == '<') {
  12433. $newdep['exclude'] = $dep['version'];
  12434. }
  12435. break;
  12436. case 'ne' :
  12437. case '!=' :
  12438. $newdep['min'] = '0';
  12439. $newdep['max'] = '100000';
  12440. $newdep['exclude'] = $dep['version'];
  12441. break;
  12442. case '==' :
  12443. $newdep['min'] = $dep['version'];
  12444. $newdep['max'] = $dep['version'];
  12445. break;
  12446. }
  12447. if ($type == 'Php') {
  12448. if (!isset($newdep['min'])) {
  12449. $newdep['min'] = '4.4.0';
  12450. }
  12451. if (!isset($newdep['max'])) {
  12452. $newdep['max'] = '6.0.0';
  12453. }
  12454. }
  12455. return array($newdep, $type);
  12456. }
  12457. /**
  12458. * Converts text comparing operators to them sign equivalents
  12459. *
  12460. * Example: 'ge' to '>='
  12461. *
  12462. * @access public
  12463. * @param string Operator
  12464. * @return string Sign equivalent
  12465. */
  12466. static function signOperator($operator)
  12467. {
  12468. switch($operator) {
  12469. case 'lt': return '<';
  12470. case 'le': return '<=';
  12471. case 'gt': return '>';
  12472. case 'ge': return '>=';
  12473. case 'eq': return '==';
  12474. case 'ne': return '!=';
  12475. default:
  12476. return $operator;
  12477. }
  12478. }
  12479. function raiseError($msg)
  12480. {
  12481. if (isset($this->_options['ignore-errors'])) {
  12482. return $this->warning($msg);
  12483. }
  12484. return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
  12485. $this->_currentPackage, true)));
  12486. }
  12487. function warning($msg)
  12488. {
  12489. return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
  12490. $this->_currentPackage, true)));
  12491. }
  12492. }
  12493. <?php
  12494. /**
  12495. * PEAR_DependencyDB, advanced installed packages dependency database
  12496. *
  12497. * PHP versions 4 and 5
  12498. *
  12499. * @category pear
  12500. * @package PEAR
  12501. * @author Tomas V. V. Cox <cox@idecnet.com>
  12502. * @author Greg Beaver <cellog@php.net>
  12503. * @copyright 1997-2009 The Authors
  12504. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  12505. * @link http://pear.php.net/package/PEAR
  12506. * @since File available since Release 1.4.0a1
  12507. */
  12508. /**
  12509. * Needed for error handling
  12510. */
  12511. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  12512. require_once 'phar://go-pear.phar/' . 'PEAR/Config.php';
  12513. $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
  12514. /**
  12515. * Track dependency relationships between installed packages
  12516. * @category pear
  12517. * @package PEAR
  12518. * @author Greg Beaver <cellog@php.net>
  12519. * @author Tomas V.V.Cox <cox@idec.net.com>
  12520. * @copyright 1997-2009 The Authors
  12521. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  12522. * @version Release: 1.10.10
  12523. * @link http://pear.php.net/package/PEAR
  12524. * @since Class available since Release 1.4.0a1
  12525. */
  12526. class PEAR_DependencyDB
  12527. {
  12528. // {{{ properties
  12529. /**
  12530. * This is initialized by {@link setConfig()}
  12531. * @var PEAR_Config
  12532. * @access private
  12533. */
  12534. var $_config;
  12535. /**
  12536. * This is initialized by {@link setConfig()}
  12537. * @var PEAR_Registry
  12538. * @access private
  12539. */
  12540. var $_registry;
  12541. /**
  12542. * Filename of the dependency DB (usually .depdb)
  12543. * @var string
  12544. * @access private
  12545. */
  12546. var $_depdb = false;
  12547. /**
  12548. * File name of the lockfile (usually .depdblock)
  12549. * @var string
  12550. * @access private
  12551. */
  12552. var $_lockfile = false;
  12553. /**
  12554. * Open file resource for locking the lockfile
  12555. * @var resource|false
  12556. * @access private
  12557. */
  12558. var $_lockFp = false;
  12559. /**
  12560. * API version of this class, used to validate a file on-disk
  12561. * @var string
  12562. * @access private
  12563. */
  12564. var $_version = '1.0';
  12565. /**
  12566. * Cached dependency database file
  12567. * @var array|null
  12568. * @access private
  12569. */
  12570. var $_cache;
  12571. // }}}
  12572. // {{{ & singleton()
  12573. /**
  12574. * Get a raw dependency database. Calls setConfig() and assertDepsDB()
  12575. * @param PEAR_Config
  12576. * @param string|false full path to the dependency database, or false to use default
  12577. * @return PEAR_DependencyDB|PEAR_Error
  12578. */
  12579. public static function &singleton(&$config, $depdb = false)
  12580. {
  12581. $phpdir = $config->get('php_dir', null, 'pear.php.net');
  12582. if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) {
  12583. $a = new PEAR_DependencyDB;
  12584. $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a;
  12585. $a->setConfig($config, $depdb);
  12586. $e = $a->assertDepsDB();
  12587. if (PEAR::isError($e)) {
  12588. return $e;
  12589. }
  12590. }
  12591. return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir];
  12592. }
  12593. /**
  12594. * Set up the registry/location of dependency DB
  12595. * @param PEAR_Config|false
  12596. * @param string|false full path to the dependency database, or false to use default
  12597. */
  12598. function setConfig(&$config, $depdb = false)
  12599. {
  12600. if (!$config) {
  12601. $this->_config = &PEAR_Config::singleton();
  12602. } else {
  12603. $this->_config = &$config;
  12604. }
  12605. $this->_registry = &$this->_config->getRegistry();
  12606. if (!$depdb) {
  12607. $dir = $this->_config->get('metadata_dir', null, 'pear.php.net');
  12608. if (!$dir) {
  12609. $dir = $this->_config->get('php_dir', null, 'pear.php.net');
  12610. }
  12611. $this->_depdb = $dir . DIRECTORY_SEPARATOR . '.depdb';
  12612. } else {
  12613. $this->_depdb = $depdb;
  12614. }
  12615. $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
  12616. }
  12617. // }}}
  12618. function hasWriteAccess()
  12619. {
  12620. if (!file_exists($this->_depdb)) {
  12621. $dir = $this->_depdb;
  12622. while ($dir && $dir != '.') {
  12623. $dir = dirname($dir); // cd ..
  12624. if ($dir != '.' && file_exists($dir)) {
  12625. if (is_writeable($dir)) {
  12626. return true;
  12627. }
  12628. return false;
  12629. }
  12630. }
  12631. return false;
  12632. }
  12633. return is_writeable($this->_depdb);
  12634. }
  12635. // {{{ assertDepsDB()
  12636. /**
  12637. * Create the dependency database, if it doesn't exist. Error if the database is
  12638. * newer than the code reading it.
  12639. * @return void|PEAR_Error
  12640. */
  12641. function assertDepsDB()
  12642. {
  12643. if (!is_file($this->_depdb)) {
  12644. $this->rebuildDB();
  12645. return;
  12646. }
  12647. $depdb = $this->_getDepDB();
  12648. // Datatype format has been changed, rebuild the Deps DB
  12649. if ($depdb['_version'] < $this->_version) {
  12650. $this->rebuildDB();
  12651. }
  12652. if ($depdb['_version'][0] > $this->_version[0]) {
  12653. return PEAR::raiseError('Dependency database is version ' .
  12654. $depdb['_version'] . ', and we are version ' .
  12655. $this->_version . ', cannot continue');
  12656. }
  12657. }
  12658. /**
  12659. * Get a list of installed packages that depend on this package
  12660. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  12661. * @return array|false
  12662. */
  12663. function getDependentPackages(&$pkg)
  12664. {
  12665. $data = $this->_getDepDB();
  12666. if (is_object($pkg)) {
  12667. $channel = strtolower($pkg->getChannel());
  12668. $package = strtolower($pkg->getPackage());
  12669. } else {
  12670. $channel = strtolower($pkg['channel']);
  12671. $package = strtolower($pkg['package']);
  12672. }
  12673. if (isset($data['packages'][$channel][$package])) {
  12674. return $data['packages'][$channel][$package];
  12675. }
  12676. return false;
  12677. }
  12678. /**
  12679. * Get a list of the actual dependencies of installed packages that depend on
  12680. * a package.
  12681. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  12682. * @return array|false
  12683. */
  12684. function getDependentPackageDependencies(&$pkg)
  12685. {
  12686. $data = $this->_getDepDB();
  12687. if (is_object($pkg)) {
  12688. $channel = strtolower($pkg->getChannel());
  12689. $package = strtolower($pkg->getPackage());
  12690. } else if (is_array($pkg)) {
  12691. $channel = strtolower($pkg['channel']);
  12692. $package = strtolower($pkg['package']);
  12693. } else {
  12694. return false;
  12695. }
  12696. $depend = $this->getDependentPackages($pkg);
  12697. if (!$depend) {
  12698. return false;
  12699. }
  12700. $dependencies = array();
  12701. foreach ($depend as $info) {
  12702. $temp = $this->getDependencies($info);
  12703. foreach ($temp as $dep) {
  12704. if (
  12705. isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) &&
  12706. strtolower($dep['dep']['channel']) == $channel &&
  12707. strtolower($dep['dep']['name']) == $package
  12708. ) {
  12709. if (!isset($dependencies[$info['channel']])) {
  12710. $dependencies[$info['channel']] = array();
  12711. }
  12712. if (!isset($dependencies[$info['channel']][$info['package']])) {
  12713. $dependencies[$info['channel']][$info['package']] = array();
  12714. }
  12715. $dependencies[$info['channel']][$info['package']][] = $dep;
  12716. }
  12717. }
  12718. }
  12719. return $dependencies;
  12720. }
  12721. /**
  12722. * Get a list of dependencies of this installed package
  12723. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  12724. * @return array|false
  12725. */
  12726. function getDependencies(&$pkg)
  12727. {
  12728. if (is_object($pkg)) {
  12729. $channel = strtolower($pkg->getChannel());
  12730. $package = strtolower($pkg->getPackage());
  12731. } else {
  12732. $channel = strtolower($pkg['channel']);
  12733. $package = strtolower($pkg['package']);
  12734. }
  12735. $data = $this->_getDepDB();
  12736. if (isset($data['dependencies'][$channel][$package])) {
  12737. return $data['dependencies'][$channel][$package];
  12738. }
  12739. return false;
  12740. }
  12741. /**
  12742. * Determine whether $parent depends on $child, near or deep
  12743. * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  12744. * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  12745. */
  12746. function dependsOn($parent, $child)
  12747. {
  12748. $c = array();
  12749. $this->_getDepDB();
  12750. return $this->_dependsOn($parent, $child, $c);
  12751. }
  12752. function _dependsOn($parent, $child, &$checked)
  12753. {
  12754. if (is_object($parent)) {
  12755. $channel = strtolower($parent->getChannel());
  12756. $package = strtolower($parent->getPackage());
  12757. } else {
  12758. $channel = strtolower($parent['channel']);
  12759. $package = strtolower($parent['package']);
  12760. }
  12761. if (is_object($child)) {
  12762. $depchannel = strtolower($child->getChannel());
  12763. $deppackage = strtolower($child->getPackage());
  12764. } else {
  12765. $depchannel = strtolower($child['channel']);
  12766. $deppackage = strtolower($child['package']);
  12767. }
  12768. if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
  12769. return false; // avoid endless recursion
  12770. }
  12771. $checked[$channel][$package][$depchannel][$deppackage] = true;
  12772. if (!isset($this->_cache['dependencies'][$channel][$package])) {
  12773. return false;
  12774. }
  12775. foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  12776. if (isset($info['dep']['uri'])) {
  12777. if (is_object($child)) {
  12778. if ($info['dep']['uri'] == $child->getURI()) {
  12779. return true;
  12780. }
  12781. } elseif (isset($child['uri'])) {
  12782. if ($info['dep']['uri'] == $child['uri']) {
  12783. return true;
  12784. }
  12785. }
  12786. return false;
  12787. }
  12788. if (strtolower($info['dep']['channel']) == $depchannel &&
  12789. strtolower($info['dep']['name']) == $deppackage) {
  12790. return true;
  12791. }
  12792. }
  12793. foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  12794. if (isset($info['dep']['uri'])) {
  12795. if ($this->_dependsOn(array(
  12796. 'uri' => $info['dep']['uri'],
  12797. 'package' => $info['dep']['name']), $child, $checked)) {
  12798. return true;
  12799. }
  12800. } else {
  12801. if ($this->_dependsOn(array(
  12802. 'channel' => $info['dep']['channel'],
  12803. 'package' => $info['dep']['name']), $child, $checked)) {
  12804. return true;
  12805. }
  12806. }
  12807. }
  12808. return false;
  12809. }
  12810. /**
  12811. * Register dependencies of a package that is being installed or upgraded
  12812. * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
  12813. */
  12814. function installPackage(&$package)
  12815. {
  12816. $data = $this->_getDepDB();
  12817. unset($this->_cache);
  12818. $this->_setPackageDeps($data, $package);
  12819. $this->_writeDepDB($data);
  12820. }
  12821. /**
  12822. * Remove dependencies of a package that is being uninstalled, or upgraded.
  12823. *
  12824. * Upgraded packages first uninstall, then install
  12825. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
  12826. * indices 'channel' and 'package'
  12827. */
  12828. function uninstallPackage(&$pkg)
  12829. {
  12830. $data = $this->_getDepDB();
  12831. unset($this->_cache);
  12832. if (is_object($pkg)) {
  12833. $channel = strtolower($pkg->getChannel());
  12834. $package = strtolower($pkg->getPackage());
  12835. } else {
  12836. $channel = strtolower($pkg['channel']);
  12837. $package = strtolower($pkg['package']);
  12838. }
  12839. if (!isset($data['dependencies'][$channel][$package])) {
  12840. return true;
  12841. }
  12842. foreach ($data['dependencies'][$channel][$package] as $dep) {
  12843. $found = false;
  12844. $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']);
  12845. $depname = strtolower($dep['dep']['name']);
  12846. if (isset($data['packages'][$depchannel][$depname])) {
  12847. foreach ($data['packages'][$depchannel][$depname] as $i => $info) {
  12848. if ($info['channel'] == $channel && $info['package'] == $package) {
  12849. $found = true;
  12850. break;
  12851. }
  12852. }
  12853. }
  12854. if ($found) {
  12855. unset($data['packages'][$depchannel][$depname][$i]);
  12856. if (!count($data['packages'][$depchannel][$depname])) {
  12857. unset($data['packages'][$depchannel][$depname]);
  12858. if (!count($data['packages'][$depchannel])) {
  12859. unset($data['packages'][$depchannel]);
  12860. }
  12861. } else {
  12862. $data['packages'][$depchannel][$depname] =
  12863. array_values($data['packages'][$depchannel][$depname]);
  12864. }
  12865. }
  12866. }
  12867. unset($data['dependencies'][$channel][$package]);
  12868. if (!count($data['dependencies'][$channel])) {
  12869. unset($data['dependencies'][$channel]);
  12870. }
  12871. if (!count($data['dependencies'])) {
  12872. unset($data['dependencies']);
  12873. }
  12874. if (!count($data['packages'])) {
  12875. unset($data['packages']);
  12876. }
  12877. $this->_writeDepDB($data);
  12878. }
  12879. /**
  12880. * Rebuild the dependency DB by reading registry entries.
  12881. * @return true|PEAR_Error
  12882. */
  12883. function rebuildDB()
  12884. {
  12885. $depdb = array('_version' => $this->_version);
  12886. if (!$this->hasWriteAccess()) {
  12887. // allow startup for read-only with older Registry
  12888. return $depdb;
  12889. }
  12890. $packages = $this->_registry->listAllPackages();
  12891. if (PEAR::isError($packages)) {
  12892. return $packages;
  12893. }
  12894. foreach ($packages as $channel => $ps) {
  12895. foreach ($ps as $package) {
  12896. $package = $this->_registry->getPackage($package, $channel);
  12897. if (PEAR::isError($package)) {
  12898. return $package;
  12899. }
  12900. $this->_setPackageDeps($depdb, $package);
  12901. }
  12902. }
  12903. $error = $this->_writeDepDB($depdb);
  12904. if (PEAR::isError($error)) {
  12905. return $error;
  12906. }
  12907. $this->_cache = $depdb;
  12908. return true;
  12909. }
  12910. /**
  12911. * Register usage of the dependency DB to prevent race conditions
  12912. * @param int one of the LOCK_* constants
  12913. * @return true|PEAR_Error
  12914. * @access private
  12915. */
  12916. function _lock($mode = LOCK_EX)
  12917. {
  12918. if (stristr(php_uname(), 'Windows 9')) {
  12919. return true;
  12920. }
  12921. if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
  12922. // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  12923. return true;
  12924. }
  12925. $open_mode = 'w';
  12926. // XXX People reported problems with LOCK_SH and 'w'
  12927. if ($mode === LOCK_SH) {
  12928. if (!file_exists($this->_lockfile)) {
  12929. touch($this->_lockfile);
  12930. } elseif (!is_file($this->_lockfile)) {
  12931. return PEAR::raiseError('could not create Dependency lock file, ' .
  12932. 'it exists and is not a regular file');
  12933. }
  12934. $open_mode = 'r';
  12935. }
  12936. if (!is_resource($this->_lockFp)) {
  12937. $this->_lockFp = @fopen($this->_lockfile, $open_mode);
  12938. }
  12939. if (!is_resource($this->_lockFp)) {
  12940. return PEAR::raiseError("could not create Dependency lock file" .
  12941. (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  12942. }
  12943. if (!(int)flock($this->_lockFp, $mode)) {
  12944. switch ($mode) {
  12945. case LOCK_SH: $str = 'shared'; break;
  12946. case LOCK_EX: $str = 'exclusive'; break;
  12947. case LOCK_UN: $str = 'unlock'; break;
  12948. default: $str = 'unknown'; break;
  12949. }
  12950. return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
  12951. }
  12952. return true;
  12953. }
  12954. /**
  12955. * Release usage of dependency DB
  12956. * @return true|PEAR_Error
  12957. * @access private
  12958. */
  12959. function _unlock()
  12960. {
  12961. $ret = $this->_lock(LOCK_UN);
  12962. if (is_resource($this->_lockFp)) {
  12963. fclose($this->_lockFp);
  12964. }
  12965. $this->_lockFp = null;
  12966. return $ret;
  12967. }
  12968. /**
  12969. * Load the dependency database from disk, or return the cache
  12970. * @return array|PEAR_Error
  12971. */
  12972. function _getDepDB()
  12973. {
  12974. if (!$this->hasWriteAccess()) {
  12975. return array('_version' => $this->_version);
  12976. }
  12977. if (isset($this->_cache)) {
  12978. return $this->_cache;
  12979. }
  12980. if (!$fp = fopen($this->_depdb, 'r')) {
  12981. $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
  12982. return $err;
  12983. }
  12984. clearstatcache();
  12985. fclose($fp);
  12986. $data = unserialize(file_get_contents($this->_depdb));
  12987. $this->_cache = $data;
  12988. return $data;
  12989. }
  12990. /**
  12991. * Write out the dependency database to disk
  12992. * @param array the database
  12993. * @return true|PEAR_Error
  12994. * @access private
  12995. */
  12996. function _writeDepDB(&$deps)
  12997. {
  12998. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  12999. return $e;
  13000. }
  13001. if (!$fp = fopen($this->_depdb, 'wb')) {
  13002. $this->_unlock();
  13003. return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
  13004. }
  13005. fwrite($fp, serialize($deps));
  13006. fclose($fp);
  13007. $this->_unlock();
  13008. $this->_cache = $deps;
  13009. return true;
  13010. }
  13011. /**
  13012. * Register all dependencies from a package in the dependencies database, in essence
  13013. * "installing" the package's dependency information
  13014. * @param array the database
  13015. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  13016. * @access private
  13017. */
  13018. function _setPackageDeps(&$data, &$pkg)
  13019. {
  13020. $pkg->setConfig($this->_config);
  13021. if ($pkg->getPackagexmlVersion() == '1.0') {
  13022. $gen = &$pkg->getDefaultGenerator();
  13023. $deps = $gen->dependenciesToV2();
  13024. } else {
  13025. $deps = $pkg->getDeps(true);
  13026. }
  13027. if (!$deps) {
  13028. return;
  13029. }
  13030. if (!is_array($data)) {
  13031. $data = array();
  13032. }
  13033. if (!isset($data['dependencies'])) {
  13034. $data['dependencies'] = array();
  13035. }
  13036. $channel = strtolower($pkg->getChannel());
  13037. $package = strtolower($pkg->getPackage());
  13038. if (!isset($data['dependencies'][$channel])) {
  13039. $data['dependencies'][$channel] = array();
  13040. }
  13041. $data['dependencies'][$channel][$package] = array();
  13042. if (isset($deps['required']['package'])) {
  13043. if (!isset($deps['required']['package'][0])) {
  13044. $deps['required']['package'] = array($deps['required']['package']);
  13045. }
  13046. foreach ($deps['required']['package'] as $dep) {
  13047. $this->_registerDep($data, $pkg, $dep, 'required');
  13048. }
  13049. }
  13050. if (isset($deps['optional']['package'])) {
  13051. if (!isset($deps['optional']['package'][0])) {
  13052. $deps['optional']['package'] = array($deps['optional']['package']);
  13053. }
  13054. foreach ($deps['optional']['package'] as $dep) {
  13055. $this->_registerDep($data, $pkg, $dep, 'optional');
  13056. }
  13057. }
  13058. if (isset($deps['required']['subpackage'])) {
  13059. if (!isset($deps['required']['subpackage'][0])) {
  13060. $deps['required']['subpackage'] = array($deps['required']['subpackage']);
  13061. }
  13062. foreach ($deps['required']['subpackage'] as $dep) {
  13063. $this->_registerDep($data, $pkg, $dep, 'required');
  13064. }
  13065. }
  13066. if (isset($deps['optional']['subpackage'])) {
  13067. if (!isset($deps['optional']['subpackage'][0])) {
  13068. $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
  13069. }
  13070. foreach ($deps['optional']['subpackage'] as $dep) {
  13071. $this->_registerDep($data, $pkg, $dep, 'optional');
  13072. }
  13073. }
  13074. if (isset($deps['group'])) {
  13075. if (!isset($deps['group'][0])) {
  13076. $deps['group'] = array($deps['group']);
  13077. }
  13078. foreach ($deps['group'] as $group) {
  13079. if (isset($group['package'])) {
  13080. if (!isset($group['package'][0])) {
  13081. $group['package'] = array($group['package']);
  13082. }
  13083. foreach ($group['package'] as $dep) {
  13084. $this->_registerDep($data, $pkg, $dep, 'optional',
  13085. $group['attribs']['name']);
  13086. }
  13087. }
  13088. if (isset($group['subpackage'])) {
  13089. if (!isset($group['subpackage'][0])) {
  13090. $group['subpackage'] = array($group['subpackage']);
  13091. }
  13092. foreach ($group['subpackage'] as $dep) {
  13093. $this->_registerDep($data, $pkg, $dep, 'optional',
  13094. $group['attribs']['name']);
  13095. }
  13096. }
  13097. }
  13098. }
  13099. if ($data['dependencies'][$channel][$package] == array()) {
  13100. unset($data['dependencies'][$channel][$package]);
  13101. if (!count($data['dependencies'][$channel])) {
  13102. unset($data['dependencies'][$channel]);
  13103. }
  13104. }
  13105. }
  13106. /**
  13107. * @param array the database
  13108. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  13109. * @param array the specific dependency
  13110. * @param required|optional whether this is a required or an optional dep
  13111. * @param string|false dependency group this dependency is from, or false for ordinary dep
  13112. */
  13113. function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
  13114. {
  13115. $info = array(
  13116. 'dep' => $dep,
  13117. 'type' => $type,
  13118. 'group' => $group
  13119. );
  13120. $dep = array_map('strtolower', $dep);
  13121. $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
  13122. if (!isset($data['dependencies'])) {
  13123. $data['dependencies'] = array();
  13124. }
  13125. $channel = strtolower($pkg->getChannel());
  13126. $package = strtolower($pkg->getPackage());
  13127. if (!isset($data['dependencies'][$channel])) {
  13128. $data['dependencies'][$channel] = array();
  13129. }
  13130. if (!isset($data['dependencies'][$channel][$package])) {
  13131. $data['dependencies'][$channel][$package] = array();
  13132. }
  13133. $data['dependencies'][$channel][$package][] = $info;
  13134. if (isset($data['packages'][$depchannel][$dep['name']])) {
  13135. $found = false;
  13136. foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) {
  13137. if ($p['channel'] == $channel && $p['package'] == $package) {
  13138. $found = true;
  13139. break;
  13140. }
  13141. }
  13142. } else {
  13143. if (!isset($data['packages'])) {
  13144. $data['packages'] = array();
  13145. }
  13146. if (!isset($data['packages'][$depchannel])) {
  13147. $data['packages'][$depchannel] = array();
  13148. }
  13149. if (!isset($data['packages'][$depchannel][$dep['name']])) {
  13150. $data['packages'][$depchannel][$dep['name']] = array();
  13151. }
  13152. $found = false;
  13153. }
  13154. if (!$found) {
  13155. $data['packages'][$depchannel][$dep['name']][] = array(
  13156. 'channel' => $channel,
  13157. 'package' => $package
  13158. );
  13159. }
  13160. }
  13161. }
  13162. <?php
  13163. /**
  13164. * PEAR_Downloader, the PEAR Installer's download utility class
  13165. *
  13166. * PHP versions 4 and 5
  13167. *
  13168. * @category pear
  13169. * @package PEAR
  13170. * @author Greg Beaver <cellog@php.net>
  13171. * @author Stig Bakken <ssb@php.net>
  13172. * @author Tomas V. V. Cox <cox@idecnet.com>
  13173. * @author Martin Jansen <mj@php.net>
  13174. * @copyright 1997-2009 The Authors
  13175. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  13176. * @link http://pear.php.net/package/PEAR
  13177. * @since File available since Release 1.3.0
  13178. */
  13179. /**
  13180. * Needed for constants, extending
  13181. */
  13182. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  13183. require_once 'phar://go-pear.phar/' . 'PEAR/Proxy.php';
  13184. define('PEAR_INSTALLER_OK', 1);
  13185. define('PEAR_INSTALLER_FAILED', 0);
  13186. define('PEAR_INSTALLER_SKIPPED', -1);
  13187. define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
  13188. /**
  13189. * Administration class used to download anything from the internet (PEAR Packages,
  13190. * static URLs, xml files)
  13191. *
  13192. * @category pear
  13193. * @package PEAR
  13194. * @author Greg Beaver <cellog@php.net>
  13195. * @author Stig Bakken <ssb@php.net>
  13196. * @author Tomas V. V. Cox <cox@idecnet.com>
  13197. * @author Martin Jansen <mj@php.net>
  13198. * @copyright 1997-2009 The Authors
  13199. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  13200. * @version Release: 1.10.10
  13201. * @link http://pear.php.net/package/PEAR
  13202. * @since Class available since Release 1.3.0
  13203. */
  13204. class PEAR_Downloader extends PEAR_Common
  13205. {
  13206. /**
  13207. * @var PEAR_Registry
  13208. * @access private
  13209. */
  13210. var $_registry;
  13211. /**
  13212. * Preferred Installation State (snapshot, devel, alpha, beta, stable)
  13213. * @var string|null
  13214. * @access private
  13215. */
  13216. var $_preferredState;
  13217. /**
  13218. * Options from command-line passed to Install.
  13219. *
  13220. * Recognized options:<br />
  13221. * - onlyreqdeps : install all required dependencies as well
  13222. * - alldeps : install all dependencies, including optional
  13223. * - installroot : base relative path to install files in
  13224. * - force : force a download even if warnings would prevent it
  13225. * - nocompress : download uncompressed tarballs
  13226. * - configureoptions : additional configure options
  13227. * @see PEAR_Command_Install
  13228. * @access private
  13229. * @var array
  13230. */
  13231. var $_options;
  13232. /**
  13233. * Downloaded Packages after a call to download().
  13234. *
  13235. * Format of each entry:
  13236. *
  13237. * <code>
  13238. * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
  13239. * 'info' => array() // parsed package.xml
  13240. * );
  13241. * </code>
  13242. * @access private
  13243. * @var array
  13244. */
  13245. var $_downloadedPackages = array();
  13246. /**
  13247. * Packages slated for download.
  13248. *
  13249. * This is used to prevent downloading a package more than once should it be a dependency
  13250. * for two packages to be installed.
  13251. * Format of each entry:
  13252. *
  13253. * <pre>
  13254. * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
  13255. * );
  13256. * </pre>
  13257. * @access private
  13258. * @var array
  13259. */
  13260. var $_toDownload = array();
  13261. /**
  13262. * Array of every package installed, with names lower-cased.
  13263. *
  13264. * Format:
  13265. * <code>
  13266. * array('package1' => 0, 'package2' => 1, );
  13267. * </code>
  13268. * @var array
  13269. */
  13270. var $_installed = array();
  13271. /**
  13272. * @var array
  13273. * @access private
  13274. */
  13275. var $_errorStack = array();
  13276. /**
  13277. * @var boolean
  13278. * @access private
  13279. */
  13280. var $_internalDownload = false;
  13281. /**
  13282. * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
  13283. * @var array
  13284. * @access private
  13285. */
  13286. var $_packageSortTree;
  13287. /**
  13288. * Temporary directory, or configuration value where downloads will occur
  13289. * @var string
  13290. */
  13291. var $_downloadDir;
  13292. /**
  13293. * List of methods that can be called both statically and non-statically.
  13294. * @var array
  13295. */
  13296. protected static $bivalentMethods = array(
  13297. 'setErrorHandling' => true,
  13298. 'raiseError' => true,
  13299. 'throwError' => true,
  13300. 'pushErrorHandling' => true,
  13301. 'popErrorHandling' => true,
  13302. 'downloadHttp' => true,
  13303. );
  13304. /**
  13305. * @param PEAR_Frontend_*
  13306. * @param array
  13307. * @param PEAR_Config
  13308. */
  13309. function __construct($ui = null, $options = array(), $config = null)
  13310. {
  13311. parent::__construct();
  13312. $this->_options = $options;
  13313. if ($config !== null) {
  13314. $this->config = &$config;
  13315. $this->_preferredState = $this->config->get('preferred_state');
  13316. }
  13317. $this->ui = &$ui;
  13318. if (!$this->_preferredState) {
  13319. // don't inadvertently use a non-set preferred_state
  13320. $this->_preferredState = null;
  13321. }
  13322. if ($config !== null) {
  13323. if (isset($this->_options['installroot'])) {
  13324. $this->config->setInstallRoot($this->_options['installroot']);
  13325. }
  13326. $this->_registry = &$config->getRegistry();
  13327. }
  13328. if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
  13329. $this->_installed = $this->_registry->listAllPackages();
  13330. foreach ($this->_installed as $key => $unused) {
  13331. if (!count($unused)) {
  13332. continue;
  13333. }
  13334. $strtolower = function($a) { return strtolower($a); };
  13335. array_walk($this->_installed[$key], $strtolower);
  13336. }
  13337. }
  13338. }
  13339. /**
  13340. * Attempt to discover a channel's remote capabilities from
  13341. * its server name
  13342. * @param string
  13343. * @return boolean
  13344. */
  13345. function discover($channel)
  13346. {
  13347. $this->log(1, 'Attempting to discover channel "' . $channel . '"...');
  13348. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13349. $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
  13350. if (!class_exists('System')) {
  13351. require_once 'phar://go-pear.phar/' . 'System.php';
  13352. }
  13353. $tmpdir = $this->config->get('temp_dir');
  13354. $tmp = System::mktemp('-d -t "' . $tmpdir . '"');
  13355. $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false);
  13356. PEAR::popErrorHandling();
  13357. if (PEAR::isError($a)) {
  13358. // Attempt to fallback to https automatically.
  13359. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13360. $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...');
  13361. $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false);
  13362. PEAR::popErrorHandling();
  13363. if (PEAR::isError($a)) {
  13364. return false;
  13365. }
  13366. }
  13367. list($a, $lastmodified) = $a;
  13368. if (!class_exists('PEAR_ChannelFile')) {
  13369. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  13370. }
  13371. $b = new PEAR_ChannelFile;
  13372. if ($b->fromXmlFile($a)) {
  13373. unlink($a);
  13374. if ($this->config->get('auto_discover')) {
  13375. $this->_registry->addChannel($b, $lastmodified);
  13376. $alias = $b->getName();
  13377. if ($b->getName() == $this->_registry->channelName($b->getAlias())) {
  13378. $alias = $b->getAlias();
  13379. }
  13380. $this->log(1, 'Auto-discovered channel "' . $channel .
  13381. '", alias "' . $alias . '", adding to registry');
  13382. }
  13383. return true;
  13384. }
  13385. unlink($a);
  13386. return false;
  13387. }
  13388. /**
  13389. * For simpler unit-testing
  13390. * @param PEAR_Downloader
  13391. * @return PEAR_Downloader_Package
  13392. */
  13393. function newDownloaderPackage(&$t)
  13394. {
  13395. if (!class_exists('PEAR_Downloader_Package')) {
  13396. require_once 'phar://go-pear.phar/' . 'PEAR/Downloader/Package.php';
  13397. }
  13398. $a = new PEAR_Downloader_Package($t);
  13399. return $a;
  13400. }
  13401. /**
  13402. * For simpler unit-testing
  13403. * @param PEAR_Config
  13404. * @param array
  13405. * @param array
  13406. * @param int
  13407. */
  13408. function &getDependency2Object(&$c, $i, $p, $s)
  13409. {
  13410. if (!class_exists('PEAR_Dependency2')) {
  13411. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  13412. }
  13413. $z = new PEAR_Dependency2($c, $i, $p, $s);
  13414. return $z;
  13415. }
  13416. function &download($params)
  13417. {
  13418. if (!count($params)) {
  13419. $a = array();
  13420. return $a;
  13421. }
  13422. if (!isset($this->_registry)) {
  13423. $this->_registry = &$this->config->getRegistry();
  13424. }
  13425. $channelschecked = array();
  13426. // convert all parameters into PEAR_Downloader_Package objects
  13427. foreach ($params as $i => $param) {
  13428. $params[$i] = $this->newDownloaderPackage($this);
  13429. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13430. $err = $params[$i]->initialize($param);
  13431. PEAR::staticPopErrorHandling();
  13432. if (!$err) {
  13433. // skip parameters that were missed by preferred_state
  13434. continue;
  13435. }
  13436. if (PEAR::isError($err)) {
  13437. if (!isset($this->_options['soft']) && $err->getMessage() !== '') {
  13438. $this->log(0, $err->getMessage());
  13439. }
  13440. $params[$i] = false;
  13441. if (is_object($param)) {
  13442. $param = $param->getChannel() . '/' . $param->getPackage();
  13443. }
  13444. if (!isset($this->_options['soft'])) {
  13445. $this->log(2, 'Package "' . $param . '" is not valid');
  13446. }
  13447. // Message logged above in a specific verbose mode, passing null to not show up on CLI
  13448. $this->pushError(null, PEAR_INSTALLER_SKIPPED);
  13449. } else {
  13450. do {
  13451. if ($params[$i] && $params[$i]->getType() == 'local') {
  13452. // bug #7090 skip channel.xml check for local packages
  13453. break;
  13454. }
  13455. if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) &&
  13456. !isset($this->_options['offline'])
  13457. ) {
  13458. $channelschecked[$params[$i]->getChannel()] = true;
  13459. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13460. if (!class_exists('System')) {
  13461. require_once 'phar://go-pear.phar/' . 'System.php';
  13462. }
  13463. $curchannel = $this->_registry->getChannel($params[$i]->getChannel());
  13464. if (PEAR::isError($curchannel)) {
  13465. PEAR::staticPopErrorHandling();
  13466. return $this->raiseError($curchannel);
  13467. }
  13468. if (PEAR::isError($dir = $this->getDownloadDir())) {
  13469. PEAR::staticPopErrorHandling();
  13470. break;
  13471. }
  13472. $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel());
  13473. $url = 'http://' . $mirror . '/channel.xml';
  13474. $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified());
  13475. PEAR::staticPopErrorHandling();
  13476. if ($a === false) {
  13477. //channel.xml not modified
  13478. break;
  13479. } else if (PEAR::isError($a)) {
  13480. // Attempt fallback to https automatically
  13481. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13482. $a = $this->downloadHttp('https://' . $mirror .
  13483. '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified());
  13484. PEAR::staticPopErrorHandling();
  13485. if (PEAR::isError($a) || !$a) {
  13486. break;
  13487. }
  13488. }
  13489. $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' .
  13490. 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() .
  13491. '" to update');
  13492. }
  13493. } while (false);
  13494. if ($params[$i] && !isset($this->_options['downloadonly'])) {
  13495. if (isset($this->_options['packagingroot'])) {
  13496. $checkdir = $this->_prependPath(
  13497. $this->config->get('php_dir', null, $params[$i]->getChannel()),
  13498. $this->_options['packagingroot']);
  13499. } else {
  13500. $checkdir = $this->config->get('php_dir',
  13501. null, $params[$i]->getChannel());
  13502. }
  13503. while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) {
  13504. $checkdir = dirname($checkdir);
  13505. }
  13506. if ($checkdir == '.') {
  13507. $checkdir = '/';
  13508. }
  13509. if (!is_writeable($checkdir)) {
  13510. return PEAR::raiseError('Cannot install, php_dir for channel "' .
  13511. $params[$i]->getChannel() . '" is not writeable by the current user');
  13512. }
  13513. }
  13514. }
  13515. }
  13516. unset($channelschecked);
  13517. PEAR_Downloader_Package::removeDuplicates($params);
  13518. if (!count($params)) {
  13519. $a = array();
  13520. return $a;
  13521. }
  13522. if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) {
  13523. $reverify = true;
  13524. while ($reverify) {
  13525. $reverify = false;
  13526. foreach ($params as $i => $param) {
  13527. //PHP Bug 40768 / PEAR Bug #10944
  13528. //Nested foreaches fail in PHP 5.2.1
  13529. key($params);
  13530. $ret = $params[$i]->detectDependencies($params);
  13531. if (PEAR::isError($ret)) {
  13532. $reverify = true;
  13533. $params[$i] = false;
  13534. PEAR_Downloader_Package::removeDuplicates($params);
  13535. if (!isset($this->_options['soft'])) {
  13536. $this->log(0, $ret->getMessage());
  13537. }
  13538. continue 2;
  13539. }
  13540. }
  13541. }
  13542. }
  13543. if (isset($this->_options['offline'])) {
  13544. $this->log(3, 'Skipping dependency download check, --offline specified');
  13545. }
  13546. if (!count($params)) {
  13547. $a = array();
  13548. return $a;
  13549. }
  13550. while (PEAR_Downloader_Package::mergeDependencies($params));
  13551. PEAR_Downloader_Package::removeDuplicates($params, true);
  13552. $errorparams = array();
  13553. if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) {
  13554. if (count($errorparams)) {
  13555. foreach ($errorparams as $param) {
  13556. $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage());
  13557. $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED);
  13558. }
  13559. $a = array();
  13560. return $a;
  13561. }
  13562. }
  13563. PEAR_Downloader_Package::removeInstalled($params);
  13564. if (!count($params)) {
  13565. $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  13566. $a = array();
  13567. return $a;
  13568. }
  13569. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13570. $err = $this->analyzeDependencies($params);
  13571. PEAR::popErrorHandling();
  13572. if (!count($params)) {
  13573. $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  13574. $a = array();
  13575. return $a;
  13576. }
  13577. $ret = array();
  13578. $newparams = array();
  13579. if (isset($this->_options['pretend'])) {
  13580. return $params;
  13581. }
  13582. $somefailed = false;
  13583. foreach ($params as $i => $package) {
  13584. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13585. $pf = &$params[$i]->download();
  13586. PEAR::staticPopErrorHandling();
  13587. if (PEAR::isError($pf)) {
  13588. if (!isset($this->_options['soft'])) {
  13589. $this->log(1, $pf->getMessage());
  13590. $this->log(0, 'Error: cannot download "' .
  13591. $this->_registry->parsedPackageNameToString($package->getParsedPackage(),
  13592. true) .
  13593. '"');
  13594. }
  13595. $somefailed = true;
  13596. continue;
  13597. }
  13598. $newparams[] = &$params[$i];
  13599. $ret[] = array(
  13600. 'file' => $pf->getArchiveFile(),
  13601. 'info' => &$pf,
  13602. 'pkg' => $pf->getPackage()
  13603. );
  13604. }
  13605. if ($somefailed) {
  13606. // remove params that did not download successfully
  13607. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13608. $err = $this->analyzeDependencies($newparams, true);
  13609. PEAR::popErrorHandling();
  13610. if (!count($newparams)) {
  13611. $this->pushError('Download failed', PEAR_INSTALLER_FAILED);
  13612. $a = array();
  13613. return $a;
  13614. }
  13615. }
  13616. $this->_downloadedPackages = $ret;
  13617. return $newparams;
  13618. }
  13619. /**
  13620. * @param array all packages to be installed
  13621. */
  13622. function analyzeDependencies(&$params, $force = false)
  13623. {
  13624. if (isset($this->_options['downloadonly'])) {
  13625. return;
  13626. }
  13627. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13628. $redo = true;
  13629. $reset = $hasfailed = $failed = false;
  13630. while ($redo) {
  13631. $redo = false;
  13632. foreach ($params as $i => $param) {
  13633. $deps = $param->getDeps();
  13634. if (!$deps) {
  13635. $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  13636. $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  13637. $send = $param->getPackageFile();
  13638. $installcheck = $depchecker->validatePackage($send, $this, $params);
  13639. if (PEAR::isError($installcheck)) {
  13640. if (!isset($this->_options['soft'])) {
  13641. $this->log(0, $installcheck->getMessage());
  13642. }
  13643. $hasfailed = true;
  13644. $params[$i] = false;
  13645. $reset = true;
  13646. $redo = true;
  13647. $failed = false;
  13648. PEAR_Downloader_Package::removeDuplicates($params);
  13649. continue 2;
  13650. }
  13651. continue;
  13652. }
  13653. if (!$reset && $param->alreadyValidated() && !$force) {
  13654. continue;
  13655. }
  13656. if (count($deps)) {
  13657. $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  13658. $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  13659. $send = $param->getPackageFile();
  13660. if ($send === null) {
  13661. $send = $param->getDownloadURL();
  13662. }
  13663. $installcheck = $depchecker->validatePackage($send, $this, $params);
  13664. if (PEAR::isError($installcheck)) {
  13665. if (!isset($this->_options['soft'])) {
  13666. $this->log(0, $installcheck->getMessage());
  13667. }
  13668. $hasfailed = true;
  13669. $params[$i] = false;
  13670. $reset = true;
  13671. $redo = true;
  13672. $failed = false;
  13673. PEAR_Downloader_Package::removeDuplicates($params);
  13674. continue 2;
  13675. }
  13676. $failed = false;
  13677. if (isset($deps['required']) && is_array($deps['required'])) {
  13678. foreach ($deps['required'] as $type => $dep) {
  13679. // note: Dependency2 will never return a PEAR_Error if ignore-errors
  13680. // is specified, so soft is needed to turn off logging
  13681. if (!isset($dep[0])) {
  13682. if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep,
  13683. true, $params))) {
  13684. $failed = true;
  13685. if (!isset($this->_options['soft'])) {
  13686. $this->log(0, $e->getMessage());
  13687. }
  13688. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13689. if (!isset($this->_options['soft'])) {
  13690. $this->log(0, $e[0]);
  13691. }
  13692. }
  13693. } else {
  13694. foreach ($dep as $d) {
  13695. if (PEAR::isError($e =
  13696. $depchecker->{"validate{$type}Dependency"}($d,
  13697. true, $params))) {
  13698. $failed = true;
  13699. if (!isset($this->_options['soft'])) {
  13700. $this->log(0, $e->getMessage());
  13701. }
  13702. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13703. if (!isset($this->_options['soft'])) {
  13704. $this->log(0, $e[0]);
  13705. }
  13706. }
  13707. }
  13708. }
  13709. }
  13710. if (isset($deps['optional']) && is_array($deps['optional'])) {
  13711. foreach ($deps['optional'] as $type => $dep) {
  13712. if (!isset($dep[0])) {
  13713. if (PEAR::isError($e =
  13714. $depchecker->{"validate{$type}Dependency"}($dep,
  13715. false, $params))) {
  13716. $failed = true;
  13717. if (!isset($this->_options['soft'])) {
  13718. $this->log(0, $e->getMessage());
  13719. }
  13720. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13721. if (!isset($this->_options['soft'])) {
  13722. $this->log(0, $e[0]);
  13723. }
  13724. }
  13725. } else {
  13726. foreach ($dep as $d) {
  13727. if (PEAR::isError($e =
  13728. $depchecker->{"validate{$type}Dependency"}($d,
  13729. false, $params))) {
  13730. $failed = true;
  13731. if (!isset($this->_options['soft'])) {
  13732. $this->log(0, $e->getMessage());
  13733. }
  13734. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13735. if (!isset($this->_options['soft'])) {
  13736. $this->log(0, $e[0]);
  13737. }
  13738. }
  13739. }
  13740. }
  13741. }
  13742. }
  13743. $groupname = $param->getGroup();
  13744. if (isset($deps['group']) && $groupname) {
  13745. if (!isset($deps['group'][0])) {
  13746. $deps['group'] = array($deps['group']);
  13747. }
  13748. $found = false;
  13749. foreach ($deps['group'] as $group) {
  13750. if ($group['attribs']['name'] == $groupname) {
  13751. $found = true;
  13752. break;
  13753. }
  13754. }
  13755. if ($found) {
  13756. unset($group['attribs']);
  13757. foreach ($group as $type => $dep) {
  13758. if (!isset($dep[0])) {
  13759. if (PEAR::isError($e =
  13760. $depchecker->{"validate{$type}Dependency"}($dep,
  13761. false, $params))) {
  13762. $failed = true;
  13763. if (!isset($this->_options['soft'])) {
  13764. $this->log(0, $e->getMessage());
  13765. }
  13766. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13767. if (!isset($this->_options['soft'])) {
  13768. $this->log(0, $e[0]);
  13769. }
  13770. }
  13771. } else {
  13772. foreach ($dep as $d) {
  13773. if (PEAR::isError($e =
  13774. $depchecker->{"validate{$type}Dependency"}($d,
  13775. false, $params))) {
  13776. $failed = true;
  13777. if (!isset($this->_options['soft'])) {
  13778. $this->log(0, $e->getMessage());
  13779. }
  13780. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13781. if (!isset($this->_options['soft'])) {
  13782. $this->log(0, $e[0]);
  13783. }
  13784. }
  13785. }
  13786. }
  13787. }
  13788. }
  13789. }
  13790. } else {
  13791. foreach ($deps as $dep) {
  13792. if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
  13793. $failed = true;
  13794. if (!isset($this->_options['soft'])) {
  13795. $this->log(0, $e->getMessage());
  13796. }
  13797. } elseif (is_array($e) && !$param->alreadyValidated()) {
  13798. if (!isset($this->_options['soft'])) {
  13799. $this->log(0, $e[0]);
  13800. }
  13801. }
  13802. }
  13803. }
  13804. $params[$i]->setValidated();
  13805. }
  13806. if ($failed) {
  13807. $hasfailed = true;
  13808. $params[$i] = false;
  13809. $reset = true;
  13810. $redo = true;
  13811. $failed = false;
  13812. PEAR_Downloader_Package::removeDuplicates($params);
  13813. continue 2;
  13814. }
  13815. }
  13816. }
  13817. PEAR::staticPopErrorHandling();
  13818. if ($hasfailed && (isset($this->_options['ignore-errors']) ||
  13819. isset($this->_options['nodeps']))) {
  13820. // this is probably not needed, but just in case
  13821. if (!isset($this->_options['soft'])) {
  13822. $this->log(0, 'WARNING: dependencies failed');
  13823. }
  13824. }
  13825. }
  13826. /**
  13827. * Retrieve the directory that downloads will happen in
  13828. * @access private
  13829. * @return string
  13830. */
  13831. function getDownloadDir()
  13832. {
  13833. if (isset($this->_downloadDir)) {
  13834. return $this->_downloadDir;
  13835. }
  13836. $downloaddir = $this->config->get('download_dir');
  13837. if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) {
  13838. if (is_dir($downloaddir) && !is_writable($downloaddir)) {
  13839. $this->log(0, 'WARNING: configuration download directory "' . $downloaddir .
  13840. '" is not writeable. Change download_dir config variable to ' .
  13841. 'a writeable dir to avoid this warning');
  13842. }
  13843. if (!class_exists('System')) {
  13844. require_once 'phar://go-pear.phar/' . 'System.php';
  13845. }
  13846. if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
  13847. return $downloaddir;
  13848. }
  13849. $this->log(3, '+ tmp dir created at ' . $downloaddir);
  13850. }
  13851. if (!is_writable($downloaddir)) {
  13852. if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) ||
  13853. !is_writable($downloaddir)) {
  13854. return PEAR::raiseError('download directory "' . $downloaddir .
  13855. '" is not writeable. Change download_dir config variable to ' .
  13856. 'a writeable dir');
  13857. }
  13858. }
  13859. return $this->_downloadDir = $downloaddir;
  13860. }
  13861. function setDownloadDir($dir)
  13862. {
  13863. if (!@is_writable($dir)) {
  13864. if (PEAR::isError(System::mkdir(array('-p', $dir)))) {
  13865. return PEAR::raiseError('download directory "' . $dir .
  13866. '" is not writeable. Change download_dir config variable to ' .
  13867. 'a writeable dir');
  13868. }
  13869. }
  13870. $this->_downloadDir = $dir;
  13871. }
  13872. function configSet($key, $value, $layer = 'user', $channel = false)
  13873. {
  13874. $this->config->set($key, $value, $layer, $channel);
  13875. $this->_preferredState = $this->config->get('preferred_state', null, $channel);
  13876. if (!$this->_preferredState) {
  13877. // don't inadvertently use a non-set preferred_state
  13878. $this->_preferredState = null;
  13879. }
  13880. }
  13881. function setOptions($options)
  13882. {
  13883. $this->_options = $options;
  13884. }
  13885. function getOptions()
  13886. {
  13887. return $this->_options;
  13888. }
  13889. /**
  13890. * @param array output of {@link parsePackageName()}
  13891. * @access private
  13892. */
  13893. function _getPackageDownloadUrl($parr)
  13894. {
  13895. $curchannel = $this->config->get('default_channel');
  13896. $this->configSet('default_channel', $parr['channel']);
  13897. // getDownloadURL returns an array. On error, it only contains information
  13898. // on the latest release as array(version, info). On success it contains
  13899. // array(version, info, download url string)
  13900. $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  13901. if (!$this->_registry->channelExists($parr['channel'])) {
  13902. do {
  13903. if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) {
  13904. break;
  13905. }
  13906. $this->configSet('default_channel', $curchannel);
  13907. return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']);
  13908. } while (false);
  13909. }
  13910. $chan = $this->_registry->getChannel($parr['channel']);
  13911. if (PEAR::isError($chan)) {
  13912. return $chan;
  13913. }
  13914. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13915. $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']);
  13916. $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']);
  13917. // package is installed - use the installed release stability level
  13918. if (!isset($parr['state']) && $stability !== null) {
  13919. $state = $stability['release'];
  13920. }
  13921. PEAR::staticPopErrorHandling();
  13922. $base2 = false;
  13923. $preferred_mirror = $this->config->get('preferred_mirror');
  13924. if (!$chan->supportsREST($preferred_mirror) ||
  13925. (
  13926. !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror))
  13927. &&
  13928. !($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
  13929. )
  13930. ) {
  13931. return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.');
  13932. }
  13933. if ($base2) {
  13934. $rest = &$this->config->getREST('1.3', $this->_options);
  13935. $base = $base2;
  13936. } else {
  13937. $rest = &$this->config->getREST('1.0', $this->_options);
  13938. }
  13939. $downloadVersion = false;
  13940. if (!isset($parr['version']) && !isset($parr['state']) && $version
  13941. && !PEAR::isError($version)
  13942. && !isset($this->_options['downloadonly'])
  13943. ) {
  13944. $downloadVersion = $version;
  13945. }
  13946. $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName());
  13947. if (PEAR::isError($url)) {
  13948. $this->configSet('default_channel', $curchannel);
  13949. return $url;
  13950. }
  13951. if ($parr['channel'] != $curchannel) {
  13952. $this->configSet('default_channel', $curchannel);
  13953. }
  13954. if (!is_array($url)) {
  13955. return $url;
  13956. }
  13957. $url['raw'] = false; // no checking is necessary for REST
  13958. if (!is_array($url['info'])) {
  13959. return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  13960. 'this should never happen');
  13961. }
  13962. if (!isset($this->_options['force']) &&
  13963. !isset($this->_options['downloadonly']) &&
  13964. $version &&
  13965. !PEAR::isError($version) &&
  13966. !isset($parr['group'])
  13967. ) {
  13968. if (version_compare($version, $url['version'], '=')) {
  13969. return PEAR::raiseError($this->_registry->parsedPackageNameToString(
  13970. $parr, true) . ' is already installed and is the same as the ' .
  13971. 'released version ' . $url['version'], -976);
  13972. }
  13973. if (version_compare($version, $url['version'], '>')) {
  13974. return PEAR::raiseError($this->_registry->parsedPackageNameToString(
  13975. $parr, true) . ' is already installed and is newer than detected ' .
  13976. 'released version ' . $url['version'], -976);
  13977. }
  13978. }
  13979. if (isset($url['info']['required']) || $url['compatible']) {
  13980. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  13981. $pf = new PEAR_PackageFile_v2;
  13982. $pf->setRawChannel($parr['channel']);
  13983. if ($url['compatible']) {
  13984. $pf->setRawCompatible($url['compatible']);
  13985. }
  13986. } else {
  13987. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  13988. $pf = new PEAR_PackageFile_v1;
  13989. }
  13990. $pf->setRawPackage($url['package']);
  13991. $pf->setDeps($url['info']);
  13992. if ($url['compatible']) {
  13993. $pf->setCompatible($url['compatible']);
  13994. }
  13995. $pf->setRawState($url['stability']);
  13996. $url['info'] = &$pf;
  13997. if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  13998. $ext = '.tar';
  13999. } else {
  14000. $ext = '.tgz';
  14001. }
  14002. if (is_array($url) && isset($url['url'])) {
  14003. $url['url'] .= $ext;
  14004. }
  14005. return $url;
  14006. }
  14007. /**
  14008. * @param array dependency array
  14009. * @access private
  14010. */
  14011. function _getDepPackageDownloadUrl($dep, $parr)
  14012. {
  14013. $xsdversion = isset($dep['rel']) ? '1.0' : '2.0';
  14014. $curchannel = $this->config->get('default_channel');
  14015. if (isset($dep['uri'])) {
  14016. $xsdversion = '2.0';
  14017. $chan = $this->_registry->getChannel('__uri');
  14018. if (PEAR::isError($chan)) {
  14019. return $chan;
  14020. }
  14021. $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri');
  14022. $this->configSet('default_channel', '__uri');
  14023. } else {
  14024. if (isset($dep['channel'])) {
  14025. $remotechannel = $dep['channel'];
  14026. } else {
  14027. $remotechannel = 'pear.php.net';
  14028. }
  14029. if (!$this->_registry->channelExists($remotechannel)) {
  14030. do {
  14031. if ($this->config->get('auto_discover')) {
  14032. if ($this->discover($remotechannel)) {
  14033. break;
  14034. }
  14035. }
  14036. return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
  14037. } while (false);
  14038. }
  14039. $chan = $this->_registry->getChannel($remotechannel);
  14040. if (PEAR::isError($chan)) {
  14041. return $chan;
  14042. }
  14043. $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel);
  14044. $this->configSet('default_channel', $remotechannel);
  14045. }
  14046. $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  14047. if (isset($parr['state']) && isset($parr['version'])) {
  14048. unset($parr['state']);
  14049. }
  14050. if (isset($dep['uri'])) {
  14051. $info = $this->newDownloaderPackage($this);
  14052. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  14053. $err = $info->initialize($dep);
  14054. PEAR::staticPopErrorHandling();
  14055. if (!$err) {
  14056. // skip parameters that were missed by preferred_state
  14057. return PEAR::raiseError('Cannot initialize dependency');
  14058. }
  14059. if (PEAR::isError($err)) {
  14060. if (!isset($this->_options['soft'])) {
  14061. $this->log(0, $err->getMessage());
  14062. }
  14063. if (is_object($info)) {
  14064. $param = $info->getChannel() . '/' . $info->getPackage();
  14065. }
  14066. return PEAR::raiseError('Package "' . $param . '" is not valid');
  14067. }
  14068. return $info;
  14069. } elseif ($chan->supportsREST($this->config->get('preferred_mirror'))
  14070. &&
  14071. (
  14072. ($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror')))
  14073. ||
  14074. ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')))
  14075. )
  14076. ) {
  14077. if ($base2) {
  14078. $base = $base2;
  14079. $rest = &$this->config->getREST('1.3', $this->_options);
  14080. } else {
  14081. $rest = &$this->config->getREST('1.0', $this->_options);
  14082. }
  14083. $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr,
  14084. $state, $version, $chan->getName());
  14085. if (PEAR::isError($url)) {
  14086. return $url;
  14087. }
  14088. if ($parr['channel'] != $curchannel) {
  14089. $this->configSet('default_channel', $curchannel);
  14090. }
  14091. if (!is_array($url)) {
  14092. return $url;
  14093. }
  14094. $url['raw'] = false; // no checking is necessary for REST
  14095. if (!is_array($url['info'])) {
  14096. return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  14097. 'this should never happen');
  14098. }
  14099. if (isset($url['info']['required'])) {
  14100. if (!class_exists('PEAR_PackageFile_v2')) {
  14101. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  14102. }
  14103. $pf = new PEAR_PackageFile_v2;
  14104. $pf->setRawChannel($remotechannel);
  14105. } else {
  14106. if (!class_exists('PEAR_PackageFile_v1')) {
  14107. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  14108. }
  14109. $pf = new PEAR_PackageFile_v1;
  14110. }
  14111. $pf->setRawPackage($url['package']);
  14112. $pf->setDeps($url['info']);
  14113. if ($url['compatible']) {
  14114. $pf->setCompatible($url['compatible']);
  14115. }
  14116. $pf->setRawState($url['stability']);
  14117. $url['info'] = &$pf;
  14118. if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  14119. $ext = '.tar';
  14120. } else {
  14121. $ext = '.tgz';
  14122. }
  14123. if (is_array($url) && isset($url['url'])) {
  14124. $url['url'] .= $ext;
  14125. }
  14126. return $url;
  14127. }
  14128. return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.');
  14129. }
  14130. /**
  14131. * @deprecated in favor of _getPackageDownloadUrl
  14132. */
  14133. function getPackageDownloadUrl($package, $version = null, $channel = false)
  14134. {
  14135. if ($version) {
  14136. $package .= "-$version";
  14137. }
  14138. if ($this === null || $this->_registry === null) {
  14139. $package = "http://pear.php.net/get/$package";
  14140. } else {
  14141. $chan = $this->_registry->getChannel($channel);
  14142. if (PEAR::isError($chan)) {
  14143. return '';
  14144. }
  14145. $package = "http://" . $chan->getServer() . "/get/$package";
  14146. }
  14147. if (!extension_loaded("zlib")) {
  14148. $package .= '?uncompress=yes';
  14149. }
  14150. return $package;
  14151. }
  14152. /**
  14153. * Retrieve a list of downloaded packages after a call to {@link download()}.
  14154. *
  14155. * Also resets the list of downloaded packages.
  14156. * @return array
  14157. */
  14158. function getDownloadedPackages()
  14159. {
  14160. $ret = $this->_downloadedPackages;
  14161. $this->_downloadedPackages = array();
  14162. $this->_toDownload = array();
  14163. return $ret;
  14164. }
  14165. function _downloadCallback($msg, $params = null)
  14166. {
  14167. switch ($msg) {
  14168. case 'saveas':
  14169. $this->log(1, "downloading $params ...");
  14170. break;
  14171. case 'done':
  14172. $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes');
  14173. break;
  14174. case 'bytesread':
  14175. static $bytes;
  14176. if (empty($bytes)) {
  14177. $bytes = 0;
  14178. }
  14179. if (!($bytes % 10240)) {
  14180. $this->log(1, '.', false);
  14181. }
  14182. $bytes += $params;
  14183. break;
  14184. case 'start':
  14185. if($params[1] == -1) {
  14186. $length = "Unknown size";
  14187. } else {
  14188. $length = number_format($params[1], 0, '', ',')." bytes";
  14189. }
  14190. $this->log(1, "Starting to download {$params[0]} ($length)");
  14191. break;
  14192. }
  14193. if (method_exists($this->ui, '_downloadCallback'))
  14194. $this->ui->_downloadCallback($msg, $params);
  14195. }
  14196. function _prependPath($path, $prepend)
  14197. {
  14198. if (strlen($prepend) > 0) {
  14199. if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  14200. if (preg_match('/^[a-z]:/i', $prepend)) {
  14201. $prepend = substr($prepend, 2);
  14202. } elseif ($prepend[0] != '\\') {
  14203. $prepend = "\\$prepend";
  14204. }
  14205. $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  14206. } else {
  14207. $path = $prepend . $path;
  14208. }
  14209. }
  14210. return $path;
  14211. }
  14212. /**
  14213. * @param string
  14214. * @param integer
  14215. */
  14216. function pushError($errmsg, $code = -1)
  14217. {
  14218. array_push($this->_errorStack, array($errmsg, $code));
  14219. }
  14220. function getErrorMsgs()
  14221. {
  14222. $msgs = array();
  14223. $errs = $this->_errorStack;
  14224. foreach ($errs as $err) {
  14225. $msgs[] = $err[0];
  14226. }
  14227. $this->_errorStack = array();
  14228. return $msgs;
  14229. }
  14230. /**
  14231. * for BC
  14232. *
  14233. * @deprecated
  14234. */
  14235. function sortPkgDeps(&$packages, $uninstall = false)
  14236. {
  14237. $uninstall ?
  14238. $this->sortPackagesForUninstall($packages) :
  14239. $this->sortPackagesForInstall($packages);
  14240. }
  14241. /**
  14242. * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  14243. *
  14244. * This uses the topological sort method from graph theory, and the
  14245. * Structures_Graph package to properly sort dependencies for installation.
  14246. * @param array an array of downloaded PEAR_Downloader_Packages
  14247. * @return array array of array(packagefilename, package.xml contents)
  14248. */
  14249. function sortPackagesForInstall(&$packages)
  14250. {
  14251. require_once 'phar://go-pear.phar/' . 'Structures/Graph.php';
  14252. require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php';
  14253. require_once 'phar://go-pear.phar/' . 'Structures/Graph/Manipulator/TopologicalSorter.php';
  14254. $depgraph = new Structures_Graph(true);
  14255. $nodes = array();
  14256. $reg = &$this->config->getRegistry();
  14257. foreach ($packages as $i => $package) {
  14258. $pname = $reg->parsedPackageNameToString(
  14259. array(
  14260. 'channel' => $package->getChannel(),
  14261. 'package' => strtolower($package->getPackage()),
  14262. ));
  14263. $nodes[$pname] = new Structures_Graph_Node;
  14264. $nodes[$pname]->setData($packages[$i]);
  14265. $depgraph->addNode($nodes[$pname]);
  14266. }
  14267. $deplinks = array();
  14268. foreach ($nodes as $package => $node) {
  14269. $pf = &$node->getData();
  14270. $pdeps = $pf->getDeps(true);
  14271. if (!$pdeps) {
  14272. continue;
  14273. }
  14274. if ($pf->getPackagexmlVersion() == '1.0') {
  14275. foreach ($pdeps as $dep) {
  14276. if ($dep['type'] != 'pkg' ||
  14277. (isset($dep['optional']) && $dep['optional'] == 'yes')) {
  14278. continue;
  14279. }
  14280. $dname = $reg->parsedPackageNameToString(
  14281. array(
  14282. 'channel' => 'pear.php.net',
  14283. 'package' => strtolower($dep['name']),
  14284. ));
  14285. if (isset($nodes[$dname])) {
  14286. if (!isset($deplinks[$dname])) {
  14287. $deplinks[$dname] = array();
  14288. }
  14289. $deplinks[$dname][$package] = 1;
  14290. // dependency is in installed packages
  14291. continue;
  14292. }
  14293. $dname = $reg->parsedPackageNameToString(
  14294. array(
  14295. 'channel' => 'pecl.php.net',
  14296. 'package' => strtolower($dep['name']),
  14297. ));
  14298. if (isset($nodes[$dname])) {
  14299. if (!isset($deplinks[$dname])) {
  14300. $deplinks[$dname] = array();
  14301. }
  14302. $deplinks[$dname][$package] = 1;
  14303. // dependency is in installed packages
  14304. continue;
  14305. }
  14306. }
  14307. } else {
  14308. // the only ordering we care about is:
  14309. // 1) subpackages must be installed before packages that depend on them
  14310. // 2) required deps must be installed before packages that depend on them
  14311. if (isset($pdeps['required']['subpackage'])) {
  14312. $t = $pdeps['required']['subpackage'];
  14313. if (!isset($t[0])) {
  14314. $t = array($t);
  14315. }
  14316. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  14317. }
  14318. if (isset($pdeps['group'])) {
  14319. if (!isset($pdeps['group'][0])) {
  14320. $pdeps['group'] = array($pdeps['group']);
  14321. }
  14322. foreach ($pdeps['group'] as $group) {
  14323. if (isset($group['subpackage'])) {
  14324. $t = $group['subpackage'];
  14325. if (!isset($t[0])) {
  14326. $t = array($t);
  14327. }
  14328. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  14329. }
  14330. }
  14331. }
  14332. if (isset($pdeps['optional']['subpackage'])) {
  14333. $t = $pdeps['optional']['subpackage'];
  14334. if (!isset($t[0])) {
  14335. $t = array($t);
  14336. }
  14337. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  14338. }
  14339. if (isset($pdeps['required']['package'])) {
  14340. $t = $pdeps['required']['package'];
  14341. if (!isset($t[0])) {
  14342. $t = array($t);
  14343. }
  14344. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  14345. }
  14346. if (isset($pdeps['group'])) {
  14347. if (!isset($pdeps['group'][0])) {
  14348. $pdeps['group'] = array($pdeps['group']);
  14349. }
  14350. foreach ($pdeps['group'] as $group) {
  14351. if (isset($group['package'])) {
  14352. $t = $group['package'];
  14353. if (!isset($t[0])) {
  14354. $t = array($t);
  14355. }
  14356. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  14357. }
  14358. }
  14359. }
  14360. }
  14361. }
  14362. $this->_detectDepCycle($deplinks);
  14363. foreach ($deplinks as $dependent => $parents) {
  14364. foreach ($parents as $parent => $unused) {
  14365. $nodes[$dependent]->connectTo($nodes[$parent]);
  14366. }
  14367. }
  14368. $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph);
  14369. $ret = array();
  14370. for ($i = 0, $count = count($installOrder); $i < $count; $i++) {
  14371. foreach ($installOrder[$i] as $index => $sortedpackage) {
  14372. $data = &$installOrder[$i][$index]->getData();
  14373. $ret[] = &$nodes[$reg->parsedPackageNameToString(
  14374. array(
  14375. 'channel' => $data->getChannel(),
  14376. 'package' => strtolower($data->getPackage()),
  14377. ))]->getData();
  14378. }
  14379. }
  14380. $packages = $ret;
  14381. return;
  14382. }
  14383. /**
  14384. * Detect recursive links between dependencies and break the cycles
  14385. *
  14386. * @param array
  14387. * @access private
  14388. */
  14389. function _detectDepCycle(&$deplinks)
  14390. {
  14391. do {
  14392. $keepgoing = false;
  14393. foreach ($deplinks as $dep => $parents) {
  14394. foreach ($parents as $parent => $unused) {
  14395. // reset the parent cycle detector
  14396. $this->_testCycle(null, null, null);
  14397. if ($this->_testCycle($dep, $deplinks, $parent)) {
  14398. $keepgoing = true;
  14399. unset($deplinks[$dep][$parent]);
  14400. if (count($deplinks[$dep]) == 0) {
  14401. unset($deplinks[$dep]);
  14402. }
  14403. continue 3;
  14404. }
  14405. }
  14406. }
  14407. } while ($keepgoing);
  14408. }
  14409. function _testCycle($test, $deplinks, $dep)
  14410. {
  14411. static $visited = array();
  14412. if ($test === null) {
  14413. $visited = array();
  14414. return;
  14415. }
  14416. // this happens when a parent has a dep cycle on another dependency
  14417. // but the child is not part of the cycle
  14418. if (isset($visited[$dep])) {
  14419. return false;
  14420. }
  14421. $visited[$dep] = 1;
  14422. if ($test == $dep) {
  14423. return true;
  14424. }
  14425. if (isset($deplinks[$dep])) {
  14426. if (in_array($test, array_keys($deplinks[$dep]), true)) {
  14427. return true;
  14428. }
  14429. foreach ($deplinks[$dep] as $parent => $unused) {
  14430. if ($this->_testCycle($test, $deplinks, $parent)) {
  14431. return true;
  14432. }
  14433. }
  14434. }
  14435. return false;
  14436. }
  14437. /**
  14438. * Set up the dependency for installation parsing
  14439. *
  14440. * @param array $t dependency information
  14441. * @param PEAR_Registry $reg
  14442. * @param array $deplinks list of dependency links already established
  14443. * @param array $nodes all existing package nodes
  14444. * @param string $package parent package name
  14445. * @access private
  14446. */
  14447. function _setupGraph($t, $reg, &$deplinks, &$nodes, $package)
  14448. {
  14449. foreach ($t as $dep) {
  14450. $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel'];
  14451. $dname = $reg->parsedPackageNameToString(
  14452. array(
  14453. 'channel' => $depchannel,
  14454. 'package' => strtolower($dep['name']),
  14455. ));
  14456. if (isset($nodes[$dname])) {
  14457. if (!isset($deplinks[$dname])) {
  14458. $deplinks[$dname] = array();
  14459. }
  14460. $deplinks[$dname][$package] = 1;
  14461. }
  14462. }
  14463. }
  14464. function _dependsOn($a, $b)
  14465. {
  14466. return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b);
  14467. }
  14468. function _checkDepTree($channel, $package, $b, $checked = array())
  14469. {
  14470. $checked[$channel][$package] = true;
  14471. if (!isset($this->_depTree[$channel][$package])) {
  14472. return false;
  14473. }
  14474. if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())]
  14475. [strtolower($b->getPackage())])) {
  14476. return true;
  14477. }
  14478. foreach ($this->_depTree[$channel][$package] as $ch => $packages) {
  14479. foreach ($packages as $pa => $true) {
  14480. if ($this->_checkDepTree($ch, $pa, $b, $checked)) {
  14481. return true;
  14482. }
  14483. }
  14484. }
  14485. return false;
  14486. }
  14487. function _sortInstall($a, $b)
  14488. {
  14489. if (!$a->getDeps() && !$b->getDeps()) {
  14490. return 0; // neither package has dependencies, order is insignificant
  14491. }
  14492. if ($a->getDeps() && !$b->getDeps()) {
  14493. return 1; // $a must be installed after $b because $a has dependencies
  14494. }
  14495. if (!$a->getDeps() && $b->getDeps()) {
  14496. return -1; // $b must be installed after $a because $b has dependencies
  14497. }
  14498. // both packages have dependencies
  14499. if ($this->_dependsOn($a, $b)) {
  14500. return 1;
  14501. }
  14502. if ($this->_dependsOn($b, $a)) {
  14503. return -1;
  14504. }
  14505. return 0;
  14506. }
  14507. /**
  14508. * Download a file through HTTP. Considers suggested file name in
  14509. * Content-disposition: header and can run a callback function for
  14510. * different events. The callback will be called with two
  14511. * parameters: the callback type, and parameters. The implemented
  14512. * callback types are:
  14513. *
  14514. * 'setup' called at the very beginning, parameter is a UI object
  14515. * that should be used for all output
  14516. * 'message' the parameter is a string with an informational message
  14517. * 'saveas' may be used to save with a different file name, the
  14518. * parameter is the filename that is about to be used.
  14519. * If a 'saveas' callback returns a non-empty string,
  14520. * that file name will be used as the filename instead.
  14521. * Note that $save_dir will not be affected by this, only
  14522. * the basename of the file.
  14523. * 'start' download is starting, parameter is number of bytes
  14524. * that are expected, or -1 if unknown
  14525. * 'bytesread' parameter is the number of bytes read so far
  14526. * 'done' download is complete, parameter is the total number
  14527. * of bytes read
  14528. * 'connfailed' if the TCP/SSL connection fails, this callback is called
  14529. * with array(host,port,errno,errmsg)
  14530. * 'writefailed' if writing to disk fails, this callback is called
  14531. * with array(destfile,errmsg)
  14532. *
  14533. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  14534. * setting), the proxy will be used.
  14535. *
  14536. * @param string $url the URL to download
  14537. * @param object $ui PEAR_Frontend_* instance
  14538. * @param object $config PEAR_Config instance
  14539. * @param string $save_dir directory to save file in
  14540. * @param mixed $callback function/method to call for status
  14541. * updates
  14542. * @param false|string|array $lastmodified header values to check against for caching
  14543. * use false to return the header values from this download
  14544. * @param false|array $accept Accept headers to send
  14545. * @param false|string $channel Channel to use for retrieving authentication
  14546. * @return mixed Returns the full path of the downloaded file or a PEAR
  14547. * error on failure. If the error is caused by
  14548. * socket-related errors, the error object will
  14549. * have the fsockopen error code available through
  14550. * getCode(). If caching is requested, then return the header
  14551. * values.
  14552. * If $lastmodified was given and the there are no changes,
  14553. * boolean false is returned.
  14554. *
  14555. * @access public
  14556. */
  14557. public static function _downloadHttp(
  14558. $object, $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
  14559. $accept = false, $channel = false
  14560. ) {
  14561. static $redirect = 0;
  14562. // always reset , so we are clean case of error
  14563. $wasredirect = $redirect;
  14564. $redirect = 0;
  14565. if ($callback) {
  14566. call_user_func($callback, 'setup', array(&$ui));
  14567. }
  14568. $info = parse_url($url);
  14569. if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
  14570. return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
  14571. }
  14572. if (!isset($info['host'])) {
  14573. return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
  14574. }
  14575. $host = isset($info['host']) ? $info['host'] : null;
  14576. $port = isset($info['port']) ? $info['port'] : null;
  14577. $path = isset($info['path']) ? $info['path'] : null;
  14578. if ($object !== null) {
  14579. $config = $object->config;
  14580. } else {
  14581. $config = &PEAR_Config::singleton();
  14582. }
  14583. $proxy = new PEAR_Proxy($config);
  14584. if ($proxy->isProxyConfigured() && $callback) {
  14585. call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
  14586. }
  14587. if (empty($port)) {
  14588. $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
  14589. }
  14590. $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
  14591. $secure = ($scheme == 'https');
  14592. $fp = $proxy->openSocket($host, $port, $secure);
  14593. if (PEAR::isError($fp)) {
  14594. if ($callback) {
  14595. $errno = $fp->getCode();
  14596. $errstr = $fp->getMessage();
  14597. call_user_func($callback, 'connfailed', array($host, $port,
  14598. $errno, $errstr));
  14599. }
  14600. return $fp;
  14601. }
  14602. $requestPath = $path;
  14603. if ($proxy->isProxyConfigured()) {
  14604. $requestPath = $url;
  14605. }
  14606. if ($lastmodified === false || $lastmodified) {
  14607. $request = "GET $requestPath HTTP/1.1\r\n";
  14608. } else {
  14609. $request = "GET $requestPath HTTP/1.0\r\n";
  14610. }
  14611. $request .= "Host: $host\r\n";
  14612. $ifmodifiedsince = '';
  14613. if (is_array($lastmodified)) {
  14614. if (isset($lastmodified['Last-Modified'])) {
  14615. $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
  14616. }
  14617. if (isset($lastmodified['ETag'])) {
  14618. $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
  14619. }
  14620. } else {
  14621. $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
  14622. }
  14623. $request .= $ifmodifiedsince .
  14624. "User-Agent: PEAR/1.10.10/PHP/" . PHP_VERSION . "\r\n";
  14625. if ($object !== null) { // only pass in authentication for non-static calls
  14626. $username = $config->get('username', null, $channel);
  14627. $password = $config->get('password', null, $channel);
  14628. if ($username && $password) {
  14629. $tmp = base64_encode("$username:$password");
  14630. $request .= "Authorization: Basic $tmp\r\n";
  14631. }
  14632. }
  14633. $proxyAuth = $proxy->getProxyAuth();
  14634. if ($proxyAuth) {
  14635. $request .= 'Proxy-Authorization: Basic ' .
  14636. $proxyAuth . "\r\n";
  14637. }
  14638. if ($accept) {
  14639. $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
  14640. }
  14641. $request .= "Connection: close\r\n";
  14642. $request .= "\r\n";
  14643. fwrite($fp, $request);
  14644. $headers = array();
  14645. $reply = 0;
  14646. while (trim($line = fgets($fp, 1024))) {
  14647. if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
  14648. $headers[strtolower($matches[1])] = trim($matches[2]);
  14649. } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  14650. $reply = (int)$matches[1];
  14651. if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
  14652. return false;
  14653. }
  14654. if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
  14655. return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)");
  14656. }
  14657. }
  14658. }
  14659. if ($reply != 200) {
  14660. if (!isset($headers['location'])) {
  14661. return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)");
  14662. }
  14663. if ($wasredirect > 4) {
  14664. return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)");
  14665. }
  14666. $redirect = $wasredirect + 1;
  14667. return static::_downloadHttp($object, $headers['location'],
  14668. $ui, $save_dir, $callback, $lastmodified, $accept);
  14669. }
  14670. if (isset($headers['content-disposition']) &&
  14671. preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) {
  14672. $save_as = basename($matches[1]);
  14673. } else {
  14674. $save_as = basename($url);
  14675. }
  14676. if ($callback) {
  14677. $tmp = call_user_func($callback, 'saveas', $save_as);
  14678. if ($tmp) {
  14679. $save_as = $tmp;
  14680. }
  14681. }
  14682. $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
  14683. if (is_link($dest_file)) {
  14684. return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $dest_file . ' as it is symlinked to ' . readlink($dest_file) . ' - Possible symlink attack');
  14685. }
  14686. if (!$wp = @fopen($dest_file, 'wb')) {
  14687. fclose($fp);
  14688. if ($callback) {
  14689. call_user_func($callback, 'writefailed',
  14690. array($dest_file, error_get_last()["message"]));
  14691. }
  14692. return PEAR::raiseError("could not open $dest_file for writing");
  14693. }
  14694. $length = isset($headers['content-length']) ? $headers['content-length'] : -1;
  14695. $bytes = 0;
  14696. if ($callback) {
  14697. call_user_func($callback, 'start', array(basename($dest_file), $length));
  14698. }
  14699. while ($data = fread($fp, 1024)) {
  14700. $bytes += strlen($data);
  14701. if ($callback) {
  14702. call_user_func($callback, 'bytesread', $bytes);
  14703. }
  14704. if (!@fwrite($wp, $data)) {
  14705. fclose($fp);
  14706. if ($callback) {
  14707. call_user_func($callback, 'writefailed',
  14708. array($dest_file, error_get_last()["message"]));
  14709. }
  14710. return PEAR::raiseError(
  14711. "$dest_file: write failed (" . error_get_last()["message"] . ")");
  14712. }
  14713. }
  14714. fclose($fp);
  14715. fclose($wp);
  14716. if ($callback) {
  14717. call_user_func($callback, 'done', $bytes);
  14718. }
  14719. if ($lastmodified === false || $lastmodified) {
  14720. if (isset($headers['etag'])) {
  14721. $lastmodified = array('ETag' => $headers['etag']);
  14722. }
  14723. if (isset($headers['last-modified'])) {
  14724. if (is_array($lastmodified)) {
  14725. $lastmodified['Last-Modified'] = $headers['last-modified'];
  14726. } else {
  14727. $lastmodified = $headers['last-modified'];
  14728. }
  14729. }
  14730. return array($dest_file, $lastmodified, $headers);
  14731. }
  14732. return $dest_file;
  14733. }
  14734. }
  14735. <?php
  14736. /**
  14737. * PEAR_Downloader_Package
  14738. *
  14739. * PHP versions 4 and 5
  14740. *
  14741. * @category pear
  14742. * @package PEAR
  14743. * @author Greg Beaver <cellog@php.net>
  14744. * @copyright 1997-2009 The Authors
  14745. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  14746. * @link http://pear.php.net/package/PEAR
  14747. * @since File available since Release 1.4.0a1
  14748. */
  14749. /**
  14750. * Error code when parameter initialization fails because no releases
  14751. * exist within preferred_state, but releases do exist
  14752. */
  14753. define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  14754. /**
  14755. * Error code when parameter initialization fails because no releases
  14756. * exist that will work with the existing PHP version
  14757. */
  14758. define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
  14759. /**
  14760. * Coordinates download parameters and manages their dependencies
  14761. * prior to downloading them.
  14762. *
  14763. * Input can come from three sources:
  14764. *
  14765. * - local files (archives or package.xml)
  14766. * - remote files (downloadable urls)
  14767. * - abstract package names
  14768. *
  14769. * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  14770. * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  14771. * format returned of dependencies is slightly different from that used in package.xml.
  14772. *
  14773. * This class hides the differences between these elements, and makes automatic
  14774. * dependency resolution a piece of cake. It also manages conflicts when
  14775. * two classes depend on incompatible dependencies, or differing versions of the same
  14776. * package dependency. In addition, download will not be attempted if the php version is
  14777. * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  14778. * installed.
  14779. * @category pear
  14780. * @package PEAR
  14781. * @author Greg Beaver <cellog@php.net>
  14782. * @copyright 1997-2009 The Authors
  14783. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  14784. * @version Release: 1.10.10
  14785. * @link http://pear.php.net/package/PEAR
  14786. * @since Class available since Release 1.4.0a1
  14787. */
  14788. class PEAR_Downloader_Package
  14789. {
  14790. /**
  14791. * @var PEAR_Downloader
  14792. */
  14793. var $_downloader;
  14794. /**
  14795. * @var PEAR_Config
  14796. */
  14797. var $_config;
  14798. /**
  14799. * @var PEAR_Registry
  14800. */
  14801. var $_registry;
  14802. /**
  14803. * Used to implement packagingroot properly
  14804. * @var PEAR_Registry
  14805. */
  14806. var $_installRegistry;
  14807. /**
  14808. * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  14809. */
  14810. var $_packagefile;
  14811. /**
  14812. * @var array
  14813. */
  14814. var $_parsedname;
  14815. /**
  14816. * @var array
  14817. */
  14818. var $_downloadURL;
  14819. /**
  14820. * @var array
  14821. */
  14822. var $_downloadDeps = array();
  14823. /**
  14824. * @var boolean
  14825. */
  14826. var $_valid = false;
  14827. /**
  14828. * @var boolean
  14829. */
  14830. var $_analyzed = false;
  14831. /**
  14832. * if this or a parent package was invoked with Package-state, this is set to the
  14833. * state variable.
  14834. *
  14835. * This allows temporary reassignment of preferred_state for a parent package and all of
  14836. * its dependencies.
  14837. * @var string|false
  14838. */
  14839. var $_explicitState = false;
  14840. /**
  14841. * If this package is invoked with Package#group, this variable will be true
  14842. */
  14843. var $_explicitGroup = false;
  14844. /**
  14845. * Package type local|url
  14846. * @var string
  14847. */
  14848. var $_type;
  14849. /**
  14850. * Contents of package.xml, if downloaded from a remote channel
  14851. * @var string|false
  14852. * @access private
  14853. */
  14854. var $_rawpackagefile;
  14855. /**
  14856. * @var boolean
  14857. * @access private
  14858. */
  14859. var $_validated = false;
  14860. /**
  14861. * @param PEAR_Downloader
  14862. */
  14863. function __construct(&$downloader)
  14864. {
  14865. $this->_downloader = &$downloader;
  14866. $this->_config = &$this->_downloader->config;
  14867. $this->_registry = &$this->_config->getRegistry();
  14868. $options = $downloader->getOptions();
  14869. if (isset($options['packagingroot'])) {
  14870. $this->_config->setInstallRoot($options['packagingroot']);
  14871. $this->_installRegistry = &$this->_config->getRegistry();
  14872. $this->_config->setInstallRoot(false);
  14873. } else {
  14874. $this->_installRegistry = &$this->_registry;
  14875. }
  14876. $this->_valid = $this->_analyzed = false;
  14877. }
  14878. /**
  14879. * Parse the input and determine whether this is a local file, a remote uri, or an
  14880. * abstract package name.
  14881. *
  14882. * This is the heart of the PEAR_Downloader_Package(), and is used in
  14883. * {@link PEAR_Downloader::download()}
  14884. * @param string
  14885. * @return bool|PEAR_Error
  14886. */
  14887. function initialize($param)
  14888. {
  14889. $origErr = $this->_fromFile($param);
  14890. if ($this->_valid) {
  14891. return true;
  14892. }
  14893. $options = $this->_downloader->getOptions();
  14894. if (isset($options['offline'])) {
  14895. if (PEAR::isError($origErr) && !isset($options['soft'])) {
  14896. foreach ($origErr->getUserInfo() as $userInfo) {
  14897. if (isset($userInfo['message'])) {
  14898. $this->_downloader->log(0, $userInfo['message']);
  14899. }
  14900. }
  14901. $this->_downloader->log(0, $origErr->getMessage());
  14902. }
  14903. return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
  14904. }
  14905. $err = $this->_fromUrl($param);
  14906. if (PEAR::isError($err) || !$this->_valid) {
  14907. if ($this->_type == 'url') {
  14908. if (PEAR::isError($err) && !isset($options['soft'])) {
  14909. $this->_downloader->log(0, $err->getMessage());
  14910. }
  14911. return PEAR::raiseError("Invalid or missing remote package file");
  14912. }
  14913. $err = $this->_fromString($param);
  14914. if (PEAR::isError($err) || !$this->_valid) {
  14915. if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
  14916. return false; // instruct the downloader to silently skip
  14917. }
  14918. if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) {
  14919. if (is_array($origErr->getUserInfo())) {
  14920. foreach ($origErr->getUserInfo() as $err) {
  14921. if (is_array($err)) {
  14922. $err = $err['message'];
  14923. }
  14924. if (!isset($options['soft'])) {
  14925. $this->_downloader->log(0, $err);
  14926. }
  14927. }
  14928. }
  14929. if (!isset($options['soft'])) {
  14930. $this->_downloader->log(0, $origErr->getMessage());
  14931. }
  14932. if (is_array($param)) {
  14933. $param = $this->_registry->parsedPackageNameToString($param, true);
  14934. }
  14935. if (!isset($options['soft'])) {
  14936. $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
  14937. }
  14938. // Passing no message back - already logged above
  14939. return PEAR::raiseError();
  14940. }
  14941. if (PEAR::isError($err) && !isset($options['soft'])) {
  14942. $this->_downloader->log(0, $err->getMessage());
  14943. }
  14944. if (is_array($param)) {
  14945. $param = $this->_registry->parsedPackageNameToString($param, true);
  14946. }
  14947. if (!isset($options['soft'])) {
  14948. $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
  14949. }
  14950. // Passing no message back - already logged above
  14951. return PEAR::raiseError();
  14952. }
  14953. }
  14954. return true;
  14955. }
  14956. /**
  14957. * Retrieve any non-local packages
  14958. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
  14959. */
  14960. function &download()
  14961. {
  14962. if (isset($this->_packagefile)) {
  14963. return $this->_packagefile;
  14964. }
  14965. if (isset($this->_downloadURL['url'])) {
  14966. $this->_isvalid = false;
  14967. $info = $this->getParsedPackage();
  14968. foreach ($info as $i => $p) {
  14969. $info[$i] = strtolower($p);
  14970. }
  14971. $err = $this->_fromUrl($this->_downloadURL['url'],
  14972. $this->_registry->parsedPackageNameToString($this->_parsedname, true));
  14973. $newinfo = $this->getParsedPackage();
  14974. foreach ($newinfo as $i => $p) {
  14975. $newinfo[$i] = strtolower($p);
  14976. }
  14977. if ($info != $newinfo) {
  14978. do {
  14979. if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') {
  14980. $info['channel'] = 'pear.php.net';
  14981. if ($info == $newinfo) {
  14982. // skip the channel check if a pecl package says it's a PEAR package
  14983. break;
  14984. }
  14985. }
  14986. if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') {
  14987. $info['channel'] = 'pecl.php.net';
  14988. if ($info == $newinfo) {
  14989. // skip the channel check if a pecl package says it's a PEAR package
  14990. break;
  14991. }
  14992. }
  14993. return PEAR::raiseError('CRITICAL ERROR: We are ' .
  14994. $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
  14995. 'downloaded claims to be ' .
  14996. $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
  14997. } while (false);
  14998. }
  14999. if (PEAR::isError($err) || !$this->_valid) {
  15000. return $err;
  15001. }
  15002. }
  15003. $this->_type = 'local';
  15004. return $this->_packagefile;
  15005. }
  15006. function &getPackageFile()
  15007. {
  15008. return $this->_packagefile;
  15009. }
  15010. function &getDownloader()
  15011. {
  15012. return $this->_downloader;
  15013. }
  15014. function getType()
  15015. {
  15016. return $this->_type;
  15017. }
  15018. /**
  15019. * Like {@link initialize()}, but operates on a dependency
  15020. */
  15021. function fromDepURL($dep)
  15022. {
  15023. $this->_downloadURL = $dep;
  15024. if (isset($dep['uri'])) {
  15025. $options = $this->_downloader->getOptions();
  15026. if (!extension_loaded("zlib") || isset($options['nocompress'])) {
  15027. $ext = '.tar';
  15028. } else {
  15029. $ext = '.tgz';
  15030. }
  15031. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15032. $err = $this->_fromUrl($dep['uri'] . $ext);
  15033. PEAR::popErrorHandling();
  15034. if (PEAR::isError($err)) {
  15035. if (!isset($options['soft'])) {
  15036. $this->_downloader->log(0, $err->getMessage());
  15037. }
  15038. return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
  15039. 'cannot download');
  15040. }
  15041. } else {
  15042. $this->_parsedname =
  15043. array(
  15044. 'package' => $dep['info']->getPackage(),
  15045. 'channel' => $dep['info']->getChannel(),
  15046. 'version' => $dep['version']
  15047. );
  15048. if (!isset($dep['nodefault'])) {
  15049. $this->_parsedname['group'] = 'default'; // download the default dependency group
  15050. $this->_explicitGroup = false;
  15051. }
  15052. $this->_rawpackagefile = $dep['raw'];
  15053. }
  15054. }
  15055. function detectDependencies($params)
  15056. {
  15057. $options = $this->_downloader->getOptions();
  15058. if (isset($options['downloadonly'])) {
  15059. return;
  15060. }
  15061. if (isset($options['offline'])) {
  15062. $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
  15063. return;
  15064. }
  15065. $pname = $this->getParsedPackage();
  15066. if (!$pname) {
  15067. return;
  15068. }
  15069. $deps = $this->getDeps();
  15070. if (!$deps) {
  15071. return;
  15072. }
  15073. if (isset($deps['required'])) { // package.xml 2.0
  15074. return $this->_detect2($deps, $pname, $options, $params);
  15075. }
  15076. return $this->_detect1($deps, $pname, $options, $params);
  15077. }
  15078. function setValidated()
  15079. {
  15080. $this->_validated = true;
  15081. }
  15082. function alreadyValidated()
  15083. {
  15084. return $this->_validated;
  15085. }
  15086. /**
  15087. * Remove packages to be downloaded that are already installed
  15088. * @param array of PEAR_Downloader_Package objects
  15089. */
  15090. public static function removeInstalled(&$params)
  15091. {
  15092. if (!isset($params[0])) {
  15093. return;
  15094. }
  15095. $options = $params[0]->_downloader->getOptions();
  15096. if (!isset($options['downloadonly'])) {
  15097. foreach ($params as $i => $param) {
  15098. $package = $param->getPackage();
  15099. $channel = $param->getChannel();
  15100. // remove self if already installed with this version
  15101. // this does not need any pecl magic - we only remove exact matches
  15102. if ($param->_installRegistry->packageExists($package, $channel)) {
  15103. $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel);
  15104. if (version_compare($packageVersion, $param->getVersion(), '==')) {
  15105. if (!isset($options['force']) && !isset($options['packagingroot'])) {
  15106. $info = $param->getParsedPackage();
  15107. unset($info['version']);
  15108. unset($info['state']);
  15109. if (!isset($options['soft'])) {
  15110. $param->_downloader->log(1, 'Skipping package "' .
  15111. $param->getShortName() .
  15112. '", already installed as version ' . $packageVersion);
  15113. }
  15114. $params[$i] = false;
  15115. }
  15116. } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
  15117. !isset($options['soft']) && !isset($options['packagingroot'])) {
  15118. $info = $param->getParsedPackage();
  15119. $param->_downloader->log(1, 'Skipping package "' .
  15120. $param->getShortName() .
  15121. '", already installed as version ' . $packageVersion);
  15122. $params[$i] = false;
  15123. }
  15124. }
  15125. }
  15126. }
  15127. PEAR_Downloader_Package::removeDuplicates($params);
  15128. }
  15129. function _detect2($deps, $pname, $options, $params)
  15130. {
  15131. $this->_downloadDeps = array();
  15132. $groupnotfound = false;
  15133. foreach (array('package', 'subpackage') as $packagetype) {
  15134. // get required dependency group
  15135. if (isset($deps['required'][$packagetype])) {
  15136. if (isset($deps['required'][$packagetype][0])) {
  15137. foreach ($deps['required'][$packagetype] as $dep) {
  15138. if (isset($dep['conflicts'])) {
  15139. // skip any package that this package conflicts with
  15140. continue;
  15141. }
  15142. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  15143. if (is_array($ret)) {
  15144. $this->_downloadDeps[] = $ret;
  15145. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  15146. $this->_downloader->log(0, $ret->getMessage());
  15147. }
  15148. }
  15149. } else {
  15150. $dep = $deps['required'][$packagetype];
  15151. if (!isset($dep['conflicts'])) {
  15152. // skip any package that this package conflicts with
  15153. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  15154. if (is_array($ret)) {
  15155. $this->_downloadDeps[] = $ret;
  15156. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  15157. $this->_downloader->log(0, $ret->getMessage());
  15158. }
  15159. }
  15160. }
  15161. }
  15162. // get optional dependency group, if any
  15163. if (isset($deps['optional'][$packagetype])) {
  15164. $skipnames = array();
  15165. if (!isset($deps['optional'][$packagetype][0])) {
  15166. $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
  15167. }
  15168. foreach ($deps['optional'][$packagetype] as $dep) {
  15169. $skip = false;
  15170. if (!isset($options['alldeps'])) {
  15171. $dep['package'] = $dep['name'];
  15172. if (!isset($options['soft'])) {
  15173. $this->_downloader->log(3, 'Notice: package "' .
  15174. $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
  15175. true) . '" optional dependency "' .
  15176. $this->_registry->parsedPackageNameToString(array('package' =>
  15177. $dep['name'], 'channel' => 'pear.php.net'), true) .
  15178. '" will not be automatically downloaded');
  15179. }
  15180. $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
  15181. $skip = true;
  15182. unset($dep['package']);
  15183. }
  15184. $ret = $this->_detect2Dep($dep, $pname, 'optional', $params);
  15185. if (PEAR::isError($ret) && !isset($options['soft'])) {
  15186. $this->_downloader->log(0, $ret->getMessage());
  15187. }
  15188. if (!$ret) {
  15189. $dep['package'] = $dep['name'];
  15190. $skip = count($skipnames) ?
  15191. $skipnames[count($skipnames) - 1] : '';
  15192. if ($skip ==
  15193. $this->_registry->parsedPackageNameToString($dep, true)) {
  15194. array_pop($skipnames);
  15195. }
  15196. }
  15197. if (!$skip && is_array($ret)) {
  15198. $this->_downloadDeps[] = $ret;
  15199. }
  15200. }
  15201. if (count($skipnames)) {
  15202. if (!isset($options['soft'])) {
  15203. $this->_downloader->log(1, 'Did not download optional dependencies: ' .
  15204. implode(', ', $skipnames) .
  15205. ', use --alldeps to download automatically');
  15206. }
  15207. }
  15208. }
  15209. // get requested dependency group, if any
  15210. $groupname = $this->getGroup();
  15211. $explicit = $this->_explicitGroup;
  15212. if (!$groupname) {
  15213. if (!$this->canDefault()) {
  15214. continue;
  15215. }
  15216. $groupname = 'default'; // try the default dependency group
  15217. }
  15218. if ($groupnotfound) {
  15219. continue;
  15220. }
  15221. if (isset($deps['group'])) {
  15222. if (isset($deps['group']['attribs'])) {
  15223. if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
  15224. $group = $deps['group'];
  15225. } elseif ($explicit) {
  15226. if (!isset($options['soft'])) {
  15227. $this->_downloader->log(0, 'Warning: package "' .
  15228. $this->_registry->parsedPackageNameToString($pname, true) .
  15229. '" has no dependency ' . 'group named "' . $groupname . '"');
  15230. }
  15231. $groupnotfound = true;
  15232. continue;
  15233. }
  15234. } else {
  15235. $found = false;
  15236. foreach ($deps['group'] as $group) {
  15237. if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
  15238. $found = true;
  15239. break;
  15240. }
  15241. }
  15242. if (!$found) {
  15243. if ($explicit) {
  15244. if (!isset($options['soft'])) {
  15245. $this->_downloader->log(0, 'Warning: package "' .
  15246. $this->_registry->parsedPackageNameToString($pname, true) .
  15247. '" has no dependency ' . 'group named "' . $groupname . '"');
  15248. }
  15249. }
  15250. $groupnotfound = true;
  15251. continue;
  15252. }
  15253. }
  15254. }
  15255. if (isset($group) && isset($group[$packagetype])) {
  15256. if (isset($group[$packagetype][0])) {
  15257. foreach ($group[$packagetype] as $dep) {
  15258. $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
  15259. $group['attribs']['name'] . '"', $params);
  15260. if (is_array($ret)) {
  15261. $this->_downloadDeps[] = $ret;
  15262. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  15263. $this->_downloader->log(0, $ret->getMessage());
  15264. }
  15265. }
  15266. } else {
  15267. $ret = $this->_detect2Dep($group[$packagetype], $pname,
  15268. 'dependency group "' .
  15269. $group['attribs']['name'] . '"', $params);
  15270. if (is_array($ret)) {
  15271. $this->_downloadDeps[] = $ret;
  15272. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  15273. $this->_downloader->log(0, $ret->getMessage());
  15274. }
  15275. }
  15276. }
  15277. }
  15278. }
  15279. function _detect2Dep($dep, $pname, $group, $params)
  15280. {
  15281. if (isset($dep['conflicts'])) {
  15282. return true;
  15283. }
  15284. $options = $this->_downloader->getOptions();
  15285. if (isset($dep['uri'])) {
  15286. return array('uri' => $dep['uri'], 'dep' => $dep);;
  15287. }
  15288. $testdep = $dep;
  15289. $testdep['package'] = $dep['name'];
  15290. if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
  15291. $dep['package'] = $dep['name'];
  15292. if (!isset($options['soft'])) {
  15293. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
  15294. ' dependency "' .
  15295. $this->_registry->parsedPackageNameToString($dep, true) .
  15296. '", will be installed');
  15297. }
  15298. return false;
  15299. }
  15300. $options = $this->_downloader->getOptions();
  15301. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15302. if ($this->_explicitState) {
  15303. $pname['state'] = $this->_explicitState;
  15304. }
  15305. $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  15306. if (PEAR::isError($url)) {
  15307. PEAR::popErrorHandling();
  15308. return $url;
  15309. }
  15310. $dep['package'] = $dep['name'];
  15311. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
  15312. !isset($options['alldeps']), true);
  15313. PEAR::popErrorHandling();
  15314. if (PEAR::isError($ret)) {
  15315. if (!isset($options['soft'])) {
  15316. $this->_downloader->log(0, $ret->getMessage());
  15317. }
  15318. return false;
  15319. }
  15320. // check to see if a dep is already installed and is the same or newer
  15321. if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
  15322. $oper = 'has';
  15323. } else {
  15324. $oper = 'gt';
  15325. }
  15326. // do not try to move this before getDepPackageDownloadURL
  15327. // we can't determine whether upgrade is necessary until we know what
  15328. // version would be downloaded
  15329. if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
  15330. $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']);
  15331. $dep['package'] = $dep['name'];
  15332. if (!isset($options['soft'])) {
  15333. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  15334. ' dependency "' .
  15335. $this->_registry->parsedPackageNameToString($dep, true) .
  15336. '" version ' . $url['version'] . ', already installed as version ' .
  15337. $version);
  15338. }
  15339. return false;
  15340. }
  15341. if (isset($dep['nodefault'])) {
  15342. $ret['nodefault'] = true;
  15343. }
  15344. return $ret;
  15345. }
  15346. function _detect1($deps, $pname, $options, $params)
  15347. {
  15348. $this->_downloadDeps = array();
  15349. $skipnames = array();
  15350. foreach ($deps as $dep) {
  15351. $nodownload = false;
  15352. if (isset ($dep['type']) && $dep['type'] === 'pkg') {
  15353. $dep['channel'] = 'pear.php.net';
  15354. $dep['package'] = $dep['name'];
  15355. switch ($dep['rel']) {
  15356. case 'not' :
  15357. continue 2;
  15358. case 'ge' :
  15359. case 'eq' :
  15360. case 'gt' :
  15361. case 'has' :
  15362. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  15363. 'required' :
  15364. 'optional';
  15365. if (PEAR_Downloader_Package::willDownload($dep, $params)) {
  15366. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  15367. . ' dependency "' .
  15368. $this->_registry->parsedPackageNameToString($dep, true) .
  15369. '", will be installed');
  15370. continue 2;
  15371. }
  15372. $fakedp = new PEAR_PackageFile_v1;
  15373. $fakedp->setPackage($dep['name']);
  15374. // skip internet check if we are not upgrading (bug #5810)
  15375. if (!isset($options['upgrade']) && $this->isInstalled(
  15376. $fakedp, $dep['rel'])) {
  15377. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  15378. . ' dependency "' .
  15379. $this->_registry->parsedPackageNameToString($dep, true) .
  15380. '", is already installed');
  15381. continue 2;
  15382. }
  15383. }
  15384. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15385. if ($this->_explicitState) {
  15386. $pname['state'] = $this->_explicitState;
  15387. }
  15388. $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  15389. $chan = 'pear.php.net';
  15390. if (PEAR::isError($url)) {
  15391. // check to see if this is a pecl package that has jumped
  15392. // from pear.php.net to pecl.php.net channel
  15393. if (!class_exists('PEAR_Dependency2')) {
  15394. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  15395. }
  15396. $newdep = PEAR_Dependency2::normalizeDep($dep);
  15397. $newdep = $newdep[0];
  15398. $newdep['channel'] = 'pecl.php.net';
  15399. $chan = 'pecl.php.net';
  15400. $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
  15401. $obj = &$this->_installRegistry->getPackage($dep['name']);
  15402. if (PEAR::isError($url)) {
  15403. PEAR::popErrorHandling();
  15404. if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
  15405. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  15406. 'required' :
  15407. 'optional';
  15408. $dep['package'] = $dep['name'];
  15409. if (!isset($options['soft'])) {
  15410. $this->_downloader->log(3, $this->getShortName() .
  15411. ': Skipping ' . $group . ' dependency "' .
  15412. $this->_registry->parsedPackageNameToString($dep, true) .
  15413. '", already installed as version ' . $obj->getVersion());
  15414. }
  15415. $skip = count($skipnames) ?
  15416. $skipnames[count($skipnames) - 1] : '';
  15417. if ($skip ==
  15418. $this->_registry->parsedPackageNameToString($dep, true)) {
  15419. array_pop($skipnames);
  15420. }
  15421. continue;
  15422. } else {
  15423. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  15424. $this->_downloader->log(2, $this->getShortName() .
  15425. ': Skipping optional dependency "' .
  15426. $this->_registry->parsedPackageNameToString($dep, true) .
  15427. '", no releases exist');
  15428. continue;
  15429. } else {
  15430. return $url;
  15431. }
  15432. }
  15433. }
  15434. }
  15435. PEAR::popErrorHandling();
  15436. if (!isset($options['alldeps'])) {
  15437. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  15438. if (!isset($options['soft'])) {
  15439. $this->_downloader->log(3, 'Notice: package "' .
  15440. $this->getShortName() .
  15441. '" optional dependency "' .
  15442. $this->_registry->parsedPackageNameToString(
  15443. array('channel' => $chan, 'package' =>
  15444. $dep['name']), true) .
  15445. '" will not be automatically downloaded');
  15446. }
  15447. $skipnames[] = $this->_registry->parsedPackageNameToString(
  15448. array('channel' => $chan, 'package' =>
  15449. $dep['name']), true);
  15450. $nodownload = true;
  15451. }
  15452. }
  15453. if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
  15454. if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  15455. if (!isset($options['soft'])) {
  15456. $this->_downloader->log(3, 'Notice: package "' .
  15457. $this->getShortName() .
  15458. '" required dependency "' .
  15459. $this->_registry->parsedPackageNameToString(
  15460. array('channel' => $chan, 'package' =>
  15461. $dep['name']), true) .
  15462. '" will not be automatically downloaded');
  15463. }
  15464. $skipnames[] = $this->_registry->parsedPackageNameToString(
  15465. array('channel' => $chan, 'package' =>
  15466. $dep['name']), true);
  15467. $nodownload = true;
  15468. }
  15469. }
  15470. // check to see if a dep is already installed
  15471. // do not try to move this before getDepPackageDownloadURL
  15472. // we can't determine whether upgrade is necessary until we know what
  15473. // version would be downloaded
  15474. if (!isset($options['force']) && $this->isInstalled(
  15475. $url, $dep['rel'])) {
  15476. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  15477. 'required' :
  15478. 'optional';
  15479. $dep['package'] = $dep['name'];
  15480. if (isset($newdep)) {
  15481. $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']);
  15482. } else {
  15483. $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
  15484. }
  15485. $dep['version'] = $url['version'];
  15486. if (!isset($options['soft'])) {
  15487. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  15488. ' dependency "' .
  15489. $this->_registry->parsedPackageNameToString($dep, true) .
  15490. '", already installed as version ' . $version);
  15491. }
  15492. $skip = count($skipnames) ?
  15493. $skipnames[count($skipnames) - 1] : '';
  15494. if ($skip ==
  15495. $this->_registry->parsedPackageNameToString($dep, true)) {
  15496. array_pop($skipnames);
  15497. }
  15498. continue;
  15499. }
  15500. if ($nodownload) {
  15501. continue;
  15502. }
  15503. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15504. if (isset($newdep)) {
  15505. $dep = $newdep;
  15506. }
  15507. $dep['package'] = $dep['name'];
  15508. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
  15509. isset($dep['optional']) && $dep['optional'] == 'yes' &&
  15510. !isset($options['alldeps']), true);
  15511. PEAR::popErrorHandling();
  15512. if (PEAR::isError($ret)) {
  15513. if (!isset($options['soft'])) {
  15514. $this->_downloader->log(0, $ret->getMessage());
  15515. }
  15516. continue;
  15517. }
  15518. $this->_downloadDeps[] = $ret;
  15519. }
  15520. }
  15521. if (count($skipnames)) {
  15522. if (!isset($options['soft'])) {
  15523. $this->_downloader->log(1, 'Did not download dependencies: ' .
  15524. implode(', ', $skipnames) .
  15525. ', use --alldeps or --onlyreqdeps to download automatically');
  15526. }
  15527. }
  15528. }
  15529. function setDownloadURL($pkg)
  15530. {
  15531. $this->_downloadURL = $pkg;
  15532. }
  15533. /**
  15534. * Set the package.xml object for this downloaded package
  15535. *
  15536. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
  15537. */
  15538. function setPackageFile(&$pkg)
  15539. {
  15540. $this->_packagefile = &$pkg;
  15541. }
  15542. function getShortName()
  15543. {
  15544. return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
  15545. 'package' => $this->getPackage()), true);
  15546. }
  15547. function getParsedPackage()
  15548. {
  15549. if (isset($this->_packagefile) || isset($this->_parsedname)) {
  15550. return array('channel' => $this->getChannel(),
  15551. 'package' => $this->getPackage(),
  15552. 'version' => $this->getVersion());
  15553. }
  15554. return false;
  15555. }
  15556. function getDownloadURL()
  15557. {
  15558. return $this->_downloadURL;
  15559. }
  15560. function canDefault()
  15561. {
  15562. if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) {
  15563. return false;
  15564. }
  15565. return true;
  15566. }
  15567. function getPackage()
  15568. {
  15569. if (isset($this->_packagefile)) {
  15570. return $this->_packagefile->getPackage();
  15571. } elseif (isset($this->_downloadURL['info'])) {
  15572. return $this->_downloadURL['info']->getPackage();
  15573. }
  15574. return false;
  15575. }
  15576. /**
  15577. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  15578. */
  15579. function isSubpackage(&$pf)
  15580. {
  15581. if (isset($this->_packagefile)) {
  15582. return $this->_packagefile->isSubpackage($pf);
  15583. } elseif (isset($this->_downloadURL['info'])) {
  15584. return $this->_downloadURL['info']->isSubpackage($pf);
  15585. }
  15586. return false;
  15587. }
  15588. function getPackageType()
  15589. {
  15590. if (isset($this->_packagefile)) {
  15591. return $this->_packagefile->getPackageType();
  15592. } elseif (isset($this->_downloadURL['info'])) {
  15593. return $this->_downloadURL['info']->getPackageType();
  15594. }
  15595. return false;
  15596. }
  15597. function isBundle()
  15598. {
  15599. if (isset($this->_packagefile)) {
  15600. return $this->_packagefile->getPackageType() == 'bundle';
  15601. }
  15602. return false;
  15603. }
  15604. function getPackageXmlVersion()
  15605. {
  15606. if (isset($this->_packagefile)) {
  15607. return $this->_packagefile->getPackagexmlVersion();
  15608. } elseif (isset($this->_downloadURL['info'])) {
  15609. return $this->_downloadURL['info']->getPackagexmlVersion();
  15610. }
  15611. return '1.0';
  15612. }
  15613. function getChannel()
  15614. {
  15615. if (isset($this->_packagefile)) {
  15616. return $this->_packagefile->getChannel();
  15617. } elseif (isset($this->_downloadURL['info'])) {
  15618. return $this->_downloadURL['info']->getChannel();
  15619. }
  15620. return false;
  15621. }
  15622. function getURI()
  15623. {
  15624. if (isset($this->_packagefile)) {
  15625. return $this->_packagefile->getURI();
  15626. } elseif (isset($this->_downloadURL['info'])) {
  15627. return $this->_downloadURL['info']->getURI();
  15628. }
  15629. return false;
  15630. }
  15631. function getVersion()
  15632. {
  15633. if (isset($this->_packagefile)) {
  15634. return $this->_packagefile->getVersion();
  15635. } elseif (isset($this->_downloadURL['version'])) {
  15636. return $this->_downloadURL['version'];
  15637. }
  15638. return false;
  15639. }
  15640. function isCompatible($pf)
  15641. {
  15642. if (isset($this->_packagefile)) {
  15643. return $this->_packagefile->isCompatible($pf);
  15644. } elseif (isset($this->_downloadURL['info'])) {
  15645. return $this->_downloadURL['info']->isCompatible($pf);
  15646. }
  15647. return true;
  15648. }
  15649. function setGroup($group)
  15650. {
  15651. $this->_parsedname['group'] = $group;
  15652. }
  15653. function getGroup()
  15654. {
  15655. if (isset($this->_parsedname['group'])) {
  15656. return $this->_parsedname['group'];
  15657. }
  15658. return '';
  15659. }
  15660. function isExtension($name)
  15661. {
  15662. if (isset($this->_packagefile)) {
  15663. return $this->_packagefile->isExtension($name);
  15664. } elseif (isset($this->_downloadURL['info'])) {
  15665. if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
  15666. return $this->_downloadURL['info']->getProvidesExtension() == $name;
  15667. }
  15668. return false;
  15669. }
  15670. return false;
  15671. }
  15672. function getDeps()
  15673. {
  15674. if (isset($this->_packagefile)) {
  15675. $ver = $this->_packagefile->getPackagexmlVersion();
  15676. if (version_compare($ver, '2.0', '>=')) {
  15677. return $this->_packagefile->getDeps(true);
  15678. }
  15679. return $this->_packagefile->getDeps();
  15680. } elseif (isset($this->_downloadURL['info'])) {
  15681. $ver = $this->_downloadURL['info']->getPackagexmlVersion();
  15682. if (version_compare($ver, '2.0', '>=')) {
  15683. return $this->_downloadURL['info']->getDeps(true);
  15684. }
  15685. return $this->_downloadURL['info']->getDeps();
  15686. }
  15687. return array();
  15688. }
  15689. /**
  15690. * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
  15691. * returned from getDepDownloadURL()
  15692. */
  15693. function isEqual($param)
  15694. {
  15695. if (is_object($param)) {
  15696. $channel = $param->getChannel();
  15697. $package = $param->getPackage();
  15698. if ($param->getURI()) {
  15699. $param = array(
  15700. 'channel' => $param->getChannel(),
  15701. 'package' => $param->getPackage(),
  15702. 'version' => $param->getVersion(),
  15703. 'uri' => $param->getURI(),
  15704. );
  15705. } else {
  15706. $param = array(
  15707. 'channel' => $param->getChannel(),
  15708. 'package' => $param->getPackage(),
  15709. 'version' => $param->getVersion(),
  15710. );
  15711. }
  15712. } else {
  15713. if (isset($param['uri'])) {
  15714. if ($this->getChannel() != '__uri') {
  15715. return false;
  15716. }
  15717. return $param['uri'] == $this->getURI();
  15718. }
  15719. $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage();
  15720. $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel();
  15721. if (isset($param['rel'])) {
  15722. if (!class_exists('PEAR_Dependency2')) {
  15723. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  15724. }
  15725. $newdep = PEAR_Dependency2::normalizeDep($param);
  15726. $newdep = $newdep[0];
  15727. } elseif (isset($param['min'])) {
  15728. $newdep = $param;
  15729. }
  15730. }
  15731. if (isset($newdep)) {
  15732. if (!isset($newdep['min'])) {
  15733. $newdep['min'] = '0';
  15734. }
  15735. if (!isset($newdep['max'])) {
  15736. $newdep['max'] = '100000000000000000000';
  15737. }
  15738. // use magic to support pecl packages suddenly jumping to the pecl channel
  15739. // we need to support both dependency possibilities
  15740. if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
  15741. if ($package == $this->getPackage()) {
  15742. $channel = 'pecl.php.net';
  15743. }
  15744. }
  15745. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  15746. if ($package == $this->getPackage()) {
  15747. $channel = 'pear.php.net';
  15748. }
  15749. }
  15750. return (strtolower($package) == strtolower($this->getPackage()) &&
  15751. $channel == $this->getChannel() &&
  15752. version_compare($newdep['min'], $this->getVersion(), '<=') &&
  15753. version_compare($newdep['max'], $this->getVersion(), '>='));
  15754. }
  15755. // use magic to support pecl packages suddenly jumping to the pecl channel
  15756. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  15757. if (strtolower($package) == strtolower($this->getPackage())) {
  15758. $channel = 'pear.php.net';
  15759. }
  15760. }
  15761. if (isset($param['version'])) {
  15762. return (strtolower($package) == strtolower($this->getPackage()) &&
  15763. $channel == $this->getChannel() &&
  15764. $param['version'] == $this->getVersion());
  15765. }
  15766. return strtolower($package) == strtolower($this->getPackage()) &&
  15767. $channel == $this->getChannel();
  15768. }
  15769. function isInstalled($dep, $oper = '==')
  15770. {
  15771. if (!$dep) {
  15772. return false;
  15773. }
  15774. if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
  15775. return false;
  15776. }
  15777. if (is_object($dep)) {
  15778. $package = $dep->getPackage();
  15779. $channel = $dep->getChannel();
  15780. if ($dep->getURI()) {
  15781. $dep = array(
  15782. 'uri' => $dep->getURI(),
  15783. 'version' => $dep->getVersion(),
  15784. );
  15785. } else {
  15786. $dep = array(
  15787. 'version' => $dep->getVersion(),
  15788. );
  15789. }
  15790. } else {
  15791. if (isset($dep['uri'])) {
  15792. $channel = '__uri';
  15793. $package = $dep['dep']['name'];
  15794. } else {
  15795. $channel = $dep['info']->getChannel();
  15796. $package = $dep['info']->getPackage();
  15797. }
  15798. }
  15799. $options = $this->_downloader->getOptions();
  15800. $test = $this->_installRegistry->packageExists($package, $channel);
  15801. if (!$test && $channel == 'pecl.php.net') {
  15802. // do magic to allow upgrading from old pecl packages to new ones
  15803. $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
  15804. $channel = 'pear.php.net';
  15805. }
  15806. if ($test) {
  15807. if (isset($dep['uri'])) {
  15808. if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
  15809. return true;
  15810. }
  15811. }
  15812. if (isset($options['upgrade'])) {
  15813. $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel);
  15814. if (version_compare($packageVersion, $dep['version'], '>=')) {
  15815. return true;
  15816. }
  15817. return false;
  15818. }
  15819. return true;
  15820. }
  15821. return false;
  15822. }
  15823. /**
  15824. * Detect duplicate package names with differing versions
  15825. *
  15826. * If a user requests to install Date 1.4.6 and Date 1.4.7,
  15827. * for instance, this is a logic error. This method
  15828. * detects this situation.
  15829. *
  15830. * @param array $params array of PEAR_Downloader_Package objects
  15831. * @param array $errorparams empty array
  15832. * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
  15833. */
  15834. public static function detectStupidDuplicates($params, &$errorparams)
  15835. {
  15836. $existing = array();
  15837. foreach ($params as $i => $param) {
  15838. $package = $param->getPackage();
  15839. $channel = $param->getChannel();
  15840. $group = $param->getGroup();
  15841. if (!isset($existing[$channel . '/' . $package])) {
  15842. $existing[$channel . '/' . $package] = array();
  15843. }
  15844. if (!isset($existing[$channel . '/' . $package][$group])) {
  15845. $existing[$channel . '/' . $package][$group] = array();
  15846. }
  15847. $existing[$channel . '/' . $package][$group][] = $i;
  15848. }
  15849. $indices = array();
  15850. foreach ($existing as $package => $groups) {
  15851. foreach ($groups as $group => $dupes) {
  15852. if (count($dupes) > 1) {
  15853. $indices = $indices + $dupes;
  15854. }
  15855. }
  15856. }
  15857. $indices = array_unique($indices);
  15858. foreach ($indices as $index) {
  15859. $errorparams[] = $params[$index];
  15860. }
  15861. return count($errorparams);
  15862. }
  15863. /**
  15864. * @param array
  15865. * @param bool ignore install groups - for final removal of dupe packages
  15866. */
  15867. public static function removeDuplicates(&$params, $ignoreGroups = false)
  15868. {
  15869. $pnames = array();
  15870. foreach ($params as $i => $param) {
  15871. if (!$param) {
  15872. continue;
  15873. }
  15874. if ($param->getPackage()) {
  15875. $group = $ignoreGroups ? '' : $param->getGroup();
  15876. $pnames[$i] = $param->getChannel() . '/' .
  15877. $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
  15878. }
  15879. }
  15880. $pnames = array_unique($pnames);
  15881. $unset = array_diff(array_keys($params), array_keys($pnames));
  15882. $testp = array_flip($pnames);
  15883. foreach ($params as $i => $param) {
  15884. if (!$param) {
  15885. $unset[] = $i;
  15886. continue;
  15887. }
  15888. if (!is_a($param, 'PEAR_Downloader_Package')) {
  15889. $unset[] = $i;
  15890. continue;
  15891. }
  15892. $group = $ignoreGroups ? '' : $param->getGroup();
  15893. if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
  15894. $param->getVersion() . '#' . $group])) {
  15895. $unset[] = $i;
  15896. }
  15897. }
  15898. foreach ($unset as $i) {
  15899. unset($params[$i]);
  15900. }
  15901. $ret = array();
  15902. foreach ($params as $i => $param) {
  15903. $ret[] = &$params[$i];
  15904. }
  15905. $params = array();
  15906. foreach ($ret as $i => $param) {
  15907. $params[] = &$ret[$i];
  15908. }
  15909. }
  15910. function explicitState()
  15911. {
  15912. return $this->_explicitState;
  15913. }
  15914. function setExplicitState($s)
  15915. {
  15916. $this->_explicitState = $s;
  15917. }
  15918. /**
  15919. */
  15920. public static function mergeDependencies(&$params)
  15921. {
  15922. $bundles = $newparams = array();
  15923. foreach ($params as $i => $param) {
  15924. if (!$param->isBundle()) {
  15925. continue;
  15926. }
  15927. $bundles[] = $i;
  15928. $pf = &$param->getPackageFile();
  15929. $newdeps = array();
  15930. $contents = $pf->getBundledPackages();
  15931. if (!is_array($contents)) {
  15932. $contents = array($contents);
  15933. }
  15934. foreach ($contents as $file) {
  15935. $filecontents = $pf->getFileContents($file);
  15936. $dl = &$param->getDownloader();
  15937. $options = $dl->getOptions();
  15938. if (PEAR::isError($dir = $dl->getDownloadDir())) {
  15939. return $dir;
  15940. }
  15941. $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
  15942. if (!$fp) {
  15943. continue;
  15944. }
  15945. // FIXME do symlink check
  15946. fwrite($fp, $filecontents, strlen($filecontents));
  15947. fclose($fp);
  15948. if ($s = $params[$i]->explicitState()) {
  15949. $obj->setExplicitState($s);
  15950. }
  15951. $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
  15952. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15953. if (PEAR::isError($dir = $dl->getDownloadDir())) {
  15954. PEAR::popErrorHandling();
  15955. return $dir;
  15956. }
  15957. $a = $dir . DIRECTORY_SEPARATOR . $file;
  15958. $e = $obj->_fromFile($a);
  15959. PEAR::popErrorHandling();
  15960. if (PEAR::isError($e)) {
  15961. if (!isset($options['soft'])) {
  15962. $dl->log(0, $e->getMessage());
  15963. }
  15964. continue;
  15965. }
  15966. if (!PEAR_Downloader_Package::willDownload($obj,
  15967. array_merge($params, $newparams)) && !$param->isInstalled($obj)) {
  15968. $newparams[] = $obj;
  15969. }
  15970. }
  15971. }
  15972. foreach ($bundles as $i) {
  15973. unset($params[$i]); // remove bundles - only their contents matter for installation
  15974. }
  15975. PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
  15976. if (count($newparams)) { // add in bundled packages for install
  15977. foreach ($newparams as $i => $unused) {
  15978. $params[] = &$newparams[$i];
  15979. }
  15980. $newparams = array();
  15981. }
  15982. foreach ($params as $i => $param) {
  15983. $newdeps = array();
  15984. foreach ($param->_downloadDeps as $dep) {
  15985. $merge = array_merge($params, $newparams);
  15986. if (!PEAR_Downloader_Package::willDownload($dep, $merge)
  15987. && !$param->isInstalled($dep)
  15988. ) {
  15989. $newdeps[] = $dep;
  15990. } else {
  15991. //var_dump($dep);
  15992. // detect versioning conflicts here
  15993. }
  15994. }
  15995. // convert the dependencies into PEAR_Downloader_Package objects for the next time around
  15996. $params[$i]->_downloadDeps = array();
  15997. foreach ($newdeps as $dep) {
  15998. $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
  15999. if ($s = $params[$i]->explicitState()) {
  16000. $obj->setExplicitState($s);
  16001. }
  16002. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16003. $e = $obj->fromDepURL($dep);
  16004. PEAR::popErrorHandling();
  16005. if (PEAR::isError($e)) {
  16006. if (!isset($options['soft'])) {
  16007. $obj->_downloader->log(0, $e->getMessage());
  16008. }
  16009. continue;
  16010. }
  16011. $e = $obj->detectDependencies($params);
  16012. if (PEAR::isError($e)) {
  16013. if (!isset($options['soft'])) {
  16014. $obj->_downloader->log(0, $e->getMessage());
  16015. }
  16016. }
  16017. $newparams[] = $obj;
  16018. }
  16019. }
  16020. if (count($newparams)) {
  16021. foreach ($newparams as $i => $unused) {
  16022. $params[] = &$newparams[$i];
  16023. }
  16024. return true;
  16025. }
  16026. return false;
  16027. }
  16028. /**
  16029. */
  16030. public static function willDownload($param, $params)
  16031. {
  16032. if (!is_array($params)) {
  16033. return false;
  16034. }
  16035. foreach ($params as $obj) {
  16036. if ($obj->isEqual($param)) {
  16037. return true;
  16038. }
  16039. }
  16040. return false;
  16041. }
  16042. /**
  16043. * For simpler unit-testing
  16044. * @param PEAR_Config
  16045. * @param int
  16046. * @param string
  16047. */
  16048. function &getPackagefileObject(&$c, $d)
  16049. {
  16050. $a = new PEAR_PackageFile($c, $d);
  16051. return $a;
  16052. }
  16053. /**
  16054. * This will retrieve from a local file if possible, and parse out
  16055. * a group name as well. The original parameter will be modified to reflect this.
  16056. * @param string|array can be a parsed package name as well
  16057. * @access private
  16058. */
  16059. function _fromFile(&$param)
  16060. {
  16061. $saveparam = $param;
  16062. if (is_string($param) && substr($param, 0, 10) !== 'channel://') {
  16063. if (!@file_exists($param)) {
  16064. $test = explode('#', $param);
  16065. $group = array_pop($test);
  16066. if (@file_exists(implode('#', $test))) {
  16067. $this->setGroup($group);
  16068. $param = implode('#', $test);
  16069. $this->_explicitGroup = true;
  16070. }
  16071. }
  16072. if (@is_file($param)) {
  16073. $this->_type = 'local';
  16074. $options = $this->_downloader->getOptions();
  16075. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug);
  16076. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16077. $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
  16078. PEAR::popErrorHandling();
  16079. if (PEAR::isError($pf)) {
  16080. $this->_valid = false;
  16081. $param = $saveparam;
  16082. return $pf;
  16083. }
  16084. $this->_packagefile = &$pf;
  16085. if (!$this->getGroup()) {
  16086. $this->setGroup('default'); // install the default dependency group
  16087. }
  16088. return $this->_valid = true;
  16089. }
  16090. }
  16091. $param = $saveparam;
  16092. return $this->_valid = false;
  16093. }
  16094. function _fromUrl($param, $saveparam = '')
  16095. {
  16096. if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) {
  16097. $options = $this->_downloader->getOptions();
  16098. $this->_type = 'url';
  16099. $callback = $this->_downloader->ui ?
  16100. array(&$this->_downloader, '_downloadCallback') : null;
  16101. $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
  16102. if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  16103. $this->_downloader->popErrorHandling();
  16104. return $dir;
  16105. }
  16106. $this->_downloader->log(3, 'Downloading "' . $param . '"');
  16107. $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
  16108. $dir, $callback, null, false, $this->getChannel());
  16109. $this->_downloader->popErrorHandling();
  16110. if (PEAR::isError($file)) {
  16111. if (!empty($saveparam)) {
  16112. $saveparam = ", cannot download \"$saveparam\"";
  16113. }
  16114. $err = PEAR::raiseError('Could not download from "' . $param .
  16115. '"' . $saveparam . ' (' . $file->getMessage() . ')');
  16116. return $err;
  16117. }
  16118. if ($this->_rawpackagefile) {
  16119. require_once 'phar://go-pear.phar/' . 'Archive/Tar.php';
  16120. $tar = new Archive_Tar($file);
  16121. $packagexml = $tar->extractInString('package2.xml');
  16122. if (!$packagexml) {
  16123. $packagexml = $tar->extractInString('package.xml');
  16124. }
  16125. if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
  16126. str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
  16127. if ($this->getChannel() != 'pear.php.net') {
  16128. return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
  16129. 'not match value returned from xml-rpc');
  16130. }
  16131. // be more lax for the existing PEAR packages that have not-ok
  16132. // characters in their package.xml
  16133. $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
  16134. $this->getPackage() . '" package has invalid characters in its ' .
  16135. 'package.xml. The next version of PEAR may not be able to install ' .
  16136. 'this package for security reasons. Please open a bug report at ' .
  16137. 'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
  16138. }
  16139. }
  16140. // whew, download worked!
  16141. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
  16142. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16143. $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
  16144. PEAR::popErrorHandling();
  16145. if (PEAR::isError($pf)) {
  16146. if (is_array($pf->getUserInfo())) {
  16147. foreach ($pf->getUserInfo() as $err) {
  16148. if (is_array($err)) {
  16149. $err = $err['message'];
  16150. }
  16151. if (!isset($options['soft'])) {
  16152. $this->_downloader->log(0, "Validation Error: $err");
  16153. }
  16154. }
  16155. }
  16156. if (!isset($options['soft'])) {
  16157. $this->_downloader->log(0, $pf->getMessage());
  16158. }
  16159. ///FIXME need to pass back some error code that we can use to match with to cancel all further operations
  16160. /// At least stop all deps of this package from being installed
  16161. $out = $saveparam ? $saveparam : $param;
  16162. $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive');
  16163. $this->_valid = false;
  16164. return $err;
  16165. }
  16166. $this->_packagefile = &$pf;
  16167. $this->setGroup('default'); // install the default dependency group
  16168. return $this->_valid = true;
  16169. }
  16170. return $this->_valid = false;
  16171. }
  16172. /**
  16173. *
  16174. * @param string|array pass in an array of format
  16175. * array(
  16176. * 'package' => 'pname',
  16177. * ['channel' => 'channame',]
  16178. * ['version' => 'version',]
  16179. * ['state' => 'state',])
  16180. * or a string of format [channame/]pname[-version|-state]
  16181. */
  16182. function _fromString($param)
  16183. {
  16184. $options = $this->_downloader->getOptions();
  16185. $channel = $this->_config->get('default_channel');
  16186. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16187. $pname = $this->_registry->parsePackageName($param, $channel);
  16188. PEAR::popErrorHandling();
  16189. if (PEAR::isError($pname)) {
  16190. if ($pname->getCode() == 'invalid') {
  16191. $this->_valid = false;
  16192. return false;
  16193. }
  16194. if ($pname->getCode() == 'channel') {
  16195. $parsed = $pname->getUserInfo();
  16196. if ($this->_downloader->discover($parsed['channel'])) {
  16197. if ($this->_config->get('auto_discover')) {
  16198. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16199. $pname = $this->_registry->parsePackageName($param, $channel);
  16200. PEAR::popErrorHandling();
  16201. } else {
  16202. if (!isset($options['soft'])) {
  16203. $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
  16204. '" is not initialized, use ' .
  16205. '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
  16206. 'or pear config-set auto_discover 1');
  16207. }
  16208. }
  16209. }
  16210. if (PEAR::isError($pname)) {
  16211. if (!isset($options['soft'])) {
  16212. $this->_downloader->log(0, $pname->getMessage());
  16213. }
  16214. if (is_array($param)) {
  16215. $param = $this->_registry->parsedPackageNameToString($param);
  16216. }
  16217. $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
  16218. $this->_valid = false;
  16219. return $err;
  16220. }
  16221. } else {
  16222. if (!isset($options['soft'])) {
  16223. $this->_downloader->log(0, $pname->getMessage());
  16224. }
  16225. $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
  16226. $this->_valid = false;
  16227. return $err;
  16228. }
  16229. }
  16230. if (!isset($this->_type)) {
  16231. $this->_type = 'rest';
  16232. }
  16233. $this->_parsedname = $pname;
  16234. $this->_explicitState = isset($pname['state']) ? $pname['state'] : false;
  16235. $this->_explicitGroup = isset($pname['group']) ? true : false;
  16236. $info = $this->_downloader->_getPackageDownloadUrl($pname);
  16237. if (PEAR::isError($info)) {
  16238. if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
  16239. // try pecl
  16240. $pname['channel'] = 'pecl.php.net';
  16241. if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
  16242. if (!PEAR::isError($test)) {
  16243. $info = PEAR::raiseError($info->getMessage() . ' - package ' .
  16244. $this->_registry->parsedPackageNameToString($pname, true) .
  16245. ' can be installed with "pecl install ' . $pname['package'] .
  16246. '"');
  16247. } else {
  16248. $pname['channel'] = 'pear.php.net';
  16249. }
  16250. } else {
  16251. $pname['channel'] = 'pear.php.net';
  16252. }
  16253. }
  16254. return $info;
  16255. }
  16256. $this->_rawpackagefile = $info['raw'];
  16257. $ret = $this->_analyzeDownloadURL($info, $param, $pname);
  16258. if (PEAR::isError($ret)) {
  16259. return $ret;
  16260. }
  16261. if ($ret) {
  16262. $this->_downloadURL = $ret;
  16263. return $this->_valid = (bool) $ret;
  16264. }
  16265. }
  16266. /**
  16267. * @param array output of package.getDownloadURL
  16268. * @param string|array|object information for detecting packages to be downloaded, and
  16269. * for errors
  16270. * @param array name information of the package
  16271. * @param array|null packages to be downloaded
  16272. * @param bool is this an optional dependency?
  16273. * @param bool is this any kind of dependency?
  16274. * @access private
  16275. */
  16276. function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
  16277. $isdependency = false)
  16278. {
  16279. if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
  16280. return false;
  16281. }
  16282. if ($info === false) {
  16283. $saveparam = !is_string($param) ? ", cannot download \"$param\"" : '';
  16284. // no releases exist
  16285. return PEAR::raiseError('No releases for package "' .
  16286. $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
  16287. }
  16288. if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
  16289. $err = false;
  16290. if ($pname['channel'] == 'pecl.php.net') {
  16291. if ($info['info']->getChannel() != 'pear.php.net') {
  16292. $err = true;
  16293. }
  16294. } elseif ($info['info']->getChannel() == 'pecl.php.net') {
  16295. if ($pname['channel'] != 'pear.php.net') {
  16296. $err = true;
  16297. }
  16298. } else {
  16299. $err = true;
  16300. }
  16301. if ($err) {
  16302. return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
  16303. '" retrieved another channel\'s name for download! ("' .
  16304. $info['info']->getChannel() . '")');
  16305. }
  16306. }
  16307. $preferred_state = $this->_config->get('preferred_state');
  16308. if (!isset($info['url'])) {
  16309. $package_version = $this->_registry->packageInfo($info['info']->getPackage(),
  16310. 'version', $info['info']->getChannel());
  16311. if ($this->isInstalled($info)) {
  16312. if ($isdependency && version_compare($info['version'], $package_version, '<=')) {
  16313. // ignore bogus errors of "failed to download dependency"
  16314. // if it is already installed and the one that would be
  16315. // downloaded is older or the same version (Bug #7219)
  16316. return false;
  16317. }
  16318. }
  16319. if ($info['version'] === $package_version) {
  16320. if (!isset($options['soft'])) {
  16321. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  16322. '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' .
  16323. ' (' . $package_version . ') is the same as the locally installed one.');
  16324. }
  16325. return false;
  16326. }
  16327. if (version_compare($info['version'], $package_version, '<=')) {
  16328. if (!isset($options['soft'])) {
  16329. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  16330. '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' .
  16331. ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').');
  16332. }
  16333. return false;
  16334. }
  16335. $instead = ', will instead download version ' . $info['version'] .
  16336. ', stability "' . $info['info']->getState() . '"';
  16337. // releases exist, but we failed to get any
  16338. if (isset($this->_downloader->_options['force'])) {
  16339. if (isset($pname['version'])) {
  16340. $vs = ', version "' . $pname['version'] . '"';
  16341. } elseif (isset($pname['state'])) {
  16342. $vs = ', stability "' . $pname['state'] . '"';
  16343. } elseif ($param == 'dependency') {
  16344. if (!class_exists('PEAR_Common')) {
  16345. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  16346. }
  16347. if (!in_array($info['info']->getState(),
  16348. PEAR_Common::betterStates($preferred_state, true))) {
  16349. if ($optional) {
  16350. // don't spit out confusing error message
  16351. return $this->_downloader->_getPackageDownloadUrl(
  16352. array('package' => $pname['package'],
  16353. 'channel' => $pname['channel'],
  16354. 'version' => $info['version']));
  16355. }
  16356. $vs = ' within preferred state "' . $preferred_state .
  16357. '"';
  16358. } else {
  16359. if (!class_exists('PEAR_Dependency2')) {
  16360. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  16361. }
  16362. if ($optional) {
  16363. // don't spit out confusing error message
  16364. return $this->_downloader->_getPackageDownloadUrl(
  16365. array('package' => $pname['package'],
  16366. 'channel' => $pname['channel'],
  16367. 'version' => $info['version']));
  16368. }
  16369. $vs = PEAR_Dependency2::_getExtraString($pname);
  16370. $instead = '';
  16371. }
  16372. } else {
  16373. $vs = ' within preferred state "' . $preferred_state . '"';
  16374. }
  16375. if (!isset($options['soft'])) {
  16376. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  16377. '/' . $pname['package'] . $vs . $instead);
  16378. }
  16379. // download the latest release
  16380. return $this->_downloader->_getPackageDownloadUrl(
  16381. array('package' => $pname['package'],
  16382. 'channel' => $pname['channel'],
  16383. 'version' => $info['version']));
  16384. } else {
  16385. if (isset($info['php']) && $info['php']) {
  16386. $err = PEAR::raiseError('Failed to download ' .
  16387. $this->_registry->parsedPackageNameToString(
  16388. array('channel' => $pname['channel'],
  16389. 'package' => $pname['package']),
  16390. true) .
  16391. ', latest release is version ' . $info['php']['v'] .
  16392. ', but it requires PHP version "' .
  16393. $info['php']['m'] . '", use "' .
  16394. $this->_registry->parsedPackageNameToString(
  16395. array('channel' => $pname['channel'], 'package' => $pname['package'],
  16396. 'version' => $info['php']['v'])) . '" to install',
  16397. PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
  16398. return $err;
  16399. }
  16400. // construct helpful error message
  16401. if (isset($pname['version'])) {
  16402. $vs = ', version "' . $pname['version'] . '"';
  16403. } elseif (isset($pname['state'])) {
  16404. $vs = ', stability "' . $pname['state'] . '"';
  16405. } elseif ($param == 'dependency') {
  16406. if (!class_exists('PEAR_Common')) {
  16407. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  16408. }
  16409. if (!in_array($info['info']->getState(),
  16410. PEAR_Common::betterStates($preferred_state, true))) {
  16411. if ($optional) {
  16412. // don't spit out confusing error message, and don't die on
  16413. // optional dep failure!
  16414. return $this->_downloader->_getPackageDownloadUrl(
  16415. array('package' => $pname['package'],
  16416. 'channel' => $pname['channel'],
  16417. 'version' => $info['version']));
  16418. }
  16419. $vs = ' within preferred state "' . $preferred_state . '"';
  16420. } else {
  16421. if (!class_exists('PEAR_Dependency2')) {
  16422. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  16423. }
  16424. if ($optional) {
  16425. // don't spit out confusing error message, and don't die on
  16426. // optional dep failure!
  16427. return $this->_downloader->_getPackageDownloadUrl(
  16428. array('package' => $pname['package'],
  16429. 'channel' => $pname['channel'],
  16430. 'version' => $info['version']));
  16431. }
  16432. $vs = PEAR_Dependency2::_getExtraString($pname);
  16433. }
  16434. } else {
  16435. $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
  16436. }
  16437. $options = $this->_downloader->getOptions();
  16438. // this is only set by the "download-all" command
  16439. if (isset($options['ignorepreferred_state'])) {
  16440. $err = PEAR::raiseError(
  16441. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  16442. array('channel' => $pname['channel'], 'package' => $pname['package']),
  16443. true)
  16444. . $vs .
  16445. ', latest release is version ' . $info['version'] .
  16446. ', stability "' . $info['info']->getState() . '", use "' .
  16447. $this->_registry->parsedPackageNameToString(
  16448. array('channel' => $pname['channel'], 'package' => $pname['package'],
  16449. 'version' => $info['version'])) . '" to install',
  16450. PEAR_DOWNLOADER_PACKAGE_STATE);
  16451. return $err;
  16452. }
  16453. // Checks if the user has a package installed already and checks the release against
  16454. // the state against the installed package, this allows upgrades for packages
  16455. // with lower stability than the preferred_state
  16456. $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']);
  16457. if (!$this->isInstalled($info)
  16458. || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true))
  16459. ) {
  16460. $err = PEAR::raiseError(
  16461. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  16462. array('channel' => $pname['channel'], 'package' => $pname['package']),
  16463. true)
  16464. . $vs .
  16465. ', latest release is version ' . $info['version'] .
  16466. ', stability "' . $info['info']->getState() . '", use "' .
  16467. $this->_registry->parsedPackageNameToString(
  16468. array('channel' => $pname['channel'], 'package' => $pname['package'],
  16469. 'version' => $info['version'])) . '" to install');
  16470. return $err;
  16471. }
  16472. }
  16473. }
  16474. if (isset($info['deprecated']) && $info['deprecated']) {
  16475. $this->_downloader->log(0,
  16476. 'WARNING: "' .
  16477. $this->_registry->parsedPackageNameToString(
  16478. array('channel' => $info['info']->getChannel(),
  16479. 'package' => $info['info']->getPackage()), true) .
  16480. '" is deprecated in favor of "' .
  16481. $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
  16482. '"');
  16483. }
  16484. return $info;
  16485. }
  16486. }
  16487. <?php
  16488. /**
  16489. * Error Stack Implementation
  16490. *
  16491. * This is an incredibly simple implementation of a very complex error handling
  16492. * facility. It contains the ability
  16493. * to track multiple errors from multiple packages simultaneously. In addition,
  16494. * it can track errors of many levels, save data along with the error, context
  16495. * information such as the exact file, line number, class and function that
  16496. * generated the error, and if necessary, it can raise a traditional PEAR_Error.
  16497. * It has built-in support for PEAR::Log, to log errors as they occur
  16498. *
  16499. * Since version 0.2alpha, it is also possible to selectively ignore errors,
  16500. * through the use of an error callback, see {@link pushCallback()}
  16501. *
  16502. * Since version 0.3alpha, it is possible to specify the exception class
  16503. * returned from {@link push()}
  16504. *
  16505. * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can
  16506. * still be done quite handily in an error callback or by manipulating the returned array
  16507. * @category Debugging
  16508. * @package PEAR_ErrorStack
  16509. * @author Greg Beaver <cellog@php.net>
  16510. * @copyright 2004-2008 Greg Beaver
  16511. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  16512. * @link http://pear.php.net/package/PEAR_ErrorStack
  16513. */
  16514. /**
  16515. * Singleton storage
  16516. *
  16517. * Format:
  16518. * <pre>
  16519. * array(
  16520. * 'package1' => PEAR_ErrorStack object,
  16521. * 'package2' => PEAR_ErrorStack object,
  16522. * ...
  16523. * )
  16524. * </pre>
  16525. * @access private
  16526. * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
  16527. */
  16528. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
  16529. /**
  16530. * Global error callback (default)
  16531. *
  16532. * This is only used if set to non-false. * is the default callback for
  16533. * all packages, whereas specific packages may set a default callback
  16534. * for all instances, regardless of whether they are a singleton or not.
  16535. *
  16536. * To exclude non-singletons, only set the local callback for the singleton
  16537. * @see PEAR_ErrorStack::setDefaultCallback()
  16538. * @access private
  16539. * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
  16540. */
  16541. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
  16542. '*' => false,
  16543. );
  16544. /**
  16545. * Global Log object (default)
  16546. *
  16547. * This is only used if set to non-false. Use to set a default log object for
  16548. * all stacks, regardless of instantiation order or location
  16549. * @see PEAR_ErrorStack::setDefaultLogger()
  16550. * @access private
  16551. * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  16552. */
  16553. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
  16554. /**
  16555. * Global Overriding Callback
  16556. *
  16557. * This callback will override any error callbacks that specific loggers have set.
  16558. * Use with EXTREME caution
  16559. * @see PEAR_ErrorStack::staticPushCallback()
  16560. * @access private
  16561. * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  16562. */
  16563. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  16564. /**#@+
  16565. * One of four possible return values from the error Callback
  16566. * @see PEAR_ErrorStack::_errorCallback()
  16567. */
  16568. /**
  16569. * If this is returned, then the error will be both pushed onto the stack
  16570. * and logged.
  16571. */
  16572. define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
  16573. /**
  16574. * If this is returned, then the error will only be pushed onto the stack,
  16575. * and not logged.
  16576. */
  16577. define('PEAR_ERRORSTACK_PUSH', 2);
  16578. /**
  16579. * If this is returned, then the error will only be logged, but not pushed
  16580. * onto the error stack.
  16581. */
  16582. define('PEAR_ERRORSTACK_LOG', 3);
  16583. /**
  16584. * If this is returned, then the error is completely ignored.
  16585. */
  16586. define('PEAR_ERRORSTACK_IGNORE', 4);
  16587. /**
  16588. * If this is returned, then the error is logged and die() is called.
  16589. */
  16590. define('PEAR_ERRORSTACK_DIE', 5);
  16591. /**#@-*/
  16592. /**
  16593. * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
  16594. * the singleton method.
  16595. */
  16596. define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
  16597. /**
  16598. * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
  16599. * that has no __toString() method
  16600. */
  16601. define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  16602. /**
  16603. * Error Stack Implementation
  16604. *
  16605. * Usage:
  16606. * <code>
  16607. * // global error stack
  16608. * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
  16609. * // local error stack
  16610. * $local_stack = new PEAR_ErrorStack('MyPackage');
  16611. * </code>
  16612. * @author Greg Beaver <cellog@php.net>
  16613. * @version 1.10.10
  16614. * @package PEAR_ErrorStack
  16615. * @category Debugging
  16616. * @copyright 2004-2008 Greg Beaver
  16617. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  16618. * @link http://pear.php.net/package/PEAR_ErrorStack
  16619. */
  16620. class PEAR_ErrorStack {
  16621. /**
  16622. * Errors are stored in the order that they are pushed on the stack.
  16623. * @since 0.4alpha Errors are no longer organized by error level.
  16624. * This renders pop() nearly unusable, and levels could be more easily
  16625. * handled in a callback anyway
  16626. * @var array
  16627. * @access private
  16628. */
  16629. var $_errors = array();
  16630. /**
  16631. * Storage of errors by level.
  16632. *
  16633. * Allows easy retrieval and deletion of only errors from a particular level
  16634. * @since PEAR 1.4.0dev
  16635. * @var array
  16636. * @access private
  16637. */
  16638. var $_errorsByLevel = array();
  16639. /**
  16640. * Package name this error stack represents
  16641. * @var string
  16642. * @access protected
  16643. */
  16644. var $_package;
  16645. /**
  16646. * Determines whether a PEAR_Error is thrown upon every error addition
  16647. * @var boolean
  16648. * @access private
  16649. */
  16650. var $_compat = false;
  16651. /**
  16652. * If set to a valid callback, this will be used to generate the error
  16653. * message from the error code, otherwise the message passed in will be
  16654. * used
  16655. * @var false|string|array
  16656. * @access private
  16657. */
  16658. var $_msgCallback = false;
  16659. /**
  16660. * If set to a valid callback, this will be used to generate the error
  16661. * context for an error. For PHP-related errors, this will be a file
  16662. * and line number as retrieved from debug_backtrace(), but can be
  16663. * customized for other purposes. The error might actually be in a separate
  16664. * configuration file, or in a database query.
  16665. * @var false|string|array
  16666. * @access protected
  16667. */
  16668. var $_contextCallback = false;
  16669. /**
  16670. * If set to a valid callback, this will be called every time an error
  16671. * is pushed onto the stack. The return value will be used to determine
  16672. * whether to allow an error to be pushed or logged.
  16673. *
  16674. * The return value must be one an PEAR_ERRORSTACK_* constant
  16675. * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  16676. * @var false|string|array
  16677. * @access protected
  16678. */
  16679. var $_errorCallback = array();
  16680. /**
  16681. * PEAR::Log object for logging errors
  16682. * @var false|Log
  16683. * @access protected
  16684. */
  16685. var $_logger = false;
  16686. /**
  16687. * Error messages - designed to be overridden
  16688. * @var array
  16689. * @abstract
  16690. */
  16691. var $_errorMsgs = array();
  16692. /**
  16693. * Set up a new error stack
  16694. *
  16695. * @param string $package name of the package this error stack represents
  16696. * @param callback $msgCallback callback used for error message generation
  16697. * @param callback $contextCallback callback used for context generation,
  16698. * defaults to {@link getFileLine()}
  16699. * @param boolean $throwPEAR_Error
  16700. */
  16701. function __construct($package, $msgCallback = false, $contextCallback = false,
  16702. $throwPEAR_Error = false)
  16703. {
  16704. $this->_package = $package;
  16705. $this->setMessageCallback($msgCallback);
  16706. $this->setContextCallback($contextCallback);
  16707. $this->_compat = $throwPEAR_Error;
  16708. }
  16709. /**
  16710. * Return a single error stack for this package.
  16711. *
  16712. * Note that all parameters are ignored if the stack for package $package
  16713. * has already been instantiated
  16714. * @param string $package name of the package this error stack represents
  16715. * @param callback $msgCallback callback used for error message generation
  16716. * @param callback $contextCallback callback used for context generation,
  16717. * defaults to {@link getFileLine()}
  16718. * @param boolean $throwPEAR_Error
  16719. * @param string $stackClass class to instantiate
  16720. *
  16721. * @return PEAR_ErrorStack
  16722. */
  16723. public static function &singleton(
  16724. $package, $msgCallback = false, $contextCallback = false,
  16725. $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack'
  16726. ) {
  16727. if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  16728. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  16729. }
  16730. if (!class_exists($stackClass)) {
  16731. if (function_exists('debug_backtrace')) {
  16732. $trace = debug_backtrace();
  16733. }
  16734. PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
  16735. 'exception', array('stackclass' => $stackClass),
  16736. 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
  16737. false, $trace);
  16738. }
  16739. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
  16740. new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
  16741. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  16742. }
  16743. /**
  16744. * Internal error handler for PEAR_ErrorStack class
  16745. *
  16746. * Dies if the error is an exception (and would have died anyway)
  16747. * @access private
  16748. */
  16749. function _handleError($err)
  16750. {
  16751. if ($err['level'] == 'exception') {
  16752. $message = $err['message'];
  16753. if (isset($_SERVER['REQUEST_URI'])) {
  16754. echo '<br />';
  16755. } else {
  16756. echo "\n";
  16757. }
  16758. var_dump($err['context']);
  16759. die($message);
  16760. }
  16761. }
  16762. /**
  16763. * Set up a PEAR::Log object for all error stacks that don't have one
  16764. * @param Log $log
  16765. */
  16766. public static function setDefaultLogger(&$log)
  16767. {
  16768. if (is_object($log) && method_exists($log, 'log') ) {
  16769. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  16770. } elseif (is_callable($log)) {
  16771. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  16772. }
  16773. }
  16774. /**
  16775. * Set up a PEAR::Log object for this error stack
  16776. * @param Log $log
  16777. */
  16778. function setLogger(&$log)
  16779. {
  16780. if (is_object($log) && method_exists($log, 'log') ) {
  16781. $this->_logger = &$log;
  16782. } elseif (is_callable($log)) {
  16783. $this->_logger = &$log;
  16784. }
  16785. }
  16786. /**
  16787. * Set an error code => error message mapping callback
  16788. *
  16789. * This method sets the callback that can be used to generate error
  16790. * messages for any instance
  16791. * @param array|string Callback function/method
  16792. */
  16793. function setMessageCallback($msgCallback)
  16794. {
  16795. if (!$msgCallback) {
  16796. $this->_msgCallback = array(&$this, 'getErrorMessage');
  16797. } else {
  16798. if (is_callable($msgCallback)) {
  16799. $this->_msgCallback = $msgCallback;
  16800. }
  16801. }
  16802. }
  16803. /**
  16804. * Get an error code => error message mapping callback
  16805. *
  16806. * This method returns the current callback that can be used to generate error
  16807. * messages
  16808. * @return array|string|false Callback function/method or false if none
  16809. */
  16810. function getMessageCallback()
  16811. {
  16812. return $this->_msgCallback;
  16813. }
  16814. /**
  16815. * Sets a default callback to be used by all error stacks
  16816. *
  16817. * This method sets the callback that can be used to generate error
  16818. * messages for a singleton
  16819. * @param array|string Callback function/method
  16820. * @param string Package name, or false for all packages
  16821. */
  16822. public static function setDefaultCallback($callback = false, $package = false)
  16823. {
  16824. if (!is_callable($callback)) {
  16825. $callback = false;
  16826. }
  16827. $package = $package ? $package : '*';
  16828. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
  16829. }
  16830. /**
  16831. * Set a callback that generates context information (location of error) for an error stack
  16832. *
  16833. * This method sets the callback that can be used to generate context
  16834. * information for an error. Passing in NULL will disable context generation
  16835. * and remove the expensive call to debug_backtrace()
  16836. * @param array|string|null Callback function/method
  16837. */
  16838. function setContextCallback($contextCallback)
  16839. {
  16840. if ($contextCallback === null) {
  16841. return $this->_contextCallback = false;
  16842. }
  16843. if (!$contextCallback) {
  16844. $this->_contextCallback = array(&$this, 'getFileLine');
  16845. } else {
  16846. if (is_callable($contextCallback)) {
  16847. $this->_contextCallback = $contextCallback;
  16848. }
  16849. }
  16850. }
  16851. /**
  16852. * Set an error Callback
  16853. * If set to a valid callback, this will be called every time an error
  16854. * is pushed onto the stack. The return value will be used to determine
  16855. * whether to allow an error to be pushed or logged.
  16856. *
  16857. * The return value must be one of the ERRORSTACK_* constants.
  16858. *
  16859. * This functionality can be used to emulate PEAR's pushErrorHandling, and
  16860. * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
  16861. * the error stack or logging
  16862. * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  16863. * @see popCallback()
  16864. * @param string|array $cb
  16865. */
  16866. function pushCallback($cb)
  16867. {
  16868. array_push($this->_errorCallback, $cb);
  16869. }
  16870. /**
  16871. * Remove a callback from the error callback stack
  16872. * @see pushCallback()
  16873. * @return array|string|false
  16874. */
  16875. function popCallback()
  16876. {
  16877. if (!count($this->_errorCallback)) {
  16878. return false;
  16879. }
  16880. return array_pop($this->_errorCallback);
  16881. }
  16882. /**
  16883. * Set a temporary overriding error callback for every package error stack
  16884. *
  16885. * Use this to temporarily disable all existing callbacks (can be used
  16886. * to emulate the @ operator, for instance)
  16887. * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  16888. * @see staticPopCallback(), pushCallback()
  16889. * @param string|array $cb
  16890. */
  16891. public static function staticPushCallback($cb)
  16892. {
  16893. array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
  16894. }
  16895. /**
  16896. * Remove a temporary overriding error callback
  16897. * @see staticPushCallback()
  16898. * @return array|string|false
  16899. */
  16900. public static function staticPopCallback()
  16901. {
  16902. $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
  16903. if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
  16904. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  16905. }
  16906. return $ret;
  16907. }
  16908. /**
  16909. * Add an error to the stack
  16910. *
  16911. * If the message generator exists, it is called with 2 parameters.
  16912. * - the current Error Stack object
  16913. * - an array that is in the same format as an error. Available indices
  16914. * are 'code', 'package', 'time', 'params', 'level', and 'context'
  16915. *
  16916. * Next, if the error should contain context information, this is
  16917. * handled by the context grabbing method.
  16918. * Finally, the error is pushed onto the proper error stack
  16919. * @param int $code Package-specific error code
  16920. * @param string $level Error level. This is NOT spell-checked
  16921. * @param array $params associative array of error parameters
  16922. * @param string $msg Error message, or a portion of it if the message
  16923. * is to be generated
  16924. * @param array $repackage If this error re-packages an error pushed by
  16925. * another package, place the array returned from
  16926. * {@link pop()} in this parameter
  16927. * @param array $backtrace Protected parameter: use this to pass in the
  16928. * {@link debug_backtrace()} that should be used
  16929. * to find error context
  16930. * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  16931. * thrown. If a PEAR_Error is returned, the userinfo
  16932. * property is set to the following array:
  16933. *
  16934. * <code>
  16935. * array(
  16936. * 'code' => $code,
  16937. * 'params' => $params,
  16938. * 'package' => $this->_package,
  16939. * 'level' => $level,
  16940. * 'time' => time(),
  16941. * 'context' => $context,
  16942. * 'message' => $msg,
  16943. * //['repackage' => $err] repackaged error array/Exception class
  16944. * );
  16945. * </code>
  16946. *
  16947. * Normally, the previous array is returned.
  16948. */
  16949. function push($code, $level = 'error', $params = array(), $msg = false,
  16950. $repackage = false, $backtrace = false)
  16951. {
  16952. $context = false;
  16953. // grab error context
  16954. if ($this->_contextCallback) {
  16955. if (!$backtrace) {
  16956. $backtrace = debug_backtrace();
  16957. }
  16958. $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
  16959. }
  16960. // save error
  16961. $time = explode(' ', microtime());
  16962. $time = $time[1] + $time[0];
  16963. $err = array(
  16964. 'code' => $code,
  16965. 'params' => $params,
  16966. 'package' => $this->_package,
  16967. 'level' => $level,
  16968. 'time' => $time,
  16969. 'context' => $context,
  16970. 'message' => $msg,
  16971. );
  16972. if ($repackage) {
  16973. $err['repackage'] = $repackage;
  16974. }
  16975. // set up the error message, if necessary
  16976. if ($this->_msgCallback) {
  16977. $msg = call_user_func_array($this->_msgCallback,
  16978. array(&$this, $err));
  16979. $err['message'] = $msg;
  16980. }
  16981. $push = $log = true;
  16982. $die = false;
  16983. // try the overriding callback first
  16984. $callback = $this->staticPopCallback();
  16985. if ($callback) {
  16986. $this->staticPushCallback($callback);
  16987. }
  16988. if (!is_callable($callback)) {
  16989. // try the local callback next
  16990. $callback = $this->popCallback();
  16991. if (is_callable($callback)) {
  16992. $this->pushCallback($callback);
  16993. } else {
  16994. // try the default callback
  16995. $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
  16996. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
  16997. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
  16998. }
  16999. }
  17000. if (is_callable($callback)) {
  17001. switch(call_user_func($callback, $err)){
  17002. case PEAR_ERRORSTACK_IGNORE:
  17003. return $err;
  17004. break;
  17005. case PEAR_ERRORSTACK_PUSH:
  17006. $log = false;
  17007. break;
  17008. case PEAR_ERRORSTACK_LOG:
  17009. $push = false;
  17010. break;
  17011. case PEAR_ERRORSTACK_DIE:
  17012. $die = true;
  17013. break;
  17014. // anything else returned has the same effect as pushandlog
  17015. }
  17016. }
  17017. if ($push) {
  17018. array_unshift($this->_errors, $err);
  17019. if (!isset($this->_errorsByLevel[$err['level']])) {
  17020. $this->_errorsByLevel[$err['level']] = array();
  17021. }
  17022. $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
  17023. }
  17024. if ($log) {
  17025. if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
  17026. $this->_log($err);
  17027. }
  17028. }
  17029. if ($die) {
  17030. die();
  17031. }
  17032. if ($this->_compat && $push) {
  17033. return $this->raiseError($msg, $code, null, null, $err);
  17034. }
  17035. return $err;
  17036. }
  17037. /**
  17038. * Static version of {@link push()}
  17039. *
  17040. * @param string $package Package name this error belongs to
  17041. * @param int $code Package-specific error code
  17042. * @param string $level Error level. This is NOT spell-checked
  17043. * @param array $params associative array of error parameters
  17044. * @param string $msg Error message, or a portion of it if the message
  17045. * is to be generated
  17046. * @param array $repackage If this error re-packages an error pushed by
  17047. * another package, place the array returned from
  17048. * {@link pop()} in this parameter
  17049. * @param array $backtrace Protected parameter: use this to pass in the
  17050. * {@link debug_backtrace()} that should be used
  17051. * to find error context
  17052. * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  17053. * thrown. see docs for {@link push()}
  17054. */
  17055. public static function staticPush(
  17056. $package, $code, $level = 'error', $params = array(),
  17057. $msg = false, $repackage = false, $backtrace = false
  17058. ) {
  17059. $s = &PEAR_ErrorStack::singleton($package);
  17060. if ($s->_contextCallback) {
  17061. if (!$backtrace) {
  17062. if (function_exists('debug_backtrace')) {
  17063. $backtrace = debug_backtrace();
  17064. }
  17065. }
  17066. }
  17067. return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
  17068. }
  17069. /**
  17070. * Log an error using PEAR::Log
  17071. * @param array $err Error array
  17072. * @param array $levels Error level => Log constant map
  17073. * @access protected
  17074. */
  17075. function _log($err)
  17076. {
  17077. if ($this->_logger) {
  17078. $logger = &$this->_logger;
  17079. } else {
  17080. $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
  17081. }
  17082. if (is_a($logger, 'Log')) {
  17083. $levels = array(
  17084. 'exception' => PEAR_LOG_CRIT,
  17085. 'alert' => PEAR_LOG_ALERT,
  17086. 'critical' => PEAR_LOG_CRIT,
  17087. 'error' => PEAR_LOG_ERR,
  17088. 'warning' => PEAR_LOG_WARNING,
  17089. 'notice' => PEAR_LOG_NOTICE,
  17090. 'info' => PEAR_LOG_INFO,
  17091. 'debug' => PEAR_LOG_DEBUG);
  17092. if (isset($levels[$err['level']])) {
  17093. $level = $levels[$err['level']];
  17094. } else {
  17095. $level = PEAR_LOG_INFO;
  17096. }
  17097. $logger->log($err['message'], $level, $err);
  17098. } else { // support non-standard logs
  17099. call_user_func($logger, $err);
  17100. }
  17101. }
  17102. /**
  17103. * Pop an error off of the error stack
  17104. *
  17105. * @return false|array
  17106. * @since 0.4alpha it is no longer possible to specify a specific error
  17107. * level to return - the last error pushed will be returned, instead
  17108. */
  17109. function pop()
  17110. {
  17111. $err = @array_shift($this->_errors);
  17112. if (!is_null($err)) {
  17113. @array_pop($this->_errorsByLevel[$err['level']]);
  17114. if (!count($this->_errorsByLevel[$err['level']])) {
  17115. unset($this->_errorsByLevel[$err['level']]);
  17116. }
  17117. }
  17118. return $err;
  17119. }
  17120. /**
  17121. * Pop an error off of the error stack, static method
  17122. *
  17123. * @param string package name
  17124. * @return boolean
  17125. * @since PEAR1.5.0a1
  17126. */
  17127. static function staticPop($package)
  17128. {
  17129. if ($package) {
  17130. if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  17131. return false;
  17132. }
  17133. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
  17134. }
  17135. }
  17136. /**
  17137. * Determine whether there are any errors on the stack
  17138. * @param string|array Level name. Use to determine if any errors
  17139. * of level (string), or levels (array) have been pushed
  17140. * @return boolean
  17141. */
  17142. function hasErrors($level = false)
  17143. {
  17144. if ($level) {
  17145. return isset($this->_errorsByLevel[$level]);
  17146. }
  17147. return count($this->_errors);
  17148. }
  17149. /**
  17150. * Retrieve all errors since last purge
  17151. *
  17152. * @param boolean set in order to empty the error stack
  17153. * @param string level name, to return only errors of a particular severity
  17154. * @return array
  17155. */
  17156. function getErrors($purge = false, $level = false)
  17157. {
  17158. if (!$purge) {
  17159. if ($level) {
  17160. if (!isset($this->_errorsByLevel[$level])) {
  17161. return array();
  17162. } else {
  17163. return $this->_errorsByLevel[$level];
  17164. }
  17165. } else {
  17166. return $this->_errors;
  17167. }
  17168. }
  17169. if ($level) {
  17170. $ret = $this->_errorsByLevel[$level];
  17171. foreach ($this->_errorsByLevel[$level] as $i => $unused) {
  17172. // entries are references to the $_errors array
  17173. $this->_errorsByLevel[$level][$i] = false;
  17174. }
  17175. // array_filter removes all entries === false
  17176. $this->_errors = array_filter($this->_errors);
  17177. unset($this->_errorsByLevel[$level]);
  17178. return $ret;
  17179. }
  17180. $ret = $this->_errors;
  17181. $this->_errors = array();
  17182. $this->_errorsByLevel = array();
  17183. return $ret;
  17184. }
  17185. /**
  17186. * Determine whether there are any errors on a single error stack, or on any error stack
  17187. *
  17188. * The optional parameter can be used to test the existence of any errors without the need of
  17189. * singleton instantiation
  17190. * @param string|false Package name to check for errors
  17191. * @param string Level name to check for a particular severity
  17192. * @return boolean
  17193. */
  17194. public static function staticHasErrors($package = false, $level = false)
  17195. {
  17196. if ($package) {
  17197. if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  17198. return false;
  17199. }
  17200. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
  17201. }
  17202. foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  17203. if ($obj->hasErrors($level)) {
  17204. return true;
  17205. }
  17206. }
  17207. return false;
  17208. }
  17209. /**
  17210. * Get a list of all errors since last purge, organized by package
  17211. * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
  17212. * @param boolean $purge Set to purge the error stack of existing errors
  17213. * @param string $level Set to a level name in order to retrieve only errors of a particular level
  17214. * @param boolean $merge Set to return a flat array, not organized by package
  17215. * @param array $sortfunc Function used to sort a merged array - default
  17216. * sorts by time, and should be good for most cases
  17217. *
  17218. * @return array
  17219. */
  17220. public static function staticGetErrors(
  17221. $purge = false, $level = false, $merge = false,
  17222. $sortfunc = array('PEAR_ErrorStack', '_sortErrors')
  17223. ) {
  17224. $ret = array();
  17225. if (!is_callable($sortfunc)) {
  17226. $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
  17227. }
  17228. foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  17229. $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
  17230. if ($test) {
  17231. if ($merge) {
  17232. $ret = array_merge($ret, $test);
  17233. } else {
  17234. $ret[$package] = $test;
  17235. }
  17236. }
  17237. }
  17238. if ($merge) {
  17239. usort($ret, $sortfunc);
  17240. }
  17241. return $ret;
  17242. }
  17243. /**
  17244. * Error sorting function, sorts by time
  17245. * @access private
  17246. */
  17247. public static function _sortErrors($a, $b)
  17248. {
  17249. if ($a['time'] == $b['time']) {
  17250. return 0;
  17251. }
  17252. if ($a['time'] < $b['time']) {
  17253. return 1;
  17254. }
  17255. return -1;
  17256. }
  17257. /**
  17258. * Standard file/line number/function/class context callback
  17259. *
  17260. * This function uses a backtrace generated from {@link debug_backtrace()}
  17261. * and so will not work at all in PHP < 4.3.0. The frame should
  17262. * reference the frame that contains the source of the error.
  17263. * @return array|false either array('file' => file, 'line' => line,
  17264. * 'function' => function name, 'class' => class name) or
  17265. * if this doesn't work, then false
  17266. * @param unused
  17267. * @param integer backtrace frame.
  17268. * @param array Results of debug_backtrace()
  17269. */
  17270. public static function getFileLine($code, $params, $backtrace = null)
  17271. {
  17272. if ($backtrace === null) {
  17273. return false;
  17274. }
  17275. $frame = 0;
  17276. $functionframe = 1;
  17277. if (!isset($backtrace[1])) {
  17278. $functionframe = 0;
  17279. } else {
  17280. while (isset($backtrace[$functionframe]['function']) &&
  17281. $backtrace[$functionframe]['function'] == 'eval' &&
  17282. isset($backtrace[$functionframe + 1])) {
  17283. $functionframe++;
  17284. }
  17285. }
  17286. if (isset($backtrace[$frame])) {
  17287. if (!isset($backtrace[$frame]['file'])) {
  17288. $frame++;
  17289. }
  17290. $funcbacktrace = $backtrace[$functionframe];
  17291. $filebacktrace = $backtrace[$frame];
  17292. $ret = array('file' => $filebacktrace['file'],
  17293. 'line' => $filebacktrace['line']);
  17294. // rearrange for eval'd code or create function errors
  17295. if (strpos($filebacktrace['file'], '(') &&
  17296. preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
  17297. $matches)) {
  17298. $ret['file'] = $matches[1];
  17299. $ret['line'] = $matches[2] + 0;
  17300. }
  17301. if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
  17302. if ($funcbacktrace['function'] != 'eval') {
  17303. if ($funcbacktrace['function'] == '__lambda_func') {
  17304. $ret['function'] = 'create_function() code';
  17305. } else {
  17306. $ret['function'] = $funcbacktrace['function'];
  17307. }
  17308. }
  17309. }
  17310. if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
  17311. $ret['class'] = $funcbacktrace['class'];
  17312. }
  17313. return $ret;
  17314. }
  17315. return false;
  17316. }
  17317. /**
  17318. * Standard error message generation callback
  17319. *
  17320. * This method may also be called by a custom error message generator
  17321. * to fill in template values from the params array, simply
  17322. * set the third parameter to the error message template string to use
  17323. *
  17324. * The special variable %__msg% is reserved: use it only to specify
  17325. * where a message passed in by the user should be placed in the template,
  17326. * like so:
  17327. *
  17328. * Error message: %msg% - internal error
  17329. *
  17330. * If the message passed like so:
  17331. *
  17332. * <code>
  17333. * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
  17334. * </code>
  17335. *
  17336. * The returned error message will be "Error message: server error 500 -
  17337. * internal error"
  17338. * @param PEAR_ErrorStack
  17339. * @param array
  17340. * @param string|false Pre-generated error message template
  17341. *
  17342. * @return string
  17343. */
  17344. public static function getErrorMessage(&$stack, $err, $template = false)
  17345. {
  17346. if ($template) {
  17347. $mainmsg = $template;
  17348. } else {
  17349. $mainmsg = $stack->getErrorMessageTemplate($err['code']);
  17350. }
  17351. $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
  17352. if (is_array($err['params']) && count($err['params'])) {
  17353. foreach ($err['params'] as $name => $val) {
  17354. if (is_array($val)) {
  17355. // @ is needed in case $val is a multi-dimensional array
  17356. $val = @implode(', ', $val);
  17357. }
  17358. if (is_object($val)) {
  17359. if (method_exists($val, '__toString')) {
  17360. $val = $val->__toString();
  17361. } else {
  17362. PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
  17363. 'warning', array('obj' => get_class($val)),
  17364. 'object %obj% passed into getErrorMessage, but has no __toString() method');
  17365. $val = 'Object';
  17366. }
  17367. }
  17368. $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
  17369. }
  17370. }
  17371. return $mainmsg;
  17372. }
  17373. /**
  17374. * Standard Error Message Template generator from code
  17375. * @return string
  17376. */
  17377. function getErrorMessageTemplate($code)
  17378. {
  17379. if (!isset($this->_errorMsgs[$code])) {
  17380. return '%__msg%';
  17381. }
  17382. return $this->_errorMsgs[$code];
  17383. }
  17384. /**
  17385. * Set the Error Message Template array
  17386. *
  17387. * The array format must be:
  17388. * <pre>
  17389. * array(error code => 'message template',...)
  17390. * </pre>
  17391. *
  17392. * Error message parameters passed into {@link push()} will be used as input
  17393. * for the error message. If the template is 'message %foo% was %bar%', and the
  17394. * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
  17395. * be 'message one was six'
  17396. * @return string
  17397. */
  17398. function setErrorMessageTemplate($template)
  17399. {
  17400. $this->_errorMsgs = $template;
  17401. }
  17402. /**
  17403. * emulate PEAR::raiseError()
  17404. *
  17405. * @return PEAR_Error
  17406. */
  17407. function raiseError()
  17408. {
  17409. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  17410. $args = func_get_args();
  17411. return call_user_func_array(array('PEAR', 'raiseError'), $args);
  17412. }
  17413. }
  17414. $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
  17415. $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
  17416. ?>
  17417. <?php
  17418. /**
  17419. * PEAR_Frontend, the singleton-based frontend for user input/output
  17420. *
  17421. * PHP versions 4 and 5
  17422. *
  17423. * @category pear
  17424. * @package PEAR
  17425. * @author Greg Beaver <cellog@php.net>
  17426. * @copyright 1997-2009 The Authors
  17427. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  17428. * @link http://pear.php.net/package/PEAR
  17429. * @since File available since Release 1.4.0a1
  17430. */
  17431. /**
  17432. * Include error handling
  17433. */
  17434. //require_once 'PEAR.php';
  17435. /**
  17436. * Which user interface class is being used.
  17437. * @var string class name
  17438. */
  17439. $GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
  17440. /**
  17441. * Instance of $_PEAR_Command_uiclass.
  17442. * @var object
  17443. */
  17444. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
  17445. /**
  17446. * Singleton-based frontend for PEAR user input/output
  17447. *
  17448. * @category pear
  17449. * @package PEAR
  17450. * @author Greg Beaver <cellog@php.net>
  17451. * @copyright 1997-2009 The Authors
  17452. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  17453. * @version Release: 1.10.10
  17454. * @link http://pear.php.net/package/PEAR
  17455. * @since Class available since Release 1.4.0a1
  17456. */
  17457. class PEAR_Frontend extends PEAR
  17458. {
  17459. /**
  17460. * Retrieve the frontend object
  17461. * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
  17462. */
  17463. public static function &singleton($type = null)
  17464. {
  17465. if ($type === null) {
  17466. if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
  17467. $a = false;
  17468. return $a;
  17469. }
  17470. return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  17471. }
  17472. $a = PEAR_Frontend::setFrontendClass($type);
  17473. return $a;
  17474. }
  17475. /**
  17476. * Set the frontend class that will be used by calls to {@link singleton()}
  17477. *
  17478. * Frontends are expected to conform to the PEAR naming standard of
  17479. * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php)
  17480. * @param string $uiclass full class name
  17481. * @return PEAR_Frontend
  17482. */
  17483. public static function &setFrontendClass($uiclass)
  17484. {
  17485. if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  17486. is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
  17487. return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  17488. }
  17489. if (!class_exists($uiclass)) {
  17490. $file = 'phar://go-pear.phar/' . str_replace('_', '/', $uiclass) . '.php';
  17491. if (PEAR_Frontend::isIncludeable($file)) {
  17492. include_once $file;
  17493. }
  17494. }
  17495. if (class_exists($uiclass)) {
  17496. $obj = new $uiclass;
  17497. // quick test to see if this class implements a few of the most
  17498. // important frontend methods
  17499. if (is_a($obj, 'PEAR_Frontend')) {
  17500. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
  17501. $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
  17502. return $obj;
  17503. }
  17504. $err = PEAR::raiseError("not a frontend class: $uiclass");
  17505. return $err;
  17506. }
  17507. $err = PEAR::raiseError("no such class: $uiclass");
  17508. return $err;
  17509. }
  17510. /**
  17511. * Set the frontend class that will be used by calls to {@link singleton()}
  17512. *
  17513. * Frontends are expected to be a descendant of PEAR_Frontend
  17514. * @param PEAR_Frontend
  17515. * @return PEAR_Frontend
  17516. */
  17517. public static function &setFrontendObject($uiobject)
  17518. {
  17519. if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  17520. is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) {
  17521. return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  17522. }
  17523. if (!is_a($uiobject, 'PEAR_Frontend')) {
  17524. $err = PEAR::raiseError('not a valid frontend class: (' .
  17525. get_class($uiobject) . ')');
  17526. return $err;
  17527. }
  17528. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
  17529. $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
  17530. return $uiobject;
  17531. }
  17532. /**
  17533. * @param string $path relative or absolute include path
  17534. * @return boolean
  17535. */
  17536. public static function isIncludeable($path)
  17537. {
  17538. if (file_exists($path) && is_readable($path)) {
  17539. return true;
  17540. }
  17541. $fp = @fopen($path, 'r', true);
  17542. if ($fp) {
  17543. fclose($fp);
  17544. return true;
  17545. }
  17546. return false;
  17547. }
  17548. /**
  17549. * @param PEAR_Config
  17550. */
  17551. function setConfig(&$config)
  17552. {
  17553. }
  17554. /**
  17555. * This can be overridden to allow session-based temporary file management
  17556. *
  17557. * By default, all files are deleted at the end of a session. The web installer
  17558. * needs to be able to sustain a list over many sessions in order to support
  17559. * user interaction with install scripts
  17560. */
  17561. static function addTempFile($file)
  17562. {
  17563. $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  17564. }
  17565. /**
  17566. * Log an action
  17567. *
  17568. * @param string $msg the message to log
  17569. * @param boolean $append_crlf
  17570. * @return boolean true
  17571. * @abstract
  17572. */
  17573. function log($msg, $append_crlf = true)
  17574. {
  17575. }
  17576. /**
  17577. * Run a post-installation script
  17578. *
  17579. * @param array $scripts array of post-install scripts
  17580. * @abstract
  17581. */
  17582. function runPostinstallScripts(&$scripts)
  17583. {
  17584. }
  17585. /**
  17586. * Display human-friendly output formatted depending on the
  17587. * $command parameter.
  17588. *
  17589. * This should be able to handle basic output data with no command
  17590. * @param mixed $data data structure containing the information to display
  17591. * @param string $command command from which this method was called
  17592. * @abstract
  17593. */
  17594. function outputData($data, $command = '_default')
  17595. {
  17596. }
  17597. /**
  17598. * Display a modal form dialog and return the given input
  17599. *
  17600. * A frontend that requires multiple requests to retrieve and process
  17601. * data must take these needs into account, and implement the request
  17602. * handling code.
  17603. * @param string $command command from which this method was called
  17604. * @param array $prompts associative array. keys are the input field names
  17605. * and values are the description
  17606. * @param array $types array of input field types (text, password,
  17607. * etc.) keys have to be the same like in $prompts
  17608. * @param array $defaults array of default values. again keys have
  17609. * to be the same like in $prompts. Do not depend
  17610. * on a default value being set.
  17611. * @return array input sent by the user
  17612. * @abstract
  17613. */
  17614. function userDialog($command, $prompts, $types = array(), $defaults = array())
  17615. {
  17616. }
  17617. }
  17618. <?php
  17619. /**
  17620. * PEAR_Frontend_CLI
  17621. *
  17622. * PHP versions 4 and 5
  17623. *
  17624. * @category pear
  17625. * @package PEAR
  17626. * @author Stig Bakken <ssb@php.net>
  17627. * @author Greg Beaver <cellog@php.net>
  17628. * @copyright 1997-2009 The Authors
  17629. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  17630. * @link http://pear.php.net/package/PEAR
  17631. * @since File available since Release 0.1
  17632. */
  17633. /**
  17634. * base class
  17635. */
  17636. require_once 'phar://go-pear.phar/' . 'PEAR/Frontend.php';
  17637. /**
  17638. * Command-line Frontend for the PEAR Installer
  17639. * @category pear
  17640. * @package PEAR
  17641. * @author Stig Bakken <ssb@php.net>
  17642. * @author Greg Beaver <cellog@php.net>
  17643. * @copyright 1997-2009 The Authors
  17644. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  17645. * @version Release: 1.10.10
  17646. * @link http://pear.php.net/package/PEAR
  17647. * @since Class available since Release 0.1
  17648. */
  17649. class PEAR_Frontend_CLI extends PEAR_Frontend
  17650. {
  17651. /**
  17652. * What type of user interface this frontend is for.
  17653. * @var string
  17654. * @access public
  17655. */
  17656. var $type = 'CLI';
  17657. var $lp = ''; // line prefix
  17658. var $params = array();
  17659. var $term = array(
  17660. 'bold' => '',
  17661. 'normal' => '',
  17662. );
  17663. function __construct()
  17664. {
  17665. parent::__construct();
  17666. $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
  17667. if (function_exists('posix_isatty') && !posix_isatty(1)) {
  17668. // output is being redirected to a file or through a pipe
  17669. } elseif ($term) {
  17670. if (preg_match('/^(xterm|vt220|linux)/', $term)) {
  17671. $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109);
  17672. $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109);
  17673. } elseif (preg_match('/^vt100/', $term)) {
  17674. $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
  17675. $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
  17676. }
  17677. } elseif (OS_WINDOWS) {
  17678. // XXX add ANSI codes here
  17679. }
  17680. }
  17681. /**
  17682. * @param object PEAR_Error object
  17683. */
  17684. function displayError($e)
  17685. {
  17686. return $this->_displayLine($e->getMessage());
  17687. }
  17688. /**
  17689. * @param object PEAR_Error object
  17690. */
  17691. function displayFatalError($eobj)
  17692. {
  17693. $this->displayError($eobj);
  17694. if (class_exists('PEAR_Config')) {
  17695. $config = &PEAR_Config::singleton();
  17696. if ($config->get('verbose') > 5) {
  17697. if (function_exists('debug_print_backtrace')) {
  17698. debug_print_backtrace();
  17699. exit(1);
  17700. }
  17701. $raised = false;
  17702. foreach (debug_backtrace() as $i => $frame) {
  17703. if (!$raised) {
  17704. if (isset($frame['class'])
  17705. && strtolower($frame['class']) == 'pear'
  17706. && strtolower($frame['function']) == 'raiseerror'
  17707. ) {
  17708. $raised = true;
  17709. } else {
  17710. continue;
  17711. }
  17712. }
  17713. $frame['class'] = !isset($frame['class']) ? '' : $frame['class'];
  17714. $frame['type'] = !isset($frame['type']) ? '' : $frame['type'];
  17715. $frame['function'] = !isset($frame['function']) ? '' : $frame['function'];
  17716. $frame['line'] = !isset($frame['line']) ? '' : $frame['line'];
  17717. $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
  17718. }
  17719. }
  17720. }
  17721. exit(1);
  17722. }
  17723. /**
  17724. * Instruct the runInstallScript method to skip a paramgroup that matches the
  17725. * id value passed in.
  17726. *
  17727. * This method is useful for dynamically configuring which sections of a post-install script
  17728. * will be run based on the user's setup, which is very useful for making flexible
  17729. * post-install scripts without losing the cross-Frontend ability to retrieve user input
  17730. * @param string
  17731. */
  17732. function skipParamgroup($id)
  17733. {
  17734. $this->_skipSections[$id] = true;
  17735. }
  17736. function runPostinstallScripts(&$scripts)
  17737. {
  17738. foreach ($scripts as $i => $script) {
  17739. $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
  17740. }
  17741. }
  17742. /**
  17743. * @param array $xml contents of postinstallscript tag
  17744. * @param object $script post-installation script
  17745. * @param string install|upgrade
  17746. */
  17747. function runInstallScript($xml, &$script)
  17748. {
  17749. $this->_skipSections = array();
  17750. if (!is_array($xml) || !isset($xml['paramgroup'])) {
  17751. $script->run(array(), '_default');
  17752. return;
  17753. }
  17754. $completedPhases = array();
  17755. if (!isset($xml['paramgroup'][0])) {
  17756. $xml['paramgroup'] = array($xml['paramgroup']);
  17757. }
  17758. foreach ($xml['paramgroup'] as $group) {
  17759. if (isset($this->_skipSections[$group['id']])) {
  17760. // the post-install script chose to skip this section dynamically
  17761. continue;
  17762. }
  17763. if (isset($group['name'])) {
  17764. $paramname = explode('::', $group['name']);
  17765. if ($lastgroup['id'] != $paramname[0]) {
  17766. continue;
  17767. }
  17768. $group['name'] = $paramname[1];
  17769. if (!isset($answers)) {
  17770. return;
  17771. }
  17772. if (isset($answers[$group['name']])) {
  17773. switch ($group['conditiontype']) {
  17774. case '=' :
  17775. if ($answers[$group['name']] != $group['value']) {
  17776. continue 2;
  17777. }
  17778. break;
  17779. case '!=' :
  17780. if ($answers[$group['name']] == $group['value']) {
  17781. continue 2;
  17782. }
  17783. break;
  17784. case 'preg_match' :
  17785. if (!@preg_match('/' . $group['value'] . '/',
  17786. $answers[$group['name']])) {
  17787. continue 2;
  17788. }
  17789. break;
  17790. default :
  17791. return;
  17792. }
  17793. }
  17794. }
  17795. $lastgroup = $group;
  17796. if (isset($group['instructions'])) {
  17797. $this->_display($group['instructions']);
  17798. }
  17799. if (!isset($group['param'][0])) {
  17800. $group['param'] = array($group['param']);
  17801. }
  17802. if (isset($group['param'])) {
  17803. if (method_exists($script, 'postProcessPrompts')) {
  17804. $prompts = $script->postProcessPrompts($group['param'], $group['id']);
  17805. if (!is_array($prompts) || count($prompts) != count($group['param'])) {
  17806. $this->outputData('postinstall', 'Error: post-install script did not ' .
  17807. 'return proper post-processed prompts');
  17808. $prompts = $group['param'];
  17809. } else {
  17810. foreach ($prompts as $i => $var) {
  17811. if (!is_array($var) || !isset($var['prompt']) ||
  17812. !isset($var['name']) ||
  17813. ($var['name'] != $group['param'][$i]['name']) ||
  17814. ($var['type'] != $group['param'][$i]['type'])
  17815. ) {
  17816. $this->outputData('postinstall', 'Error: post-install script ' .
  17817. 'modified the variables or prompts, severe security risk. ' .
  17818. 'Will instead use the defaults from the package.xml');
  17819. $prompts = $group['param'];
  17820. }
  17821. }
  17822. }
  17823. $answers = $this->confirmDialog($prompts);
  17824. } else {
  17825. $answers = $this->confirmDialog($group['param']);
  17826. }
  17827. }
  17828. if ((isset($answers) && $answers) || !isset($group['param'])) {
  17829. if (!isset($answers)) {
  17830. $answers = array();
  17831. }
  17832. array_unshift($completedPhases, $group['id']);
  17833. if (!$script->run($answers, $group['id'])) {
  17834. $script->run($completedPhases, '_undoOnError');
  17835. return;
  17836. }
  17837. } else {
  17838. $script->run($completedPhases, '_undoOnError');
  17839. return;
  17840. }
  17841. }
  17842. }
  17843. /**
  17844. * Ask for user input, confirm the answers and continue until the user is satisfied
  17845. * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
  17846. * 'text to display', 'type' => 'string'[, default => 'default value'])
  17847. * @return array
  17848. */
  17849. function confirmDialog($params)
  17850. {
  17851. $answers = $prompts = $types = array();
  17852. foreach ($params as $param) {
  17853. $prompts[$param['name']] = $param['prompt'];
  17854. $types[$param['name']] = $param['type'];
  17855. $answers[$param['name']] = isset($param['default']) ? $param['default'] : '';
  17856. }
  17857. $tried = false;
  17858. do {
  17859. if ($tried) {
  17860. $i = 1;
  17861. foreach ($answers as $var => $value) {
  17862. if (!strlen($value)) {
  17863. echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
  17864. }
  17865. $i++;
  17866. }
  17867. }
  17868. $answers = $this->userDialog('', $prompts, $types, $answers);
  17869. $tried = true;
  17870. } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
  17871. return $answers;
  17872. }
  17873. function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20)
  17874. {
  17875. if (!is_array($prompts)) {
  17876. return array();
  17877. }
  17878. $testprompts = array_keys($prompts);
  17879. $result = $defaults;
  17880. reset($prompts);
  17881. if (count($prompts) === 1) {
  17882. foreach ($prompts as $key => $prompt) {
  17883. $type = $types[$key];
  17884. $default = @$defaults[$key];
  17885. print "$prompt ";
  17886. if ($default) {
  17887. print "[$default] ";
  17888. }
  17889. print ": ";
  17890. $line = fgets(STDIN, 2048);
  17891. $result[$key] = ($default && trim($line) == '') ? $default : trim($line);
  17892. }
  17893. return $result;
  17894. }
  17895. $first_run = true;
  17896. while (true) {
  17897. $descLength = max(array_map('strlen', $prompts));
  17898. $descFormat = "%-{$descLength}s";
  17899. $last = count($prompts);
  17900. $i = 0;
  17901. foreach ($prompts as $n => $var) {
  17902. $res = isset($result[$n]) ? $result[$n] : null;
  17903. printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res);
  17904. }
  17905. print "\n1-$last, 'all', 'abort', or Enter to continue: ";
  17906. $tmp = trim(fgets(STDIN, 1024));
  17907. if (empty($tmp)) {
  17908. break;
  17909. }
  17910. if ($tmp == 'abort') {
  17911. return false;
  17912. }
  17913. if (isset($testprompts[(int)$tmp - 1])) {
  17914. $var = $testprompts[(int)$tmp - 1];
  17915. $desc = $prompts[$var];
  17916. $current = @$result[$var];
  17917. print "$desc [$current] : ";
  17918. $tmp = trim(fgets(STDIN, 1024));
  17919. if ($tmp !== '') {
  17920. $result[$var] = $tmp;
  17921. }
  17922. } elseif ($tmp == 'all') {
  17923. foreach ($prompts as $var => $desc) {
  17924. $current = $result[$var];
  17925. print "$desc [$current] : ";
  17926. $tmp = trim(fgets(STDIN, 1024));
  17927. if (trim($tmp) !== '') {
  17928. $result[$var] = trim($tmp);
  17929. }
  17930. }
  17931. }
  17932. $first_run = false;
  17933. }
  17934. return $result;
  17935. }
  17936. function userConfirm($prompt, $default = 'yes')
  17937. {
  17938. trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
  17939. static $positives = array('y', 'yes', 'on', '1');
  17940. static $negatives = array('n', 'no', 'off', '0');
  17941. print "$this->lp$prompt [$default] : ";
  17942. $fp = fopen("php://stdin", "r");
  17943. $line = fgets($fp, 2048);
  17944. fclose($fp);
  17945. $answer = strtolower(trim($line));
  17946. if (empty($answer)) {
  17947. $answer = $default;
  17948. }
  17949. if (in_array($answer, $positives)) {
  17950. return true;
  17951. }
  17952. if (in_array($answer, $negatives)) {
  17953. return false;
  17954. }
  17955. if (in_array($default, $positives)) {
  17956. return true;
  17957. }
  17958. return false;
  17959. }
  17960. function outputData($data, $command = '_default')
  17961. {
  17962. switch ($command) {
  17963. case 'channel-info':
  17964. foreach ($data as $type => $section) {
  17965. if ($type == 'main') {
  17966. $section['data'] = array_values($section['data']);
  17967. }
  17968. $this->outputData($section);
  17969. }
  17970. break;
  17971. case 'install':
  17972. case 'upgrade':
  17973. case 'upgrade-all':
  17974. if (is_array($data) && isset($data['release_warnings'])) {
  17975. $this->_displayLine('');
  17976. $this->_startTable(array(
  17977. 'border' => false,
  17978. 'caption' => 'Release Warnings'
  17979. ));
  17980. $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
  17981. $this->_endTable();
  17982. $this->_displayLine('');
  17983. }
  17984. $this->_displayLine(is_array($data) ? $data['data'] : $data);
  17985. break;
  17986. case 'search':
  17987. $this->_startTable($data);
  17988. if (isset($data['headline']) && is_array($data['headline'])) {
  17989. $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  17990. }
  17991. $packages = array();
  17992. foreach($data['data'] as $category) {
  17993. foreach($category as $name => $pkg) {
  17994. $packages[$pkg[0]] = $pkg;
  17995. }
  17996. }
  17997. $p = array_keys($packages);
  17998. natcasesort($p);
  17999. foreach ($p as $name) {
  18000. $this->_tableRow($packages[$name], null, array(1 => array('wrap' => 55)));
  18001. }
  18002. $this->_endTable();
  18003. break;
  18004. case 'list-all':
  18005. if (!isset($data['data'])) {
  18006. $this->_displayLine('No packages in channel');
  18007. break;
  18008. }
  18009. $this->_startTable($data);
  18010. if (isset($data['headline']) && is_array($data['headline'])) {
  18011. $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  18012. }
  18013. $packages = array();
  18014. foreach($data['data'] as $category) {
  18015. foreach($category as $name => $pkg) {
  18016. $packages[$pkg[0]] = $pkg;
  18017. }
  18018. }
  18019. $p = array_keys($packages);
  18020. natcasesort($p);
  18021. foreach ($p as $name) {
  18022. $pkg = $packages[$name];
  18023. unset($pkg[4], $pkg[5]);
  18024. $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
  18025. }
  18026. $this->_endTable();
  18027. break;
  18028. case 'config-show':
  18029. $data['border'] = false;
  18030. $opts = array(
  18031. 0 => array('wrap' => 30),
  18032. 1 => array('wrap' => 20),
  18033. 2 => array('wrap' => 35)
  18034. );
  18035. $this->_startTable($data);
  18036. if (isset($data['headline']) && is_array($data['headline'])) {
  18037. $this->_tableRow($data['headline'], array('bold' => true), $opts);
  18038. }
  18039. foreach ($data['data'] as $group) {
  18040. foreach ($group as $value) {
  18041. if ($value[2] == '') {
  18042. $value[2] = "<not set>";
  18043. }
  18044. $this->_tableRow($value, null, $opts);
  18045. }
  18046. }
  18047. $this->_endTable();
  18048. break;
  18049. case 'remote-info':
  18050. $d = $data;
  18051. $data = array(
  18052. 'caption' => 'Package details:',
  18053. 'border' => false,
  18054. 'data' => array(
  18055. array("Latest", $data['stable']),
  18056. array("Installed", $data['installed']),
  18057. array("Package", $data['name']),
  18058. array("License", $data['license']),
  18059. array("Category", $data['category']),
  18060. array("Summary", $data['summary']),
  18061. array("Description", $data['description']),
  18062. ),
  18063. );
  18064. if (isset($d['deprecated']) && $d['deprecated']) {
  18065. $conf = &PEAR_Config::singleton();
  18066. $reg = $conf->getRegistry();
  18067. $name = $reg->parsedPackageNameToString($d['deprecated'], true);
  18068. $data['data'][] = array('Deprecated! use', $name);
  18069. }
  18070. default: {
  18071. if (is_array($data)) {
  18072. $this->_startTable($data);
  18073. $count = count($data['data'][0]);
  18074. if ($count == 2) {
  18075. $opts = array(0 => array('wrap' => 25),
  18076. 1 => array('wrap' => 48)
  18077. );
  18078. } elseif ($count == 3) {
  18079. $opts = array(0 => array('wrap' => 30),
  18080. 1 => array('wrap' => 20),
  18081. 2 => array('wrap' => 35)
  18082. );
  18083. } else {
  18084. $opts = null;
  18085. }
  18086. if (isset($data['headline']) && is_array($data['headline'])) {
  18087. $this->_tableRow($data['headline'],
  18088. array('bold' => true),
  18089. $opts);
  18090. }
  18091. if (is_array($data['data'])) {
  18092. foreach($data['data'] as $row) {
  18093. $this->_tableRow($row, null, $opts);
  18094. }
  18095. } else {
  18096. $this->_tableRow(array($data['data']), null, $opts);
  18097. }
  18098. $this->_endTable();
  18099. } else {
  18100. $this->_displayLine($data);
  18101. }
  18102. }
  18103. }
  18104. }
  18105. function log($text, $append_crlf = true)
  18106. {
  18107. if ($append_crlf) {
  18108. return $this->_displayLine($text);
  18109. }
  18110. return $this->_display($text);
  18111. }
  18112. function bold($text)
  18113. {
  18114. if (empty($this->term['bold'])) {
  18115. return strtoupper($text);
  18116. }
  18117. return $this->term['bold'] . $text . $this->term['normal'];
  18118. }
  18119. function _displayHeading($title)
  18120. {
  18121. print $this->lp.$this->bold($title)."\n";
  18122. print $this->lp.str_repeat("=", strlen($title))."\n";
  18123. }
  18124. function _startTable($params = array())
  18125. {
  18126. $params['table_data'] = array();
  18127. $params['widest'] = array(); // indexed by column
  18128. $params['highest'] = array(); // indexed by row
  18129. $params['ncols'] = 0;
  18130. $this->params = $params;
  18131. }
  18132. function _tableRow($columns, $rowparams = array(), $colparams = array())
  18133. {
  18134. $highest = 1;
  18135. for ($i = 0; $i < count($columns); $i++) {
  18136. $col = &$columns[$i];
  18137. if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
  18138. $col = wordwrap($col, $colparams[$i]['wrap']);
  18139. }
  18140. if (strpos($col, "\n") !== false) {
  18141. $multiline = explode("\n", $col);
  18142. $w = 0;
  18143. foreach ($multiline as $n => $line) {
  18144. $len = strlen($line);
  18145. if ($len > $w) {
  18146. $w = $len;
  18147. }
  18148. }
  18149. $lines = count($multiline);
  18150. } else {
  18151. $w = strlen($col);
  18152. }
  18153. if (isset($this->params['widest'][$i])) {
  18154. if ($w > $this->params['widest'][$i]) {
  18155. $this->params['widest'][$i] = $w;
  18156. }
  18157. } else {
  18158. $this->params['widest'][$i] = $w;
  18159. }
  18160. $tmp = count_chars($columns[$i], 1);
  18161. // handle unix, mac and windows formats
  18162. $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
  18163. if ($lines > $highest) {
  18164. $highest = $lines;
  18165. }
  18166. }
  18167. if (count($columns) > $this->params['ncols']) {
  18168. $this->params['ncols'] = count($columns);
  18169. }
  18170. $new_row = array(
  18171. 'data' => $columns,
  18172. 'height' => $highest,
  18173. 'rowparams' => $rowparams,
  18174. 'colparams' => $colparams,
  18175. );
  18176. $this->params['table_data'][] = $new_row;
  18177. }
  18178. function _endTable()
  18179. {
  18180. extract($this->params);
  18181. if (!empty($caption)) {
  18182. $this->_displayHeading($caption);
  18183. }
  18184. if (count($table_data) === 0) {
  18185. return;
  18186. }
  18187. if (!isset($width)) {
  18188. $width = $widest;
  18189. } else {
  18190. for ($i = 0; $i < $ncols; $i++) {
  18191. if (!isset($width[$i])) {
  18192. $width[$i] = $widest[$i];
  18193. }
  18194. }
  18195. }
  18196. $border = false;
  18197. if (empty($border)) {
  18198. $cellstart = '';
  18199. $cellend = ' ';
  18200. $rowend = '';
  18201. $padrowend = false;
  18202. $borderline = '';
  18203. } else {
  18204. $cellstart = '| ';
  18205. $cellend = ' ';
  18206. $rowend = '|';
  18207. $padrowend = true;
  18208. $borderline = '+';
  18209. foreach ($width as $w) {
  18210. $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
  18211. $borderline .= '+';
  18212. }
  18213. }
  18214. if ($borderline) {
  18215. $this->_displayLine($borderline);
  18216. }
  18217. for ($i = 0; $i < count($table_data); $i++) {
  18218. extract($table_data[$i]);
  18219. if (!is_array($rowparams)) {
  18220. $rowparams = array();
  18221. }
  18222. if (!is_array($colparams)) {
  18223. $colparams = array();
  18224. }
  18225. $rowlines = array();
  18226. if ($height > 1) {
  18227. for ($c = 0; $c < count($data); $c++) {
  18228. $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
  18229. if (count($rowlines[$c]) < $height) {
  18230. $rowlines[$c] = array_pad($rowlines[$c], $height, '');
  18231. }
  18232. }
  18233. } else {
  18234. for ($c = 0; $c < count($data); $c++) {
  18235. $rowlines[$c] = array($data[$c]);
  18236. }
  18237. }
  18238. for ($r = 0; $r < $height; $r++) {
  18239. $rowtext = '';
  18240. for ($c = 0; $c < count($data); $c++) {
  18241. if (isset($colparams[$c])) {
  18242. $attribs = array_merge($rowparams, $colparams);
  18243. } else {
  18244. $attribs = $rowparams;
  18245. }
  18246. $w = isset($width[$c]) ? $width[$c] : 0;
  18247. //$cell = $data[$c];
  18248. $cell = $rowlines[$c][$r];
  18249. $l = strlen($cell);
  18250. if ($l > $w) {
  18251. $cell = substr($cell, 0, $w);
  18252. }
  18253. if (isset($attribs['bold'])) {
  18254. $cell = $this->bold($cell);
  18255. }
  18256. if ($l < $w) {
  18257. // not using str_pad here because we may
  18258. // add bold escape characters to $cell
  18259. $cell .= str_repeat(' ', $w - $l);
  18260. }
  18261. $rowtext .= $cellstart . $cell . $cellend;
  18262. }
  18263. if (!$border) {
  18264. $rowtext = rtrim($rowtext);
  18265. }
  18266. $rowtext .= $rowend;
  18267. $this->_displayLine($rowtext);
  18268. }
  18269. }
  18270. if ($borderline) {
  18271. $this->_displayLine($borderline);
  18272. }
  18273. }
  18274. function _displayLine($text)
  18275. {
  18276. print "$this->lp$text\n";
  18277. }
  18278. function _display($text)
  18279. {
  18280. print $text;
  18281. }
  18282. }
  18283. package.xml�����������������������������������������������������������������������������������������0000644�0000766�0000024�00000041334�13553331435�012220� 0����������������������������������������������������������������������������������������������������ustar �mrook���������������������������staff������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?>
  18284. <package packagerversion="1.10.7" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  18285. <name>Archive_Tar</name>
  18286. <channel>pear.php.net</channel>
  18287. <summary>Tar file management class</summary>
  18288. <description>This class provides handling of tar files in PHP.
  18289. It supports creating, listing, extracting and adding to tar files.
  18290. Gzip support is available if PHP has the zlib extension built-in or
  18291. loaded. Bz2 compression is also supported with the bz2 extension loaded.
  18292. Also Lzma2 compressed archives are supported with xz extension.</description>
  18293. <lead>
  18294. <name>Vincent Blavet</name>
  18295. <user>vblavet</user>
  18296. <email>vincent@phpconcept.net</email>
  18297. <active>no</active>
  18298. </lead>
  18299. <lead>
  18300. <name>Greg Beaver</name>
  18301. <user>cellog</user>
  18302. <email>greg@chiaraquartet.net</email>
  18303. <active>no</active>
  18304. </lead>
  18305. <lead>
  18306. <name>Michiel Rook</name>
  18307. <user>mrook</user>
  18308. <email>mrook@php.net</email>
  18309. <active>yes</active>
  18310. </lead>
  18311. <helper>
  18312. <name>Stig Bakken</name>
  18313. <user>ssb</user>
  18314. <email>stig@php.net</email>
  18315. <active>no</active>
  18316. </helper>
  18317. <date>2019-10-21</date>
  18318. <time>13:31:09</time>
  18319. <version>
  18320. <release>1.4.8</release>
  18321. <api>1.4.0</api>
  18322. </version>
  18323. <stability>
  18324. <release>stable</release>
  18325. <api>stable</api>
  18326. </stability>
  18327. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18328. <notes>
  18329. * Fix Bug #23852: PHP 7.4 - Archive_Tar-&gt;_readHeader throws deprecation [mrook]
  18330. </notes>
  18331. <contents>
  18332. <dir name="/">
  18333. <file baseinstalldir="/" md5sum="e481f1bfecf0056ed2c4d6db421fe83d" name="Archive/Tar.php" role="php" />
  18334. <file baseinstalldir="/" md5sum="2fb90f0be7089a45c09a0d1182792419" name="docs/Archive_Tar.txt" role="doc" />
  18335. </dir>
  18336. </contents>
  18337. <compatible>
  18338. <name>PEAR</name>
  18339. <channel>pear.php.net</channel>
  18340. <min>1.8.0</min>
  18341. <max>1.10.10</max>
  18342. </compatible>
  18343. <dependencies>
  18344. <required>
  18345. <php>
  18346. <min>5.2.0</min>
  18347. </php>
  18348. <pearinstaller>
  18349. <min>1.9.0</min>
  18350. </pearinstaller>
  18351. </required>
  18352. </dependencies>
  18353. <phprelease />
  18354. <changelog>
  18355. <release>
  18356. <version>
  18357. <release>1.4.7</release>
  18358. <api>1.4.0</api>
  18359. </version>
  18360. <stability>
  18361. <release>stable</release>
  18362. <api>stable</api>
  18363. </stability>
  18364. <date>2019-04-08</date>
  18365. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18366. <notes>
  18367. * Improved performance by increasing read buffer size
  18368. </notes>
  18369. </release>
  18370. <release>
  18371. <version>
  18372. <release>1.4.6</release>
  18373. <api>1.4.0</api>
  18374. </version>
  18375. <stability>
  18376. <release>stable</release>
  18377. <api>stable</api>
  18378. </stability>
  18379. <date>2019-02-01</date>
  18380. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18381. <notes>
  18382. * Improve path traversal detection for forward and backward slashes
  18383. </notes>
  18384. </release>
  18385. <release>
  18386. <version>
  18387. <release>1.4.5</release>
  18388. <api>1.4.0</api>
  18389. </version>
  18390. <stability>
  18391. <release>stable</release>
  18392. <api>stable</api>
  18393. </stability>
  18394. <date>2019-01-02</date>
  18395. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18396. <notes>
  18397. * Fix Bug #23788: Relative symlinks are broken [mrook]
  18398. </notes>
  18399. </release>
  18400. <release>
  18401. <version>
  18402. <release>1.4.4</release>
  18403. <api>1.4.0</api>
  18404. </version>
  18405. <stability>
  18406. <release>stable</release>
  18407. <api>stable</api>
  18408. </stability>
  18409. <date>2018-12-20</date>
  18410. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18411. <notes>
  18412. * Fix Bug #21058: Long symlinks are not supported [mrook]
  18413. * Fix Bug #23782: Prevent phar:// files from being extracted [mrook]
  18414. </notes>
  18415. </release>
  18416. <release>
  18417. <version>
  18418. <release>1.4.3</release>
  18419. <api>1.4.0</api>
  18420. </version>
  18421. <stability>
  18422. <release>stable</release>
  18423. <api>stable</api>
  18424. </stability>
  18425. <date>2017-06-11</date>
  18426. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18427. <notes>
  18428. * Fix Bug #21218: Cannot use result of built-in function in write context in PHP
  18429. 7.2.0alpha1 [mrook]
  18430. </notes>
  18431. </release>
  18432. <release>
  18433. <version>
  18434. <release>1.4.2</release>
  18435. <api>1.4.0</api>
  18436. </version>
  18437. <stability>
  18438. <release>stable</release>
  18439. <api>stable</api>
  18440. </stability>
  18441. <date>2016-02-25</date>
  18442. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18443. <notes>
  18444. * Fix reading of archives with files &gt; 8GB
  18445. * Performance optimizations
  18446. * Do not try to call require_once on PEAR.php if it has already been loaded by the autoloader
  18447. </notes>
  18448. </release>
  18449. <release>
  18450. <version>
  18451. <release>1.4.1</release>
  18452. <api>1.4.0</api>
  18453. </version>
  18454. <stability>
  18455. <release>stable</release>
  18456. <api>stable</api>
  18457. </stability>
  18458. <date>2015-08-05</date>
  18459. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18460. <notes>
  18461. * Update composer.json to use pear-core-minimal 1.10.0alpha2
  18462. </notes>
  18463. </release>
  18464. <release>
  18465. <version>
  18466. <release>1.4.0</release>
  18467. <api>1.4.0</api>
  18468. </version>
  18469. <stability>
  18470. <release>stable</release>
  18471. <api>stable</api>
  18472. </stability>
  18473. <date>2015-07-20</date>
  18474. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18475. <notes>
  18476. * Add support for PHP 7
  18477. * Drop support for PHP 4
  18478. * Add visibility declarations to methods and properties
  18479. </notes>
  18480. </release>
  18481. <release>
  18482. <version>
  18483. <release>1.3.16</release>
  18484. <api>1.3.1</api>
  18485. </version>
  18486. <stability>
  18487. <release>stable</release>
  18488. <api>stable</api>
  18489. </stability>
  18490. <date>2015-04-14</date>
  18491. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18492. <notes>
  18493. * Fix Bug #20514: invalid package.xml; not installable with pyrus [mrook]
  18494. </notes>
  18495. </release>
  18496. <release>
  18497. <version>
  18498. <release>1.3.15</release>
  18499. <api>1.3.1</api>
  18500. </version>
  18501. <stability>
  18502. <release>stable</release>
  18503. <api>stable</api>
  18504. </stability>
  18505. <date>2015-03-05</date>
  18506. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18507. <notes>
  18508. * Fixes composer.json parse error
  18509. </notes>
  18510. </release>
  18511. <release>
  18512. <version>
  18513. <release>1.3.14</release>
  18514. <api>1.3.1</api>
  18515. </version>
  18516. <stability>
  18517. <release>stable</release>
  18518. <api>stable</api>
  18519. </stability>
  18520. <date>2015-02-26</date>
  18521. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18522. <notes>
  18523. * Fix Bug #18505: Possible incorrect handling of file names in TAR [mrook]
  18524. </notes>
  18525. </release>
  18526. <release>
  18527. <version>
  18528. <release>1.3.13</release>
  18529. <api>1.3.1</api>
  18530. </version>
  18531. <stability>
  18532. <release>stable</release>
  18533. <api>stable</api>
  18534. </stability>
  18535. <date>2014-09-02</date>
  18536. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD
  18537. License</license>
  18538. <notes>
  18539. * Fix Bug #20382: gzopen fix [mrook]
  18540. </notes>
  18541. </release>
  18542. <release>
  18543. <version>
  18544. <release>1.3.12</release>
  18545. <api>1.3.1</api>
  18546. </version>
  18547. <stability>
  18548. <release>stable</release>
  18549. <api>stable</api>
  18550. </stability>
  18551. <date>2014-08-04</date>
  18552. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD
  18553. License</license>
  18554. <notes>
  18555. * Fix Bug #19964: Memory leaking in Archive_Tar [mrook]
  18556. * Fix Bug #20246: Broken with php 5.5.9 [mrook]
  18557. * Fix Bug #20275: &quot;pax_global_header&quot; looks like a regular file
  18558. * [mrook]
  18559. * Implement Feature #19827: pass filename to _addFile function - downstream
  18560. * patch [mrook]
  18561. * Implement Feature #20132: Add custom mode/uid/gid to addString() [mrook]
  18562. </notes>
  18563. </release>
  18564. <release>
  18565. <version>
  18566. <release>1.3.11</release>
  18567. <api>1.3.1</api>
  18568. </version>
  18569. <stability>
  18570. <release>stable</release>
  18571. <api>stable</api>
  18572. </stability>
  18573. <date>2013-02-09</date>
  18574. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD
  18575. License</license>
  18576. <notes>
  18577. * Fix Bug #19746: Broken with PHP 5.5 [mrook]
  18578. * Implement Feature #11258: Custom date/time in files added on-the-fly
  18579. * [mrook]
  18580. </notes>
  18581. </release>
  18582. <release>
  18583. <version>
  18584. <release>1.3.10</release>
  18585. <api>1.3.1</api>
  18586. </version>
  18587. <stability>
  18588. <release>stable</release>
  18589. <api>stable</api>
  18590. </stability>
  18591. <date>2012-04-10</date>
  18592. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD
  18593. License</license>
  18594. <notes>
  18595. * Fix Bug #13361: Unable to add() some files (ex. mp3) [mrook]
  18596. * Fix Bug #19330: Class creates incorrect (non-readable) tar.gz file
  18597. * [mrook]
  18598. </notes>
  18599. </release>
  18600. <release>
  18601. <version>
  18602. <release>1.3.9</release>
  18603. <api>1.3.1</api>
  18604. </version>
  18605. <stability>
  18606. <release>stable</release>
  18607. <api>stable</api>
  18608. </stability>
  18609. <date>2012-02-27</date>
  18610. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18611. <notes>
  18612. * Fix Bug #16759: No error thrown from missing PHP zlib functions [mrook]
  18613. * Fix Bug #18877: Incorrect handling of backslashes in filenames on Linux [mrook]
  18614. * Fix Bug #19085: Error while packaging [mrook]
  18615. * Fix Bug #19289: Invalid tar file generated [mrook]
  18616. </notes>
  18617. </release>
  18618. <release>
  18619. <version>
  18620. <release>1.3.8</release>
  18621. <api>1.3.1</api>
  18622. </version>
  18623. <stability>
  18624. <release>stable</release>
  18625. <api>stable</api>
  18626. </stability>
  18627. <date>2011-10-14</date>
  18628. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18629. <notes>
  18630. * Fix Bug #17853: Test failure: dirtraversal.phpt [mrook]
  18631. * Fix Bug #18512: dead links are not saved in tar file [mrook]
  18632. * Fix Bug #18702: Unpacks incorrectly on long file names using header prefix [mrook]
  18633. * Implement Feature #10145: Patch to return a Pear Error Object on failure [mrook]
  18634. * Implement Feature #17491: Option to preserve permissions [mrook]
  18635. * Implement Feature #17813: Prevent PHP notice when extracting corrupted archive [mrook]
  18636. </notes>
  18637. </release>
  18638. <release>
  18639. <version>
  18640. <release>1.3.7</release>
  18641. <api>1.3.1</api>
  18642. </version>
  18643. <stability>
  18644. <release>stable</release>
  18645. <api>stable</api>
  18646. </stability>
  18647. <date>2010-04-26</date>
  18648. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18649. <notes>
  18650. PEAR compatibility update
  18651. </notes>
  18652. </release>
  18653. <release>
  18654. <version>
  18655. <release>1.3.6</release>
  18656. <api>1.3.1</api>
  18657. </version>
  18658. <stability>
  18659. <release>stable</release>
  18660. <api>stable</api>
  18661. </stability>
  18662. <date>2010-03-09</date>
  18663. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18664. <notes>
  18665. * Fix Bug #16963: extractList can&apos;t extract zipped files from big tar [mrook]
  18666. * Implement Feature #4013: Ignoring files and directories on creating an archive. [mrook]
  18667. </notes>
  18668. </release>
  18669. <release>
  18670. <version>
  18671. <release>1.3.5</release>
  18672. <api>1.3.1</api>
  18673. </version>
  18674. <stability>
  18675. <release>stable</release>
  18676. <api>stable</api>
  18677. </stability>
  18678. <date>2009-12-31</date>
  18679. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18680. <notes>
  18681. * Fix Bug #16958: Update &apos;compatible&apos; tag in package.xml [mrook]
  18682. </notes>
  18683. </release>
  18684. <release>
  18685. <version>
  18686. <release>1.3.4</release>
  18687. <api>1.3.1</api>
  18688. </version>
  18689. <stability>
  18690. <release>stable</release>
  18691. <api>stable</api>
  18692. </stability>
  18693. <date>2009-12-30</date>
  18694. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18695. <notes>
  18696. * Fix Bug #11871: wrong result of ::listContent() if filename begins or ends with space [mrook]
  18697. * Fix Bug #12462: invalid tar magic [mrook]
  18698. * Fix Bug #13918: Long filenames may get up to 511 0x00 bytes appended on read [mrook]
  18699. * Fix Bug #16202: Bogus modification times [mrook]
  18700. * Implement Feature #16212: Die is not exception [mrook]
  18701. </notes>
  18702. </release>
  18703. <release>
  18704. <version>
  18705. <release>1.3.3</release>
  18706. <api>1.3.1</api>
  18707. </version>
  18708. <stability>
  18709. <release>stable</release>
  18710. <api>stable</api>
  18711. </stability>
  18712. <date>2009-03-27</date>
  18713. <license uri="http://www.opensource.org/licenses/bsd-license.php">New BSD License</license>
  18714. <notes>
  18715. Change the license to New BSD license
  18716. minor bugfix release
  18717. * fix Bug #9921 compression with bzip2 fails [cellog]
  18718. * fix Bug #11594 _readLongHeader leaves 0 bytes in filename [jamessas]
  18719. * fix Bug #11769 Incorrect symlink handing [fajar99]
  18720. </notes>
  18721. </release>
  18722. <release>
  18723. <version>
  18724. <release>1.3.2</release>
  18725. <api>1.3.1</api>
  18726. </version>
  18727. <stability>
  18728. <release>stable</release>
  18729. <api>stable</api>
  18730. </stability>
  18731. <date>2007-01-03</date>
  18732. <license uri="http://www.php.net/license">PHP License</license>
  18733. <notes>
  18734. Correct Bug #4016
  18735. Remove duplicate remove error display with &apos;@&apos;
  18736. Correct Bug #3909 : Check existence of OS_WINDOWS constant
  18737. Correct Bug #5452 fix for &quot;lone zero block&quot; when untarring packages
  18738. Change filemode (from pear-core/Archive/Tar.php v.1.21)
  18739. Correct Bug #6486 Can not extract symlinks
  18740. Correct Bug #6933 Archive_Tar (Tar file management class) Directory traversal
  18741. Correct Bug #8114 Files added on-the-fly not storing date
  18742. Correct Bug #9352 Bug on _dirCheck function over nfs path
  18743. </notes>
  18744. </release>
  18745. <release>
  18746. <version>
  18747. <release>1.3.1</release>
  18748. <api>1.3.1</api>
  18749. </version>
  18750. <stability>
  18751. <release>stable</release>
  18752. <api>stable</api>
  18753. </stability>
  18754. <date>2005-03-17</date>
  18755. <license uri="http://www.php.net/license">PHP License</license>
  18756. <notes>
  18757. Correct Bug #3855
  18758. </notes>
  18759. </release>
  18760. <release>
  18761. <version>
  18762. <release>1.3.0</release>
  18763. <api>1.3.0</api>
  18764. </version>
  18765. <stability>
  18766. <release>stable</release>
  18767. <api>stable</api>
  18768. </stability>
  18769. <date>2005-03-06</date>
  18770. <license uri="http://www.php.net/license">PHP License</license>
  18771. <notes>
  18772. Bugs correction (2475, 2488, 2135, 2176)
  18773. </notes>
  18774. </release>
  18775. <release>
  18776. <version>
  18777. <release>1.2</release>
  18778. <api>1.2</api>
  18779. </version>
  18780. <stability>
  18781. <release>stable</release>
  18782. <api>stable</api>
  18783. </stability>
  18784. <date>2004-05-08</date>
  18785. <license uri="http://www.php.net/license">PHP License</license>
  18786. <notes>
  18787. Add support for other separator than the space char and bug
  18788. correction
  18789. </notes>
  18790. </release>
  18791. <release>
  18792. <version>
  18793. <release>1.1</release>
  18794. <api>1.1</api>
  18795. </version>
  18796. <stability>
  18797. <release>stable</release>
  18798. <api>stable</api>
  18799. </stability>
  18800. <date>2003-05-28</date>
  18801. <license uri="http://www.php.net/license">PHP License</license>
  18802. <notes>
  18803. * Add support for BZ2 compression
  18804. * Add support for add and extract without using temporary files : methods addString() and extractInString()
  18805. </notes>
  18806. </release>
  18807. <release>
  18808. <version>
  18809. <release>1.0</release>
  18810. <api>1.0</api>
  18811. </version>
  18812. <stability>
  18813. <release>stable</release>
  18814. <api>stable</api>
  18815. </stability>
  18816. <date>2003-01-24</date>
  18817. <license uri="http://www.php.net/license">PHP License</license>
  18818. <notes>
  18819. Change status to stable
  18820. </notes>
  18821. </release>
  18822. <release>
  18823. <version>
  18824. <release>0.10-b1</release>
  18825. <api>0.10-b1</api>
  18826. </version>
  18827. <stability>
  18828. <release>beta</release>
  18829. <api>beta</api>
  18830. </stability>
  18831. <date>2003-01-08</date>
  18832. <license uri="http://www.php.net/license">PHP License</license>
  18833. <notes>
  18834. Add support for long filenames (greater than 99 characters)
  18835. </notes>
  18836. </release>
  18837. <release>
  18838. <version>
  18839. <release>0.9</release>
  18840. <api>0.9</api>
  18841. </version>
  18842. <stability>
  18843. <release>stable</release>
  18844. <api>stable</api>
  18845. </stability>
  18846. <date>2002-05-27</date>
  18847. <license uri="http://www.php.net/license">PHP License</license>
  18848. <notes>
  18849. Auto-detect gzip&apos;ed files
  18850. </notes>
  18851. </release>
  18852. <release>
  18853. <version>
  18854. <release>0.4</release>
  18855. <api>0.4</api>
  18856. </version>
  18857. <stability>
  18858. <release>stable</release>
  18859. <api>stable</api>
  18860. </stability>
  18861. <date>2002-05-20</date>
  18862. <license uri="http://www.php.net/license">PHP License</license>
  18863. <notes>
  18864. Windows bugfix: use forward slashes inside archives
  18865. </notes>
  18866. </release>
  18867. <release>
  18868. <version>
  18869. <release>0.2</release>
  18870. <api>0.2</api>
  18871. </version>
  18872. <stability>
  18873. <release>stable</release>
  18874. <api>stable</api>
  18875. </stability>
  18876. <date>2002-02-18</date>
  18877. <license uri="http://www.php.net/license">PHP License</license>
  18878. <notes>
  18879. From initial commit to stable
  18880. </notes>
  18881. </release>
  18882. <release>
  18883. <version>
  18884. <release>0.3</release>
  18885. <api>0.3</api>
  18886. </version>
  18887. <stability>
  18888. <release>stable</release>
  18889. <api>stable</api>
  18890. </stability>
  18891. <date>2002-04-13</date>
  18892. <license uri="http://www.php.net/license">PHP License</license>
  18893. <notes>
  18894. Windows bugfix: used wrong directory separators
  18895. </notes>
  18896. </release>
  18897. </changelog>
  18898. </package>
  18899. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Archive_Tar-1.4.8/Archive/Tar.php�������������������������������������������������������������������0000644�0000766�0000024�00000246761�13553331435�015573� 0����������������������������������������������������������������������������������������������������ustar �mrook���������������������������staff������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  18900. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  18901. /**
  18902. * File::CSV
  18903. *
  18904. * PHP versions 4 and 5
  18905. *
  18906. * Copyright (c) 1997-2008,
  18907. * Vincent Blavet <vincent@phpconcept.net>
  18908. * All rights reserved.
  18909. *
  18910. * Redistribution and use in source and binary forms, with or without
  18911. * modification, are permitted provided that the following conditions are met:
  18912. *
  18913. * * Redistributions of source code must retain the above copyright notice,
  18914. * this list of conditions and the following disclaimer.
  18915. * * Redistributions in binary form must reproduce the above copyright
  18916. * notice, this list of conditions and the following disclaimer in the
  18917. * documentation and/or other materials provided with the distribution.
  18918. *
  18919. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18920. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18921. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18922. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  18923. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18924. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  18925. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  18926. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  18927. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  18928. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  18929. *
  18930. * @category File_Formats
  18931. * @package Archive_Tar
  18932. * @author Vincent Blavet <vincent@phpconcept.net>
  18933. * @copyright 1997-2010 The Authors
  18934. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  18935. * @version CVS: $Id$
  18936. * @link http://pear.php.net/package/Archive_Tar
  18937. */
  18938. // If the PEAR class cannot be loaded via the autoloader,
  18939. // then try to require_once it from the PHP include path.
  18940. if (!class_exists('PEAR')) {
  18941. require_once 'PEAR.php';
  18942. }
  18943. define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  18944. define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
  18945. if (!function_exists('gzopen') && function_exists('gzopen64')) {
  18946. function gzopen($filename, $mode, $use_include_path = 0)
  18947. {
  18948. return gzopen64($filename, $mode, $use_include_path);
  18949. }
  18950. }
  18951. if (!function_exists('gztell') && function_exists('gztell64')) {
  18952. function gztell($zp)
  18953. {
  18954. return gztell64($zp);
  18955. }
  18956. }
  18957. if (!function_exists('gzseek') && function_exists('gzseek64')) {
  18958. function gzseek($zp, $offset, $whence = SEEK_SET)
  18959. {
  18960. return gzseek64($zp, $offset, $whence);
  18961. }
  18962. }
  18963. /**
  18964. * Creates a (compressed) Tar archive
  18965. *
  18966. * @package Archive_Tar
  18967. * @author Vincent Blavet <vincent@phpconcept.net>
  18968. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  18969. * @version $Revision$
  18970. */
  18971. class Archive_Tar extends PEAR
  18972. {
  18973. /**
  18974. * @var string Name of the Tar
  18975. */
  18976. public $_tarname = '';
  18977. /**
  18978. * @var boolean if true, the Tar file will be gzipped
  18979. */
  18980. public $_compress = false;
  18981. /**
  18982. * @var string Type of compression : 'none', 'gz', 'bz2' or 'lzma2'
  18983. */
  18984. public $_compress_type = 'none';
  18985. /**
  18986. * @var string Explode separator
  18987. */
  18988. public $_separator = ' ';
  18989. /**
  18990. * @var file descriptor
  18991. */
  18992. public $_file = 0;
  18993. /**
  18994. * @var string Local Tar name of a remote Tar (http:// or ftp://)
  18995. */
  18996. public $_temp_tarname = '';
  18997. /**
  18998. * @var string regular expression for ignoring files or directories
  18999. */
  19000. public $_ignore_regexp = '';
  19001. /**
  19002. * @var object PEAR_Error object
  19003. */
  19004. public $error_object = null;
  19005. /**
  19006. * Format for data extraction
  19007. *
  19008. * @var string
  19009. */
  19010. public $_fmt = '';
  19011. /**
  19012. * @var int Length of the read buffer in bytes
  19013. */
  19014. protected $buffer_length;
  19015. /**
  19016. * Archive_Tar Class constructor. This flavour of the constructor only
  19017. * declare a new Archive_Tar object, identifying it by the name of the
  19018. * tar file.
  19019. * If the compress argument is set the tar will be read or created as a
  19020. * gzip or bz2 compressed TAR file.
  19021. *
  19022. * @param string $p_tarname The name of the tar archive to create
  19023. * @param string $p_compress can be null, 'gz', 'bz2' or 'lzma2'. This
  19024. * parameter indicates if gzip, bz2 or lzma2 compression
  19025. * is required. For compatibility reason the
  19026. * boolean value 'true' means 'gz'.
  19027. * @param int $buffer_length Length of the read buffer in bytes
  19028. *
  19029. * @return bool
  19030. */
  19031. public function __construct($p_tarname, $p_compress = null, $buffer_length = 512)
  19032. {
  19033. parent::__construct();
  19034. $this->_compress = false;
  19035. $this->_compress_type = 'none';
  19036. if (($p_compress === null) || ($p_compress == '')) {
  19037. if (@file_exists($p_tarname)) {
  19038. if ($fp = @fopen($p_tarname, "rb")) {
  19039. // look for gzip magic cookie
  19040. $data = fread($fp, 2);
  19041. fclose($fp);
  19042. if ($data == "\37\213") {
  19043. $this->_compress = true;
  19044. $this->_compress_type = 'gz';
  19045. // No sure it's enought for a magic code ....
  19046. } elseif ($data == "BZ") {
  19047. $this->_compress = true;
  19048. $this->_compress_type = 'bz2';
  19049. } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
  19050. $this->_compress = true;
  19051. $this->_compress_type = 'lzma2';
  19052. }
  19053. }
  19054. } else {
  19055. // probably a remote file or some file accessible
  19056. // through a stream interface
  19057. if (substr($p_tarname, -2) == 'gz') {
  19058. $this->_compress = true;
  19059. $this->_compress_type = 'gz';
  19060. } elseif ((substr($p_tarname, -3) == 'bz2') ||
  19061. (substr($p_tarname, -2) == 'bz')
  19062. ) {
  19063. $this->_compress = true;
  19064. $this->_compress_type = 'bz2';
  19065. } else {
  19066. if (substr($p_tarname, -2) == 'xz') {
  19067. $this->_compress = true;
  19068. $this->_compress_type = 'lzma2';
  19069. }
  19070. }
  19071. }
  19072. } else {
  19073. if (($p_compress === true) || ($p_compress == 'gz')) {
  19074. $this->_compress = true;
  19075. $this->_compress_type = 'gz';
  19076. } else {
  19077. if ($p_compress == 'bz2') {
  19078. $this->_compress = true;
  19079. $this->_compress_type = 'bz2';
  19080. } else {
  19081. if ($p_compress == 'lzma2') {
  19082. $this->_compress = true;
  19083. $this->_compress_type = 'lzma2';
  19084. } else {
  19085. $this->_error(
  19086. "Unsupported compression type '$p_compress'\n" .
  19087. "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
  19088. );
  19089. return false;
  19090. }
  19091. }
  19092. }
  19093. }
  19094. $this->_tarname = $p_tarname;
  19095. if ($this->_compress) { // assert zlib or bz2 or xz extension support
  19096. if ($this->_compress_type == 'gz') {
  19097. $extname = 'zlib';
  19098. } else {
  19099. if ($this->_compress_type == 'bz2') {
  19100. $extname = 'bz2';
  19101. } else {
  19102. if ($this->_compress_type == 'lzma2') {
  19103. $extname = 'xz';
  19104. }
  19105. }
  19106. }
  19107. if (!extension_loaded($extname)) {
  19108. PEAR::loadExtension($extname);
  19109. }
  19110. if (!extension_loaded($extname)) {
  19111. $this->_error(
  19112. "The extension '$extname' couldn't be found.\n" .
  19113. "Please make sure your version of PHP was built " .
  19114. "with '$extname' support.\n"
  19115. );
  19116. return false;
  19117. }
  19118. }
  19119. if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
  19120. $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
  19121. "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
  19122. "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
  19123. } else {
  19124. $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
  19125. "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
  19126. "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
  19127. }
  19128. $this->buffer_length = $buffer_length;
  19129. }
  19130. public function __destruct()
  19131. {
  19132. $this->_close();
  19133. // ----- Look for a local copy to delete
  19134. if ($this->_temp_tarname != '') {
  19135. @unlink($this->_temp_tarname);
  19136. }
  19137. }
  19138. /**
  19139. * This method creates the archive file and add the files / directories
  19140. * that are listed in $p_filelist.
  19141. * If a file with the same name exist and is writable, it is replaced
  19142. * by the new tar.
  19143. * The method return false and a PEAR error text.
  19144. * The $p_filelist parameter can be an array of string, each string
  19145. * representing a filename or a directory name with their path if
  19146. * needed. It can also be a single string with names separated by a
  19147. * single blank.
  19148. * For each directory added in the archive, the files and
  19149. * sub-directories are also added.
  19150. * See also createModify() method for more details.
  19151. *
  19152. * @param array $p_filelist An array of filenames and directory names, or a
  19153. * single string with names separated by a single
  19154. * blank space.
  19155. *
  19156. * @return true on success, false on error.
  19157. * @see createModify()
  19158. */
  19159. public function create($p_filelist)
  19160. {
  19161. return $this->createModify($p_filelist, '', '');
  19162. }
  19163. /**
  19164. * This method add the files / directories that are listed in $p_filelist in
  19165. * the archive. If the archive does not exist it is created.
  19166. * The method return false and a PEAR error text.
  19167. * The files and directories listed are only added at the end of the archive,
  19168. * even if a file with the same name is already archived.
  19169. * See also createModify() method for more details.
  19170. *
  19171. * @param array $p_filelist An array of filenames and directory names, or a
  19172. * single string with names separated by a single
  19173. * blank space.
  19174. *
  19175. * @return true on success, false on error.
  19176. * @see createModify()
  19177. * @access public
  19178. */
  19179. public function add($p_filelist)
  19180. {
  19181. return $this->addModify($p_filelist, '', '');
  19182. }
  19183. /**
  19184. * @param string $p_path
  19185. * @param bool $p_preserve
  19186. * @return bool
  19187. */
  19188. public function extract($p_path = '', $p_preserve = false)
  19189. {
  19190. return $this->extractModify($p_path, '', $p_preserve);
  19191. }
  19192. /**
  19193. * @return array|int
  19194. */
  19195. public function listContent()
  19196. {
  19197. $v_list_detail = array();
  19198. if ($this->_openRead()) {
  19199. if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  19200. unset($v_list_detail);
  19201. $v_list_detail = 0;
  19202. }
  19203. $this->_close();
  19204. }
  19205. return $v_list_detail;
  19206. }
  19207. /**
  19208. * This method creates the archive file and add the files / directories
  19209. * that are listed in $p_filelist.
  19210. * If the file already exists and is writable, it is replaced by the
  19211. * new tar. It is a create and not an add. If the file exists and is
  19212. * read-only or is a directory it is not replaced. The method return
  19213. * false and a PEAR error text.
  19214. * The $p_filelist parameter can be an array of string, each string
  19215. * representing a filename or a directory name with their path if
  19216. * needed. It can also be a single string with names separated by a
  19217. * single blank.
  19218. * The path indicated in $p_remove_dir will be removed from the
  19219. * memorized path of each file / directory listed when this path
  19220. * exists. By default nothing is removed (empty path '')
  19221. * The path indicated in $p_add_dir will be added at the beginning of
  19222. * the memorized path of each file / directory listed. However it can
  19223. * be set to empty ''. The adding of a path is done after the removing
  19224. * of path.
  19225. * The path add/remove ability enables the user to prepare an archive
  19226. * for extraction in a different path than the origin files are.
  19227. * See also addModify() method for file adding properties.
  19228. *
  19229. * @param array $p_filelist An array of filenames and directory names,
  19230. * or a single string with names separated by
  19231. * a single blank space.
  19232. * @param string $p_add_dir A string which contains a path to be added
  19233. * to the memorized path of each element in
  19234. * the list.
  19235. * @param string $p_remove_dir A string which contains a path to be
  19236. * removed from the memorized path of each
  19237. * element in the list, when relevant.
  19238. *
  19239. * @return boolean true on success, false on error.
  19240. * @see addModify()
  19241. */
  19242. public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
  19243. {
  19244. $v_result = true;
  19245. if (!$this->_openWrite()) {
  19246. return false;
  19247. }
  19248. if ($p_filelist != '') {
  19249. if (is_array($p_filelist)) {
  19250. $v_list = $p_filelist;
  19251. } elseif (is_string($p_filelist)) {
  19252. $v_list = explode($this->_separator, $p_filelist);
  19253. } else {
  19254. $this->_cleanFile();
  19255. $this->_error('Invalid file list');
  19256. return false;
  19257. }
  19258. $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  19259. }
  19260. if ($v_result) {
  19261. $this->_writeFooter();
  19262. $this->_close();
  19263. } else {
  19264. $this->_cleanFile();
  19265. }
  19266. return $v_result;
  19267. }
  19268. /**
  19269. * This method add the files / directories listed in $p_filelist at the
  19270. * end of the existing archive. If the archive does not yet exists it
  19271. * is created.
  19272. * The $p_filelist parameter can be an array of string, each string
  19273. * representing a filename or a directory name with their path if
  19274. * needed. It can also be a single string with names separated by a
  19275. * single blank.
  19276. * The path indicated in $p_remove_dir will be removed from the
  19277. * memorized path of each file / directory listed when this path
  19278. * exists. By default nothing is removed (empty path '')
  19279. * The path indicated in $p_add_dir will be added at the beginning of
  19280. * the memorized path of each file / directory listed. However it can
  19281. * be set to empty ''. The adding of a path is done after the removing
  19282. * of path.
  19283. * The path add/remove ability enables the user to prepare an archive
  19284. * for extraction in a different path than the origin files are.
  19285. * If a file/dir is already in the archive it will only be added at the
  19286. * end of the archive. There is no update of the existing archived
  19287. * file/dir. However while extracting the archive, the last file will
  19288. * replace the first one. This results in a none optimization of the
  19289. * archive size.
  19290. * If a file/dir does not exist the file/dir is ignored. However an
  19291. * error text is send to PEAR error.
  19292. * If a file/dir is not readable the file/dir is ignored. However an
  19293. * error text is send to PEAR error.
  19294. *
  19295. * @param array $p_filelist An array of filenames and directory
  19296. * names, or a single string with names
  19297. * separated by a single blank space.
  19298. * @param string $p_add_dir A string which contains a path to be
  19299. * added to the memorized path of each
  19300. * element in the list.
  19301. * @param string $p_remove_dir A string which contains a path to be
  19302. * removed from the memorized path of
  19303. * each element in the list, when
  19304. * relevant.
  19305. *
  19306. * @return true on success, false on error.
  19307. */
  19308. public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
  19309. {
  19310. $v_result = true;
  19311. if (!$this->_isArchive()) {
  19312. $v_result = $this->createModify(
  19313. $p_filelist,
  19314. $p_add_dir,
  19315. $p_remove_dir
  19316. );
  19317. } else {
  19318. if (is_array($p_filelist)) {
  19319. $v_list = $p_filelist;
  19320. } elseif (is_string($p_filelist)) {
  19321. $v_list = explode($this->_separator, $p_filelist);
  19322. } else {
  19323. $this->_error('Invalid file list');
  19324. return false;
  19325. }
  19326. $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  19327. }
  19328. return $v_result;
  19329. }
  19330. /**
  19331. * This method add a single string as a file at the
  19332. * end of the existing archive. If the archive does not yet exists it
  19333. * is created.
  19334. *
  19335. * @param string $p_filename A string which contains the full
  19336. * filename path that will be associated
  19337. * with the string.
  19338. * @param string $p_string The content of the file added in
  19339. * the archive.
  19340. * @param bool|int $p_datetime A custom date/time (unix timestamp)
  19341. * for the file (optional).
  19342. * @param array $p_params An array of optional params:
  19343. * stamp => the datetime (replaces
  19344. * datetime above if it exists)
  19345. * mode => the permissions on the
  19346. * file (600 by default)
  19347. * type => is this a link? See the
  19348. * tar specification for details.
  19349. * (default = regular file)
  19350. * uid => the user ID of the file
  19351. * (default = 0 = root)
  19352. * gid => the group ID of the file
  19353. * (default = 0 = root)
  19354. *
  19355. * @return true on success, false on error.
  19356. */
  19357. public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
  19358. {
  19359. $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
  19360. $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
  19361. $p_type = @$p_params["type"] ? $p_params["type"] : "";
  19362. $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
  19363. $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
  19364. $v_result = true;
  19365. if (!$this->_isArchive()) {
  19366. if (!$this->_openWrite()) {
  19367. return false;
  19368. }
  19369. $this->_close();
  19370. }
  19371. if (!$this->_openAppend()) {
  19372. return false;
  19373. }
  19374. // Need to check the get back to the temporary file ? ....
  19375. $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
  19376. $this->_writeFooter();
  19377. $this->_close();
  19378. return $v_result;
  19379. }
  19380. /**
  19381. * This method extract all the content of the archive in the directory
  19382. * indicated by $p_path. When relevant the memorized path of the
  19383. * files/dir can be modified by removing the $p_remove_path path at the
  19384. * beginning of the file/dir path.
  19385. * While extracting a file, if the directory path does not exists it is
  19386. * created.
  19387. * While extracting a file, if the file already exists it is replaced
  19388. * without looking for last modification date.
  19389. * While extracting a file, if the file already exists and is write
  19390. * protected, the extraction is aborted.
  19391. * While extracting a file, if a directory with the same name already
  19392. * exists, the extraction is aborted.
  19393. * While extracting a directory, if a file with the same name already
  19394. * exists, the extraction is aborted.
  19395. * While extracting a file/directory if the destination directory exist
  19396. * and is write protected, or does not exist but can not be created,
  19397. * the extraction is aborted.
  19398. * If after extraction an extracted file does not show the correct
  19399. * stored file size, the extraction is aborted.
  19400. * When the extraction is aborted, a PEAR error text is set and false
  19401. * is returned. However the result can be a partial extraction that may
  19402. * need to be manually cleaned.
  19403. *
  19404. * @param string $p_path The path of the directory where the
  19405. * files/dir need to by extracted.
  19406. * @param string $p_remove_path Part of the memorized path that can be
  19407. * removed if present at the beginning of
  19408. * the file/dir path.
  19409. * @param boolean $p_preserve Preserve user/group ownership of files
  19410. *
  19411. * @return boolean true on success, false on error.
  19412. * @see extractList()
  19413. */
  19414. public function extractModify($p_path, $p_remove_path, $p_preserve = false)
  19415. {
  19416. $v_result = true;
  19417. $v_list_detail = array();
  19418. if ($v_result = $this->_openRead()) {
  19419. $v_result = $this->_extractList(
  19420. $p_path,
  19421. $v_list_detail,
  19422. "complete",
  19423. 0,
  19424. $p_remove_path,
  19425. $p_preserve
  19426. );
  19427. $this->_close();
  19428. }
  19429. return $v_result;
  19430. }
  19431. /**
  19432. * This method extract from the archive one file identified by $p_filename.
  19433. * The return value is a string with the file content, or NULL on error.
  19434. *
  19435. * @param string $p_filename The path of the file to extract in a string.
  19436. *
  19437. * @return a string with the file content or NULL.
  19438. */
  19439. public function extractInString($p_filename)
  19440. {
  19441. if ($this->_openRead()) {
  19442. $v_result = $this->_extractInString($p_filename);
  19443. $this->_close();
  19444. } else {
  19445. $v_result = null;
  19446. }
  19447. return $v_result;
  19448. }
  19449. /**
  19450. * This method extract from the archive only the files indicated in the
  19451. * $p_filelist. These files are extracted in the current directory or
  19452. * in the directory indicated by the optional $p_path parameter.
  19453. * If indicated the $p_remove_path can be used in the same way as it is
  19454. * used in extractModify() method.
  19455. *
  19456. * @param array $p_filelist An array of filenames and directory names,
  19457. * or a single string with names separated
  19458. * by a single blank space.
  19459. * @param string $p_path The path of the directory where the
  19460. * files/dir need to by extracted.
  19461. * @param string $p_remove_path Part of the memorized path that can be
  19462. * removed if present at the beginning of
  19463. * the file/dir path.
  19464. * @param boolean $p_preserve Preserve user/group ownership of files
  19465. *
  19466. * @return true on success, false on error.
  19467. * @see extractModify()
  19468. */
  19469. public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false)
  19470. {
  19471. $v_result = true;
  19472. $v_list_detail = array();
  19473. if (is_array($p_filelist)) {
  19474. $v_list = $p_filelist;
  19475. } elseif (is_string($p_filelist)) {
  19476. $v_list = explode($this->_separator, $p_filelist);
  19477. } else {
  19478. $this->_error('Invalid string list');
  19479. return false;
  19480. }
  19481. if ($v_result = $this->_openRead()) {
  19482. $v_result = $this->_extractList(
  19483. $p_path,
  19484. $v_list_detail,
  19485. "partial",
  19486. $v_list,
  19487. $p_remove_path,
  19488. $p_preserve
  19489. );
  19490. $this->_close();
  19491. }
  19492. return $v_result;
  19493. }
  19494. /**
  19495. * This method set specific attributes of the archive. It uses a variable
  19496. * list of parameters, in the format attribute code + attribute values :
  19497. * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  19498. *
  19499. * @return true on success, false on error.
  19500. */
  19501. public function setAttribute()
  19502. {
  19503. $v_result = true;
  19504. // ----- Get the number of variable list of arguments
  19505. if (($v_size = func_num_args()) == 0) {
  19506. return true;
  19507. }
  19508. // ----- Get the arguments
  19509. $v_att_list = func_get_args();
  19510. // ----- Read the attributes
  19511. $i = 0;
  19512. while ($i < $v_size) {
  19513. // ----- Look for next option
  19514. switch ($v_att_list[$i]) {
  19515. // ----- Look for options that request a string value
  19516. case ARCHIVE_TAR_ATT_SEPARATOR :
  19517. // ----- Check the number of parameters
  19518. if (($i + 1) >= $v_size) {
  19519. $this->_error(
  19520. 'Invalid number of parameters for '
  19521. . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
  19522. );
  19523. return false;
  19524. }
  19525. // ----- Get the value
  19526. $this->_separator = $v_att_list[$i + 1];
  19527. $i++;
  19528. break;
  19529. default :
  19530. $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
  19531. return false;
  19532. }
  19533. // ----- Next attribute
  19534. $i++;
  19535. }
  19536. return $v_result;
  19537. }
  19538. /**
  19539. * This method sets the regular expression for ignoring files and directories
  19540. * at import, for example:
  19541. * $arch->setIgnoreRegexp("#CVS|\.svn#");
  19542. *
  19543. * @param string $regexp regular expression defining which files or directories to ignore
  19544. */
  19545. public function setIgnoreRegexp($regexp)
  19546. {
  19547. $this->_ignore_regexp = $regexp;
  19548. }
  19549. /**
  19550. * This method sets the regular expression for ignoring all files and directories
  19551. * matching the filenames in the array list at import, for example:
  19552. * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
  19553. *
  19554. * @param array $list a list of file or directory names to ignore
  19555. *
  19556. * @access public
  19557. */
  19558. public function setIgnoreList($list)
  19559. {
  19560. $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
  19561. $regexp = '#/' . join('$|/', $list) . '#';
  19562. $this->setIgnoreRegexp($regexp);
  19563. }
  19564. /**
  19565. * @param string $p_message
  19566. */
  19567. public function _error($p_message)
  19568. {
  19569. $this->error_object = $this->raiseError($p_message);
  19570. }
  19571. /**
  19572. * @param string $p_message
  19573. */
  19574. public function _warning($p_message)
  19575. {
  19576. $this->error_object = $this->raiseError($p_message);
  19577. }
  19578. /**
  19579. * @param string $p_filename
  19580. * @return bool
  19581. */
  19582. public function _isArchive($p_filename = null)
  19583. {
  19584. if ($p_filename == null) {
  19585. $p_filename = $this->_tarname;
  19586. }
  19587. clearstatcache();
  19588. return @is_file($p_filename) && !@is_link($p_filename);
  19589. }
  19590. /**
  19591. * @return bool
  19592. */
  19593. public function _openWrite()
  19594. {
  19595. if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
  19596. $this->_file = @gzopen($this->_tarname, "wb9");
  19597. } else {
  19598. if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
  19599. $this->_file = @bzopen($this->_tarname, "w");
  19600. } else {
  19601. if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
  19602. $this->_file = @xzopen($this->_tarname, 'w');
  19603. } else {
  19604. if ($this->_compress_type == 'none') {
  19605. $this->_file = @fopen($this->_tarname, "wb");
  19606. } else {
  19607. $this->_error(
  19608. 'Unknown or missing compression type ('
  19609. . $this->_compress_type . ')'
  19610. );
  19611. return false;
  19612. }
  19613. }
  19614. }
  19615. }
  19616. if ($this->_file == 0) {
  19617. $this->_error(
  19618. 'Unable to open in write mode \''
  19619. . $this->_tarname . '\''
  19620. );
  19621. return false;
  19622. }
  19623. return true;
  19624. }
  19625. /**
  19626. * @return bool
  19627. */
  19628. public function _openRead()
  19629. {
  19630. if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  19631. // ----- Look if a local copy need to be done
  19632. if ($this->_temp_tarname == '') {
  19633. $this->_temp_tarname = uniqid('tar') . '.tmp';
  19634. if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  19635. $this->_error(
  19636. 'Unable to open in read mode \''
  19637. . $this->_tarname . '\''
  19638. );
  19639. $this->_temp_tarname = '';
  19640. return false;
  19641. }
  19642. if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  19643. $this->_error(
  19644. 'Unable to open in write mode \''
  19645. . $this->_temp_tarname . '\''
  19646. );
  19647. $this->_temp_tarname = '';
  19648. return false;
  19649. }
  19650. while ($v_data = @fread($v_file_from, 1024)) {
  19651. @fwrite($v_file_to, $v_data);
  19652. }
  19653. @fclose($v_file_from);
  19654. @fclose($v_file_to);
  19655. }
  19656. // ----- File to open if the local copy
  19657. $v_filename = $this->_temp_tarname;
  19658. } else {
  19659. // ----- File to open if the normal Tar file
  19660. $v_filename = $this->_tarname;
  19661. }
  19662. if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
  19663. $this->_file = @gzopen($v_filename, "rb");
  19664. } else {
  19665. if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
  19666. $this->_file = @bzopen($v_filename, "r");
  19667. } else {
  19668. if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
  19669. $this->_file = @xzopen($v_filename, "r");
  19670. } else {
  19671. if ($this->_compress_type == 'none') {
  19672. $this->_file = @fopen($v_filename, "rb");
  19673. } else {
  19674. $this->_error(
  19675. 'Unknown or missing compression type ('
  19676. . $this->_compress_type . ')'
  19677. );
  19678. return false;
  19679. }
  19680. }
  19681. }
  19682. }
  19683. if ($this->_file == 0) {
  19684. $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
  19685. return false;
  19686. }
  19687. return true;
  19688. }
  19689. /**
  19690. * @return bool
  19691. */
  19692. public function _openReadWrite()
  19693. {
  19694. if ($this->_compress_type == 'gz') {
  19695. $this->_file = @gzopen($this->_tarname, "r+b");
  19696. } else {
  19697. if ($this->_compress_type == 'bz2') {
  19698. $this->_error(
  19699. 'Unable to open bz2 in read/write mode \''
  19700. . $this->_tarname . '\' (limitation of bz2 extension)'
  19701. );
  19702. return false;
  19703. } else {
  19704. if ($this->_compress_type == 'lzma2') {
  19705. $this->_error(
  19706. 'Unable to open lzma2 in read/write mode \''
  19707. . $this->_tarname . '\' (limitation of lzma2 extension)'
  19708. );
  19709. return false;
  19710. } else {
  19711. if ($this->_compress_type == 'none') {
  19712. $this->_file = @fopen($this->_tarname, "r+b");
  19713. } else {
  19714. $this->_error(
  19715. 'Unknown or missing compression type ('
  19716. . $this->_compress_type . ')'
  19717. );
  19718. return false;
  19719. }
  19720. }
  19721. }
  19722. }
  19723. if ($this->_file == 0) {
  19724. $this->_error(
  19725. 'Unable to open in read/write mode \''
  19726. . $this->_tarname . '\''
  19727. );
  19728. return false;
  19729. }
  19730. return true;
  19731. }
  19732. /**
  19733. * @return bool
  19734. */
  19735. public function _close()
  19736. {
  19737. //if (isset($this->_file)) {
  19738. if (is_resource($this->_file)) {
  19739. if ($this->_compress_type == 'gz') {
  19740. @gzclose($this->_file);
  19741. } else {
  19742. if ($this->_compress_type == 'bz2') {
  19743. @bzclose($this->_file);
  19744. } else {
  19745. if ($this->_compress_type == 'lzma2') {
  19746. @xzclose($this->_file);
  19747. } else {
  19748. if ($this->_compress_type == 'none') {
  19749. @fclose($this->_file);
  19750. } else {
  19751. $this->_error(
  19752. 'Unknown or missing compression type ('
  19753. . $this->_compress_type . ')'
  19754. );
  19755. }
  19756. }
  19757. }
  19758. }
  19759. $this->_file = 0;
  19760. }
  19761. // ----- Look if a local copy need to be erase
  19762. // Note that it might be interesting to keep the url for a time : ToDo
  19763. if ($this->_temp_tarname != '') {
  19764. @unlink($this->_temp_tarname);
  19765. $this->_temp_tarname = '';
  19766. }
  19767. return true;
  19768. }
  19769. /**
  19770. * @return bool
  19771. */
  19772. public function _cleanFile()
  19773. {
  19774. $this->_close();
  19775. // ----- Look for a local copy
  19776. if ($this->_temp_tarname != '') {
  19777. // ----- Remove the local copy but not the remote tarname
  19778. @unlink($this->_temp_tarname);
  19779. $this->_temp_tarname = '';
  19780. } else {
  19781. // ----- Remove the local tarname file
  19782. @unlink($this->_tarname);
  19783. }
  19784. $this->_tarname = '';
  19785. return true;
  19786. }
  19787. /**
  19788. * @param mixed $p_binary_data
  19789. * @param integer $p_len
  19790. * @return bool
  19791. */
  19792. public function _writeBlock($p_binary_data, $p_len = null)
  19793. {
  19794. if (is_resource($this->_file)) {
  19795. if ($p_len === null) {
  19796. if ($this->_compress_type == 'gz') {
  19797. @gzputs($this->_file, $p_binary_data);
  19798. } else {
  19799. if ($this->_compress_type == 'bz2') {
  19800. @bzwrite($this->_file, $p_binary_data);
  19801. } else {
  19802. if ($this->_compress_type == 'lzma2') {
  19803. @xzwrite($this->_file, $p_binary_data);
  19804. } else {
  19805. if ($this->_compress_type == 'none') {
  19806. @fputs($this->_file, $p_binary_data);
  19807. } else {
  19808. $this->_error(
  19809. 'Unknown or missing compression type ('
  19810. . $this->_compress_type . ')'
  19811. );
  19812. }
  19813. }
  19814. }
  19815. }
  19816. } else {
  19817. if ($this->_compress_type == 'gz') {
  19818. @gzputs($this->_file, $p_binary_data, $p_len);
  19819. } else {
  19820. if ($this->_compress_type == 'bz2') {
  19821. @bzwrite($this->_file, $p_binary_data, $p_len);
  19822. } else {
  19823. if ($this->_compress_type == 'lzma2') {
  19824. @xzwrite($this->_file, $p_binary_data, $p_len);
  19825. } else {
  19826. if ($this->_compress_type == 'none') {
  19827. @fputs($this->_file, $p_binary_data, $p_len);
  19828. } else {
  19829. $this->_error(
  19830. 'Unknown or missing compression type ('
  19831. . $this->_compress_type . ')'
  19832. );
  19833. }
  19834. }
  19835. }
  19836. }
  19837. }
  19838. }
  19839. return true;
  19840. }
  19841. /**
  19842. * @return null|string
  19843. */
  19844. public function _readBlock()
  19845. {
  19846. $v_block = null;
  19847. if (is_resource($this->_file)) {
  19848. if ($this->_compress_type == 'gz') {
  19849. $v_block = @gzread($this->_file, 512);
  19850. } else {
  19851. if ($this->_compress_type == 'bz2') {
  19852. $v_block = @bzread($this->_file, 512);
  19853. } else {
  19854. if ($this->_compress_type == 'lzma2') {
  19855. $v_block = @xzread($this->_file, 512);
  19856. } else {
  19857. if ($this->_compress_type == 'none') {
  19858. $v_block = @fread($this->_file, 512);
  19859. } else {
  19860. $this->_error(
  19861. 'Unknown or missing compression type ('
  19862. . $this->_compress_type . ')'
  19863. );
  19864. }
  19865. }
  19866. }
  19867. }
  19868. }
  19869. return $v_block;
  19870. }
  19871. /**
  19872. * @param null $p_len
  19873. * @return bool
  19874. */
  19875. public function _jumpBlock($p_len = null)
  19876. {
  19877. if (is_resource($this->_file)) {
  19878. if ($p_len === null) {
  19879. $p_len = 1;
  19880. }
  19881. if ($this->_compress_type == 'gz') {
  19882. @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
  19883. } else {
  19884. if ($this->_compress_type == 'bz2') {
  19885. // ----- Replace missing bztell() and bzseek()
  19886. for ($i = 0; $i < $p_len; $i++) {
  19887. $this->_readBlock();
  19888. }
  19889. } else {
  19890. if ($this->_compress_type == 'lzma2') {
  19891. // ----- Replace missing xztell() and xzseek()
  19892. for ($i = 0; $i < $p_len; $i++) {
  19893. $this->_readBlock();
  19894. }
  19895. } else {
  19896. if ($this->_compress_type == 'none') {
  19897. @fseek($this->_file, $p_len * 512, SEEK_CUR);
  19898. } else {
  19899. $this->_error(
  19900. 'Unknown or missing compression type ('
  19901. . $this->_compress_type . ')'
  19902. );
  19903. }
  19904. }
  19905. }
  19906. }
  19907. }
  19908. return true;
  19909. }
  19910. /**
  19911. * @return bool
  19912. */
  19913. public function _writeFooter()
  19914. {
  19915. if (is_resource($this->_file)) {
  19916. // ----- Write the last 0 filled block for end of archive
  19917. $v_binary_data = pack('a1024', '');
  19918. $this->_writeBlock($v_binary_data);
  19919. }
  19920. return true;
  19921. }
  19922. /**
  19923. * @param array $p_list
  19924. * @param string $p_add_dir
  19925. * @param string $p_remove_dir
  19926. * @return bool
  19927. */
  19928. public function _addList($p_list, $p_add_dir, $p_remove_dir)
  19929. {
  19930. $v_result = true;
  19931. $v_header = array();
  19932. // ----- Remove potential windows directory separator
  19933. $p_add_dir = $this->_translateWinPath($p_add_dir);
  19934. $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  19935. if (!$this->_file) {
  19936. $this->_error('Invalid file descriptor');
  19937. return false;
  19938. }
  19939. if (sizeof($p_list) == 0) {
  19940. return true;
  19941. }
  19942. foreach ($p_list as $v_filename) {
  19943. if (!$v_result) {
  19944. break;
  19945. }
  19946. // ----- Skip the current tar name
  19947. if ($v_filename == $this->_tarname) {
  19948. continue;
  19949. }
  19950. if ($v_filename == '') {
  19951. continue;
  19952. }
  19953. // ----- ignore files and directories matching the ignore regular expression
  19954. if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
  19955. $this->_warning("File '$v_filename' ignored");
  19956. continue;
  19957. }
  19958. if (!file_exists($v_filename) && !is_link($v_filename)) {
  19959. $this->_warning("File '$v_filename' does not exist");
  19960. continue;
  19961. }
  19962. // ----- Add the file or directory header
  19963. if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
  19964. return false;
  19965. }
  19966. if (@is_dir($v_filename) && !@is_link($v_filename)) {
  19967. if (!($p_hdir = opendir($v_filename))) {
  19968. $this->_warning("Directory '$v_filename' can not be read");
  19969. continue;
  19970. }
  19971. while (false !== ($p_hitem = readdir($p_hdir))) {
  19972. if (($p_hitem != '.') && ($p_hitem != '..')) {
  19973. if ($v_filename != ".") {
  19974. $p_temp_list[0] = $v_filename . '/' . $p_hitem;
  19975. } else {
  19976. $p_temp_list[0] = $p_hitem;
  19977. }
  19978. $v_result = $this->_addList(
  19979. $p_temp_list,
  19980. $p_add_dir,
  19981. $p_remove_dir
  19982. );
  19983. }
  19984. }
  19985. unset($p_temp_list);
  19986. unset($p_hdir);
  19987. unset($p_hitem);
  19988. }
  19989. }
  19990. return $v_result;
  19991. }
  19992. /**
  19993. * @param string $p_filename
  19994. * @param mixed $p_header
  19995. * @param string $p_add_dir
  19996. * @param string $p_remove_dir
  19997. * @param null $v_stored_filename
  19998. * @return bool
  19999. */
  20000. public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
  20001. {
  20002. if (!$this->_file) {
  20003. $this->_error('Invalid file descriptor');
  20004. return false;
  20005. }
  20006. if ($p_filename == '') {
  20007. $this->_error('Invalid file name');
  20008. return false;
  20009. }
  20010. if (is_null($v_stored_filename)) {
  20011. // ----- Calculate the stored filename
  20012. $p_filename = $this->_translateWinPath($p_filename, false);
  20013. $v_stored_filename = $p_filename;
  20014. if (strcmp($p_filename, $p_remove_dir) == 0) {
  20015. return true;
  20016. }
  20017. if ($p_remove_dir != '') {
  20018. if (substr($p_remove_dir, -1) != '/') {
  20019. $p_remove_dir .= '/';
  20020. }
  20021. if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
  20022. $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  20023. }
  20024. }
  20025. $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  20026. if ($p_add_dir != '') {
  20027. if (substr($p_add_dir, -1) == '/') {
  20028. $v_stored_filename = $p_add_dir . $v_stored_filename;
  20029. } else {
  20030. $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
  20031. }
  20032. }
  20033. $v_stored_filename = $this->_pathReduction($v_stored_filename);
  20034. }
  20035. if ($this->_isArchive($p_filename)) {
  20036. if (($v_file = @fopen($p_filename, "rb")) == 0) {
  20037. $this->_warning(
  20038. "Unable to open file '" . $p_filename
  20039. . "' in binary read mode"
  20040. );
  20041. return true;
  20042. }
  20043. if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
  20044. return false;
  20045. }
  20046. while (($v_buffer = fread($v_file, $this->buffer_length)) != '') {
  20047. $buffer_length = strlen("$v_buffer");
  20048. if ($buffer_length != $this->buffer_length) {
  20049. $pack_size = ((int)($buffer_length / 512) + 1) * 512;
  20050. $pack_format = sprintf('a%d', $pack_size);
  20051. } else {
  20052. $pack_format = sprintf('a%d', $this->buffer_length);
  20053. }
  20054. $v_binary_data = pack($pack_format, "$v_buffer");
  20055. $this->_writeBlock($v_binary_data);
  20056. }
  20057. fclose($v_file);
  20058. } else {
  20059. // ----- Only header for dir
  20060. if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
  20061. return false;
  20062. }
  20063. }
  20064. return true;
  20065. }
  20066. /**
  20067. * @param string $p_filename
  20068. * @param string $p_string
  20069. * @param bool $p_datetime
  20070. * @param array $p_params
  20071. * @return bool
  20072. */
  20073. public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
  20074. {
  20075. $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
  20076. $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
  20077. $p_type = @$p_params["type"] ? $p_params["type"] : "";
  20078. $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
  20079. $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
  20080. if (!$this->_file) {
  20081. $this->_error('Invalid file descriptor');
  20082. return false;
  20083. }
  20084. if ($p_filename == '') {
  20085. $this->_error('Invalid file name');
  20086. return false;
  20087. }
  20088. // ----- Calculate the stored filename
  20089. $p_filename = $this->_translateWinPath($p_filename, false);
  20090. // ----- If datetime is not specified, set current time
  20091. if ($p_datetime === false) {
  20092. $p_datetime = time();
  20093. }
  20094. if (!$this->_writeHeaderBlock(
  20095. $p_filename,
  20096. strlen($p_string),
  20097. $p_stamp,
  20098. $p_mode,
  20099. $p_type,
  20100. $p_uid,
  20101. $p_gid
  20102. )
  20103. ) {
  20104. return false;
  20105. }
  20106. $i = 0;
  20107. while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
  20108. $v_binary_data = pack("a512", $v_buffer);
  20109. $this->_writeBlock($v_binary_data);
  20110. }
  20111. return true;
  20112. }
  20113. /**
  20114. * @param string $p_filename
  20115. * @param string $p_stored_filename
  20116. * @return bool
  20117. */
  20118. public function _writeHeader($p_filename, $p_stored_filename)
  20119. {
  20120. if ($p_stored_filename == '') {
  20121. $p_stored_filename = $p_filename;
  20122. }
  20123. $v_reduced_filename = $this->_pathReduction($p_stored_filename);
  20124. if (strlen($v_reduced_filename) > 99) {
  20125. if (!$this->_writeLongHeader($v_reduced_filename, false)) {
  20126. return false;
  20127. }
  20128. }
  20129. $v_linkname = '';
  20130. if (@is_link($p_filename)) {
  20131. $v_linkname = readlink($p_filename);
  20132. }
  20133. if (strlen($v_linkname) > 99) {
  20134. if (!$this->_writeLongHeader($v_linkname, true)) {
  20135. return false;
  20136. }
  20137. }
  20138. $v_info = lstat($p_filename);
  20139. $v_uid = sprintf("%07s", DecOct($v_info[4]));
  20140. $v_gid = sprintf("%07s", DecOct($v_info[5]));
  20141. $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
  20142. $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
  20143. if (@is_link($p_filename)) {
  20144. $v_typeflag = '2';
  20145. $v_size = sprintf("%011s", DecOct(0));
  20146. } elseif (@is_dir($p_filename)) {
  20147. $v_typeflag = "5";
  20148. $v_size = sprintf("%011s", DecOct(0));
  20149. } else {
  20150. $v_typeflag = '0';
  20151. clearstatcache();
  20152. $v_size = sprintf("%011s", DecOct($v_info['size']));
  20153. }
  20154. $v_magic = 'ustar ';
  20155. $v_version = ' ';
  20156. if (function_exists('posix_getpwuid')) {
  20157. $userinfo = posix_getpwuid($v_info[4]);
  20158. $groupinfo = posix_getgrgid($v_info[5]);
  20159. $v_uname = $userinfo['name'];
  20160. $v_gname = $groupinfo['name'];
  20161. } else {
  20162. $v_uname = '';
  20163. $v_gname = '';
  20164. }
  20165. $v_devmajor = '';
  20166. $v_devminor = '';
  20167. $v_prefix = '';
  20168. $v_binary_data_first = pack(
  20169. "a100a8a8a8a12a12",
  20170. $v_reduced_filename,
  20171. $v_perms,
  20172. $v_uid,
  20173. $v_gid,
  20174. $v_size,
  20175. $v_mtime
  20176. );
  20177. $v_binary_data_last = pack(
  20178. "a1a100a6a2a32a32a8a8a155a12",
  20179. $v_typeflag,
  20180. $v_linkname,
  20181. $v_magic,
  20182. $v_version,
  20183. $v_uname,
  20184. $v_gname,
  20185. $v_devmajor,
  20186. $v_devminor,
  20187. $v_prefix,
  20188. ''
  20189. );
  20190. // ----- Calculate the checksum
  20191. $v_checksum = 0;
  20192. // ..... First part of the header
  20193. for ($i = 0; $i < 148; $i++) {
  20194. $v_checksum += ord(substr($v_binary_data_first, $i, 1));
  20195. }
  20196. // ..... Ignore the checksum value and replace it by ' ' (space)
  20197. for ($i = 148; $i < 156; $i++) {
  20198. $v_checksum += ord(' ');
  20199. }
  20200. // ..... Last part of the header
  20201. for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
  20202. $v_checksum += ord(substr($v_binary_data_last, $j, 1));
  20203. }
  20204. // ----- Write the first 148 bytes of the header in the archive
  20205. $this->_writeBlock($v_binary_data_first, 148);
  20206. // ----- Write the calculated checksum
  20207. $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
  20208. $v_binary_data = pack("a8", $v_checksum);
  20209. $this->_writeBlock($v_binary_data, 8);
  20210. // ----- Write the last 356 bytes of the header in the archive
  20211. $this->_writeBlock($v_binary_data_last, 356);
  20212. return true;
  20213. }
  20214. /**
  20215. * @param string $p_filename
  20216. * @param int $p_size
  20217. * @param int $p_mtime
  20218. * @param int $p_perms
  20219. * @param string $p_type
  20220. * @param int $p_uid
  20221. * @param int $p_gid
  20222. * @return bool
  20223. */
  20224. public function _writeHeaderBlock(
  20225. $p_filename,
  20226. $p_size,
  20227. $p_mtime = 0,
  20228. $p_perms = 0,
  20229. $p_type = '',
  20230. $p_uid = 0,
  20231. $p_gid = 0
  20232. )
  20233. {
  20234. $p_filename = $this->_pathReduction($p_filename);
  20235. if (strlen($p_filename) > 99) {
  20236. if (!$this->_writeLongHeader($p_filename, false)) {
  20237. return false;
  20238. }
  20239. }
  20240. if ($p_type == "5") {
  20241. $v_size = sprintf("%011s", DecOct(0));
  20242. } else {
  20243. $v_size = sprintf("%011s", DecOct($p_size));
  20244. }
  20245. $v_uid = sprintf("%07s", DecOct($p_uid));
  20246. $v_gid = sprintf("%07s", DecOct($p_gid));
  20247. $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
  20248. $v_mtime = sprintf("%11s", DecOct($p_mtime));
  20249. $v_linkname = '';
  20250. $v_magic = 'ustar ';
  20251. $v_version = ' ';
  20252. if (function_exists('posix_getpwuid')) {
  20253. $userinfo = posix_getpwuid($p_uid);
  20254. $groupinfo = posix_getgrgid($p_gid);
  20255. $v_uname = $userinfo['name'];
  20256. $v_gname = $groupinfo['name'];
  20257. } else {
  20258. $v_uname = '';
  20259. $v_gname = '';
  20260. }
  20261. $v_devmajor = '';
  20262. $v_devminor = '';
  20263. $v_prefix = '';
  20264. $v_binary_data_first = pack(
  20265. "a100a8a8a8a12A12",
  20266. $p_filename,
  20267. $v_perms,
  20268. $v_uid,
  20269. $v_gid,
  20270. $v_size,
  20271. $v_mtime
  20272. );
  20273. $v_binary_data_last = pack(
  20274. "a1a100a6a2a32a32a8a8a155a12",
  20275. $p_type,
  20276. $v_linkname,
  20277. $v_magic,
  20278. $v_version,
  20279. $v_uname,
  20280. $v_gname,
  20281. $v_devmajor,
  20282. $v_devminor,
  20283. $v_prefix,
  20284. ''
  20285. );
  20286. // ----- Calculate the checksum
  20287. $v_checksum = 0;
  20288. // ..... First part of the header
  20289. for ($i = 0; $i < 148; $i++) {
  20290. $v_checksum += ord(substr($v_binary_data_first, $i, 1));
  20291. }
  20292. // ..... Ignore the checksum value and replace it by ' ' (space)
  20293. for ($i = 148; $i < 156; $i++) {
  20294. $v_checksum += ord(' ');
  20295. }
  20296. // ..... Last part of the header
  20297. for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
  20298. $v_checksum += ord(substr($v_binary_data_last, $j, 1));
  20299. }
  20300. // ----- Write the first 148 bytes of the header in the archive
  20301. $this->_writeBlock($v_binary_data_first, 148);
  20302. // ----- Write the calculated checksum
  20303. $v_checksum = sprintf("%06s ", DecOct($v_checksum));
  20304. $v_binary_data = pack("a8", $v_checksum);
  20305. $this->_writeBlock($v_binary_data, 8);
  20306. // ----- Write the last 356 bytes of the header in the archive
  20307. $this->_writeBlock($v_binary_data_last, 356);
  20308. return true;
  20309. }
  20310. /**
  20311. * @param string $p_filename
  20312. * @return bool
  20313. */
  20314. public function _writeLongHeader($p_filename, $is_link = false)
  20315. {
  20316. $v_uid = sprintf("%07s", 0);
  20317. $v_gid = sprintf("%07s", 0);
  20318. $v_perms = sprintf("%07s", 0);
  20319. $v_size = sprintf("%'011s", DecOct(strlen($p_filename)));
  20320. $v_mtime = sprintf("%011s", 0);
  20321. $v_typeflag = ($is_link ? 'K' : 'L');
  20322. $v_linkname = '';
  20323. $v_magic = 'ustar ';
  20324. $v_version = ' ';
  20325. $v_uname = '';
  20326. $v_gname = '';
  20327. $v_devmajor = '';
  20328. $v_devminor = '';
  20329. $v_prefix = '';
  20330. $v_binary_data_first = pack(
  20331. "a100a8a8a8a12a12",
  20332. '././@LongLink',
  20333. $v_perms,
  20334. $v_uid,
  20335. $v_gid,
  20336. $v_size,
  20337. $v_mtime
  20338. );
  20339. $v_binary_data_last = pack(
  20340. "a1a100a6a2a32a32a8a8a155a12",
  20341. $v_typeflag,
  20342. $v_linkname,
  20343. $v_magic,
  20344. $v_version,
  20345. $v_uname,
  20346. $v_gname,
  20347. $v_devmajor,
  20348. $v_devminor,
  20349. $v_prefix,
  20350. ''
  20351. );
  20352. // ----- Calculate the checksum
  20353. $v_checksum = 0;
  20354. // ..... First part of the header
  20355. for ($i = 0; $i < 148; $i++) {
  20356. $v_checksum += ord(substr($v_binary_data_first, $i, 1));
  20357. }
  20358. // ..... Ignore the checksum value and replace it by ' ' (space)
  20359. for ($i = 148; $i < 156; $i++) {
  20360. $v_checksum += ord(' ');
  20361. }
  20362. // ..... Last part of the header
  20363. for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
  20364. $v_checksum += ord(substr($v_binary_data_last, $j, 1));
  20365. }
  20366. // ----- Write the first 148 bytes of the header in the archive
  20367. $this->_writeBlock($v_binary_data_first, 148);
  20368. // ----- Write the calculated checksum
  20369. $v_checksum = sprintf("%06s\0 ", DecOct($v_checksum));
  20370. $v_binary_data = pack("a8", $v_checksum);
  20371. $this->_writeBlock($v_binary_data, 8);
  20372. // ----- Write the last 356 bytes of the header in the archive
  20373. $this->_writeBlock($v_binary_data_last, 356);
  20374. // ----- Write the filename as content of the block
  20375. $i = 0;
  20376. while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
  20377. $v_binary_data = pack("a512", "$v_buffer");
  20378. $this->_writeBlock($v_binary_data);
  20379. }
  20380. return true;
  20381. }
  20382. /**
  20383. * @param mixed $v_binary_data
  20384. * @param mixed $v_header
  20385. * @return bool
  20386. */
  20387. public function _readHeader($v_binary_data, &$v_header)
  20388. {
  20389. if (strlen($v_binary_data) == 0) {
  20390. $v_header['filename'] = '';
  20391. return true;
  20392. }
  20393. if (strlen($v_binary_data) != 512) {
  20394. $v_header['filename'] = '';
  20395. $this->_error('Invalid block size : ' . strlen($v_binary_data));
  20396. return false;
  20397. }
  20398. if (!is_array($v_header)) {
  20399. $v_header = array();
  20400. }
  20401. // ----- Calculate the checksum
  20402. $v_checksum = 0;
  20403. // ..... First part of the header
  20404. $v_binary_split = str_split($v_binary_data);
  20405. $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
  20406. $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
  20407. $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
  20408. $v_data = unpack($this->_fmt, $v_binary_data);
  20409. if (strlen($v_data["prefix"]) > 0) {
  20410. $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
  20411. }
  20412. // ----- Extract the checksum
  20413. $v_data_checksum = trim($v_data['checksum']);
  20414. if (!preg_match('/^[0-7]*$/', $v_data_checksum)) {
  20415. $this->_error(
  20416. 'Invalid checksum for file "' . $v_data['filename']
  20417. . '" : ' . $v_data_checksum . ' extracted'
  20418. );
  20419. return false;
  20420. }
  20421. $v_header['checksum'] = OctDec($v_data_checksum);
  20422. if ($v_header['checksum'] != $v_checksum) {
  20423. $v_header['filename'] = '';
  20424. // ----- Look for last block (empty block)
  20425. if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
  20426. return true;
  20427. }
  20428. $this->_error(
  20429. 'Invalid checksum for file "' . $v_data['filename']
  20430. . '" : ' . $v_checksum . ' calculated, '
  20431. . $v_header['checksum'] . ' expected'
  20432. );
  20433. return false;
  20434. }
  20435. // ----- Extract the properties
  20436. $v_header['filename'] = rtrim($v_data['filename'], "\0");
  20437. if ($this->_maliciousFilename($v_header['filename'])) {
  20438. $this->_error(
  20439. 'Malicious .tar detected, file "' . $v_header['filename'] .
  20440. '" will not install in desired directory tree'
  20441. );
  20442. return false;
  20443. }
  20444. $v_header['mode'] = OctDec(trim($v_data['mode']));
  20445. $v_header['uid'] = OctDec(trim($v_data['uid']));
  20446. $v_header['gid'] = OctDec(trim($v_data['gid']));
  20447. $v_header['size'] = $this->_tarRecToSize($v_data['size']);
  20448. $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  20449. if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  20450. $v_header['size'] = 0;
  20451. }
  20452. $v_header['link'] = trim($v_data['link']);
  20453. /* ----- All these fields are removed form the header because
  20454. they do not carry interesting info
  20455. $v_header[magic] = trim($v_data[magic]);
  20456. $v_header[version] = trim($v_data[version]);
  20457. $v_header[uname] = trim($v_data[uname]);
  20458. $v_header[gname] = trim($v_data[gname]);
  20459. $v_header[devmajor] = trim($v_data[devmajor]);
  20460. $v_header[devminor] = trim($v_data[devminor]);
  20461. */
  20462. return true;
  20463. }
  20464. /**
  20465. * Convert Tar record size to actual size
  20466. *
  20467. * @param string $tar_size
  20468. * @return size of tar record in bytes
  20469. */
  20470. private function _tarRecToSize($tar_size)
  20471. {
  20472. /*
  20473. * First byte of size has a special meaning if bit 7 is set.
  20474. *
  20475. * Bit 7 indicates base-256 encoding if set.
  20476. * Bit 6 is the sign bit.
  20477. * Bits 5:0 are most significant value bits.
  20478. */
  20479. $ch = ord($tar_size[0]);
  20480. if ($ch & 0x80) {
  20481. // Full 12-bytes record is required.
  20482. $rec_str = $tar_size . "\x00";
  20483. $size = ($ch & 0x40) ? -1 : 0;
  20484. $size = ($size << 6) | ($ch & 0x3f);
  20485. for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
  20486. $size = ($size * 256) + ord($rec_str[$num_ch]);
  20487. }
  20488. return $size;
  20489. } else {
  20490. return OctDec(trim($tar_size));
  20491. }
  20492. }
  20493. /**
  20494. * Detect and report a malicious file name
  20495. *
  20496. * @param string $file
  20497. *
  20498. * @return bool
  20499. */
  20500. private function _maliciousFilename($file)
  20501. {
  20502. if (strpos($file, 'phar://') === 0) {
  20503. return true;
  20504. }
  20505. if (strpos($file, '../') !== false || strpos($file, '..\\') !== false) {
  20506. return true;
  20507. }
  20508. return false;
  20509. }
  20510. /**
  20511. * @param $v_header
  20512. * @return bool
  20513. */
  20514. public function _readLongHeader(&$v_header)
  20515. {
  20516. $v_filename = '';
  20517. $v_filesize = $v_header['size'];
  20518. $n = floor($v_header['size'] / 512);
  20519. for ($i = 0; $i < $n; $i++) {
  20520. $v_content = $this->_readBlock();
  20521. $v_filename .= $v_content;
  20522. }
  20523. if (($v_header['size'] % 512) != 0) {
  20524. $v_content = $this->_readBlock();
  20525. $v_filename .= $v_content;
  20526. }
  20527. // ----- Read the next header
  20528. $v_binary_data = $this->_readBlock();
  20529. if (!$this->_readHeader($v_binary_data, $v_header)) {
  20530. return false;
  20531. }
  20532. $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
  20533. $v_header['filename'] = $v_filename;
  20534. if ($this->_maliciousFilename($v_filename)) {
  20535. $this->_error(
  20536. 'Malicious .tar detected, file "' . $v_filename .
  20537. '" will not install in desired directory tree'
  20538. );
  20539. return false;
  20540. }
  20541. return true;
  20542. }
  20543. /**
  20544. * This method extract from the archive one file identified by $p_filename.
  20545. * The return value is a string with the file content, or null on error.
  20546. *
  20547. * @param string $p_filename The path of the file to extract in a string.
  20548. *
  20549. * @return a string with the file content or null.
  20550. */
  20551. private function _extractInString($p_filename)
  20552. {
  20553. $v_result_str = "";
  20554. while (strlen($v_binary_data = $this->_readBlock()) != 0) {
  20555. if (!$this->_readHeader($v_binary_data, $v_header)) {
  20556. return null;
  20557. }
  20558. if ($v_header['filename'] == '') {
  20559. continue;
  20560. }
  20561. switch ($v_header['typeflag']) {
  20562. case 'L':
  20563. {
  20564. if (!$this->_readLongHeader($v_header)) {
  20565. return null;
  20566. }
  20567. }
  20568. break;
  20569. case 'K':
  20570. {
  20571. $v_link_header = $v_header;
  20572. if (!$this->_readLongHeader($v_link_header)) {
  20573. return null;
  20574. }
  20575. $v_header['link'] = $v_link_header['filename'];
  20576. }
  20577. break;
  20578. }
  20579. if ($v_header['filename'] == $p_filename) {
  20580. if ($v_header['typeflag'] == "5") {
  20581. $this->_error(
  20582. 'Unable to extract in string a directory '
  20583. . 'entry {' . $v_header['filename'] . '}'
  20584. );
  20585. return null;
  20586. } else {
  20587. $n = floor($v_header['size'] / 512);
  20588. for ($i = 0; $i < $n; $i++) {
  20589. $v_result_str .= $this->_readBlock();
  20590. }
  20591. if (($v_header['size'] % 512) != 0) {
  20592. $v_content = $this->_readBlock();
  20593. $v_result_str .= substr(
  20594. $v_content,
  20595. 0,
  20596. ($v_header['size'] % 512)
  20597. );
  20598. }
  20599. return $v_result_str;
  20600. }
  20601. } else {
  20602. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  20603. }
  20604. }
  20605. return null;
  20606. }
  20607. /**
  20608. * @param string $p_path
  20609. * @param string $p_list_detail
  20610. * @param string $p_mode
  20611. * @param string $p_file_list
  20612. * @param string $p_remove_path
  20613. * @param bool $p_preserve
  20614. * @return bool
  20615. */
  20616. public function _extractList(
  20617. $p_path,
  20618. &$p_list_detail,
  20619. $p_mode,
  20620. $p_file_list,
  20621. $p_remove_path,
  20622. $p_preserve = false
  20623. )
  20624. {
  20625. $v_result = true;
  20626. $v_nb = 0;
  20627. $v_extract_all = true;
  20628. $v_listing = false;
  20629. $p_path = $this->_translateWinPath($p_path, false);
  20630. if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  20631. && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
  20632. ) {
  20633. $p_path = "./" . $p_path;
  20634. }
  20635. $p_remove_path = $this->_translateWinPath($p_remove_path);
  20636. // ----- Look for path to remove format (should end by /)
  20637. if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
  20638. $p_remove_path .= '/';
  20639. }
  20640. $p_remove_path_size = strlen($p_remove_path);
  20641. switch ($p_mode) {
  20642. case "complete" :
  20643. $v_extract_all = true;
  20644. $v_listing = false;
  20645. break;
  20646. case "partial" :
  20647. $v_extract_all = false;
  20648. $v_listing = false;
  20649. break;
  20650. case "list" :
  20651. $v_extract_all = false;
  20652. $v_listing = true;
  20653. break;
  20654. default :
  20655. $this->_error('Invalid extract mode (' . $p_mode . ')');
  20656. return false;
  20657. }
  20658. clearstatcache();
  20659. while (strlen($v_binary_data = $this->_readBlock()) != 0) {
  20660. $v_extract_file = false;
  20661. $v_extraction_stopped = 0;
  20662. if (!$this->_readHeader($v_binary_data, $v_header)) {
  20663. return false;
  20664. }
  20665. if ($v_header['filename'] == '') {
  20666. continue;
  20667. }
  20668. switch ($v_header['typeflag']) {
  20669. case 'L':
  20670. {
  20671. if (!$this->_readLongHeader($v_header)) {
  20672. return null;
  20673. }
  20674. }
  20675. break;
  20676. case 'K':
  20677. {
  20678. $v_link_header = $v_header;
  20679. if (!$this->_readLongHeader($v_link_header)) {
  20680. return null;
  20681. }
  20682. $v_header['link'] = $v_link_header['filename'];
  20683. }
  20684. break;
  20685. }
  20686. // ignore extended / pax headers
  20687. if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
  20688. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  20689. continue;
  20690. }
  20691. if ((!$v_extract_all) && (is_array($p_file_list))) {
  20692. // ----- By default no unzip if the file is not found
  20693. $v_extract_file = false;
  20694. for ($i = 0; $i < sizeof($p_file_list); $i++) {
  20695. // ----- Look if it is a directory
  20696. if (substr($p_file_list[$i], -1) == '/') {
  20697. // ----- Look if the directory is in the filename path
  20698. if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  20699. && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  20700. == $p_file_list[$i])
  20701. ) {
  20702. $v_extract_file = true;
  20703. break;
  20704. }
  20705. } // ----- It is a file, so compare the file names
  20706. elseif ($p_file_list[$i] == $v_header['filename']) {
  20707. $v_extract_file = true;
  20708. break;
  20709. }
  20710. }
  20711. } else {
  20712. $v_extract_file = true;
  20713. }
  20714. // ----- Look if this file need to be extracted
  20715. if (($v_extract_file) && (!$v_listing)) {
  20716. if (($p_remove_path != '')
  20717. && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
  20718. == $p_remove_path)
  20719. ) {
  20720. $v_header['filename'] = substr(
  20721. $v_header['filename'],
  20722. $p_remove_path_size
  20723. );
  20724. if ($v_header['filename'] == '') {
  20725. continue;
  20726. }
  20727. }
  20728. if (($p_path != './') && ($p_path != '/')) {
  20729. while (substr($p_path, -1) == '/') {
  20730. $p_path = substr($p_path, 0, strlen($p_path) - 1);
  20731. }
  20732. if (substr($v_header['filename'], 0, 1) == '/') {
  20733. $v_header['filename'] = $p_path . $v_header['filename'];
  20734. } else {
  20735. $v_header['filename'] = $p_path . '/' . $v_header['filename'];
  20736. }
  20737. }
  20738. if (file_exists($v_header['filename'])) {
  20739. if ((@is_dir($v_header['filename']))
  20740. && ($v_header['typeflag'] == '')
  20741. ) {
  20742. $this->_error(
  20743. 'File ' . $v_header['filename']
  20744. . ' already exists as a directory'
  20745. );
  20746. return false;
  20747. }
  20748. if (($this->_isArchive($v_header['filename']))
  20749. && ($v_header['typeflag'] == "5")
  20750. ) {
  20751. $this->_error(
  20752. 'Directory ' . $v_header['filename']
  20753. . ' already exists as a file'
  20754. );
  20755. return false;
  20756. }
  20757. if (!is_writeable($v_header['filename'])) {
  20758. $this->_error(
  20759. 'File ' . $v_header['filename']
  20760. . ' already exists and is write protected'
  20761. );
  20762. return false;
  20763. }
  20764. if (filemtime($v_header['filename']) > $v_header['mtime']) {
  20765. // To be completed : An error or silent no replace ?
  20766. }
  20767. } // ----- Check the directory availability and create it if necessary
  20768. elseif (($v_result
  20769. = $this->_dirCheck(
  20770. ($v_header['typeflag'] == "5"
  20771. ? $v_header['filename']
  20772. : dirname($v_header['filename']))
  20773. )) != 1
  20774. ) {
  20775. $this->_error('Unable to create path for ' . $v_header['filename']);
  20776. return false;
  20777. }
  20778. if ($v_extract_file) {
  20779. if ($v_header['typeflag'] == "5") {
  20780. if (!@file_exists($v_header['filename'])) {
  20781. if (!@mkdir($v_header['filename'], 0777)) {
  20782. $this->_error(
  20783. 'Unable to create directory {'
  20784. . $v_header['filename'] . '}'
  20785. );
  20786. return false;
  20787. }
  20788. }
  20789. } elseif ($v_header['typeflag'] == "2") {
  20790. if (@file_exists($v_header['filename'])) {
  20791. @unlink($v_header['filename']);
  20792. }
  20793. if (!@symlink($v_header['link'], $v_header['filename'])) {
  20794. $this->_error(
  20795. 'Unable to extract symbolic link {'
  20796. . $v_header['filename'] . '}'
  20797. );
  20798. return false;
  20799. }
  20800. } else {
  20801. if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  20802. $this->_error(
  20803. 'Error while opening {' . $v_header['filename']
  20804. . '} in write binary mode'
  20805. );
  20806. return false;
  20807. } else {
  20808. $n = floor($v_header['size'] / 512);
  20809. for ($i = 0; $i < $n; $i++) {
  20810. $v_content = $this->_readBlock();
  20811. fwrite($v_dest_file, $v_content, 512);
  20812. }
  20813. if (($v_header['size'] % 512) != 0) {
  20814. $v_content = $this->_readBlock();
  20815. fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  20816. }
  20817. @fclose($v_dest_file);
  20818. if ($p_preserve) {
  20819. @chown($v_header['filename'], $v_header['uid']);
  20820. @chgrp($v_header['filename'], $v_header['gid']);
  20821. }
  20822. // ----- Change the file mode, mtime
  20823. @touch($v_header['filename'], $v_header['mtime']);
  20824. if ($v_header['mode'] & 0111) {
  20825. // make file executable, obey umask
  20826. $mode = fileperms($v_header['filename']) | (~umask() & 0111);
  20827. @chmod($v_header['filename'], $mode);
  20828. }
  20829. }
  20830. // ----- Check the file size
  20831. clearstatcache();
  20832. if (!is_file($v_header['filename'])) {
  20833. $this->_error(
  20834. 'Extracted file ' . $v_header['filename']
  20835. . 'does not exist. Archive may be corrupted.'
  20836. );
  20837. return false;
  20838. }
  20839. $filesize = filesize($v_header['filename']);
  20840. if ($filesize != $v_header['size']) {
  20841. $this->_error(
  20842. 'Extracted file ' . $v_header['filename']
  20843. . ' does not have the correct file size \''
  20844. . $filesize
  20845. . '\' (' . $v_header['size']
  20846. . ' expected). Archive may be corrupted.'
  20847. );
  20848. return false;
  20849. }
  20850. }
  20851. } else {
  20852. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  20853. }
  20854. } else {
  20855. $this->_jumpBlock(ceil(($v_header['size'] / 512)));
  20856. }
  20857. /* TBC : Seems to be unused ...
  20858. if ($this->_compress)
  20859. $v_end_of_file = @gzeof($this->_file);
  20860. else
  20861. $v_end_of_file = @feof($this->_file);
  20862. */
  20863. if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  20864. // ----- Log extracted files
  20865. if (($v_file_dir = dirname($v_header['filename']))
  20866. == $v_header['filename']
  20867. ) {
  20868. $v_file_dir = '';
  20869. }
  20870. if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
  20871. $v_file_dir = '/';
  20872. }
  20873. $p_list_detail[$v_nb++] = $v_header;
  20874. if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
  20875. return true;
  20876. }
  20877. }
  20878. }
  20879. return true;
  20880. }
  20881. /**
  20882. * @return bool
  20883. */
  20884. public function _openAppend()
  20885. {
  20886. if (filesize($this->_tarname) == 0) {
  20887. return $this->_openWrite();
  20888. }
  20889. if ($this->_compress) {
  20890. $this->_close();
  20891. if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
  20892. $this->_error(
  20893. 'Error while renaming \'' . $this->_tarname
  20894. . '\' to temporary file \'' . $this->_tarname
  20895. . '.tmp\''
  20896. );
  20897. return false;
  20898. }
  20899. if ($this->_compress_type == 'gz') {
  20900. $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
  20901. } elseif ($this->_compress_type == 'bz2') {
  20902. $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
  20903. } elseif ($this->_compress_type == 'lzma2') {
  20904. $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
  20905. }
  20906. if ($v_temp_tar == 0) {
  20907. $this->_error(
  20908. 'Unable to open file \'' . $this->_tarname
  20909. . '.tmp\' in binary read mode'
  20910. );
  20911. @rename($this->_tarname . ".tmp", $this->_tarname);
  20912. return false;
  20913. }
  20914. if (!$this->_openWrite()) {
  20915. @rename($this->_tarname . ".tmp", $this->_tarname);
  20916. return false;
  20917. }
  20918. if ($this->_compress_type == 'gz') {
  20919. $end_blocks = 0;
  20920. while (!@gzeof($v_temp_tar)) {
  20921. $v_buffer = @gzread($v_temp_tar, 512);
  20922. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  20923. $end_blocks++;
  20924. // do not copy end blocks, we will re-make them
  20925. // after appending
  20926. continue;
  20927. } elseif ($end_blocks > 0) {
  20928. for ($i = 0; $i < $end_blocks; $i++) {
  20929. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  20930. }
  20931. $end_blocks = 0;
  20932. }
  20933. $v_binary_data = pack("a512", $v_buffer);
  20934. $this->_writeBlock($v_binary_data);
  20935. }
  20936. @gzclose($v_temp_tar);
  20937. } elseif ($this->_compress_type == 'bz2') {
  20938. $end_blocks = 0;
  20939. while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
  20940. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  20941. $end_blocks++;
  20942. // do not copy end blocks, we will re-make them
  20943. // after appending
  20944. continue;
  20945. } elseif ($end_blocks > 0) {
  20946. for ($i = 0; $i < $end_blocks; $i++) {
  20947. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  20948. }
  20949. $end_blocks = 0;
  20950. }
  20951. $v_binary_data = pack("a512", $v_buffer);
  20952. $this->_writeBlock($v_binary_data);
  20953. }
  20954. @bzclose($v_temp_tar);
  20955. } elseif ($this->_compress_type == 'lzma2') {
  20956. $end_blocks = 0;
  20957. while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
  20958. if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
  20959. $end_blocks++;
  20960. // do not copy end blocks, we will re-make them
  20961. // after appending
  20962. continue;
  20963. } elseif ($end_blocks > 0) {
  20964. for ($i = 0; $i < $end_blocks; $i++) {
  20965. $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  20966. }
  20967. $end_blocks = 0;
  20968. }
  20969. $v_binary_data = pack("a512", $v_buffer);
  20970. $this->_writeBlock($v_binary_data);
  20971. }
  20972. @xzclose($v_temp_tar);
  20973. }
  20974. if (!@unlink($this->_tarname . ".tmp")) {
  20975. $this->_error(
  20976. 'Error while deleting temporary file \''
  20977. . $this->_tarname . '.tmp\''
  20978. );
  20979. }
  20980. } else {
  20981. // ----- For not compressed tar, just add files before the last
  20982. // one or two 512 bytes block
  20983. if (!$this->_openReadWrite()) {
  20984. return false;
  20985. }
  20986. clearstatcache();
  20987. $v_size = filesize($this->_tarname);
  20988. // We might have zero, one or two end blocks.
  20989. // The standard is two, but we should try to handle
  20990. // other cases.
  20991. fseek($this->_file, $v_size - 1024);
  20992. if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  20993. fseek($this->_file, $v_size - 1024);
  20994. } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
  20995. fseek($this->_file, $v_size - 512);
  20996. }
  20997. }
  20998. return true;
  20999. }
  21000. /**
  21001. * @param $p_filelist
  21002. * @param string $p_add_dir
  21003. * @param string $p_remove_dir
  21004. * @return bool
  21005. */
  21006. public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
  21007. {
  21008. if (!$this->_openAppend()) {
  21009. return false;
  21010. }
  21011. if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
  21012. $this->_writeFooter();
  21013. }
  21014. $this->_close();
  21015. return true;
  21016. }
  21017. /**
  21018. * Check if a directory exists and create it (including parent
  21019. * dirs) if not.
  21020. *
  21021. * @param string $p_dir directory to check
  21022. *
  21023. * @return bool true if the directory exists or was created
  21024. */
  21025. public function _dirCheck($p_dir)
  21026. {
  21027. clearstatcache();
  21028. if ((@is_dir($p_dir)) || ($p_dir == '')) {
  21029. return true;
  21030. }
  21031. $p_parent_dir = dirname($p_dir);
  21032. if (($p_parent_dir != $p_dir) &&
  21033. ($p_parent_dir != '') &&
  21034. (!$this->_dirCheck($p_parent_dir))
  21035. ) {
  21036. return false;
  21037. }
  21038. if (!@mkdir($p_dir, 0777)) {
  21039. $this->_error("Unable to create directory '$p_dir'");
  21040. return false;
  21041. }
  21042. return true;
  21043. }
  21044. /**
  21045. * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
  21046. * rand emove double slashes.
  21047. *
  21048. * @param string $p_dir path to reduce
  21049. *
  21050. * @return string reduced path
  21051. */
  21052. private function _pathReduction($p_dir)
  21053. {
  21054. $v_result = '';
  21055. // ----- Look for not empty path
  21056. if ($p_dir != '') {
  21057. // ----- Explode path by directory names
  21058. $v_list = explode('/', $p_dir);
  21059. // ----- Study directories from last to first
  21060. for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
  21061. // ----- Look for current path
  21062. if ($v_list[$i] == ".") {
  21063. // ----- Ignore this directory
  21064. // Should be the first $i=0, but no check is done
  21065. } else {
  21066. if ($v_list[$i] == "..") {
  21067. // ----- Ignore it and ignore the $i-1
  21068. $i--;
  21069. } else {
  21070. if (($v_list[$i] == '')
  21071. && ($i != (sizeof($v_list) - 1))
  21072. && ($i != 0)
  21073. ) {
  21074. // ----- Ignore only the double '//' in path,
  21075. // but not the first and last /
  21076. } else {
  21077. $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
  21078. . $v_result : '');
  21079. }
  21080. }
  21081. }
  21082. }
  21083. }
  21084. if (defined('OS_WINDOWS') && OS_WINDOWS) {
  21085. $v_result = strtr($v_result, '\\', '/');
  21086. }
  21087. return $v_result;
  21088. }
  21089. /**
  21090. * @param $p_path
  21091. * @param bool $p_remove_disk_letter
  21092. * @return string
  21093. */
  21094. public function _translateWinPath($p_path, $p_remove_disk_letter = true)
  21095. {
  21096. if (defined('OS_WINDOWS') && OS_WINDOWS) {
  21097. // ----- Look for potential disk letter
  21098. if (($p_remove_disk_letter)
  21099. && (($v_position = strpos($p_path, ':')) != false)
  21100. ) {
  21101. $p_path = substr($p_path, $v_position + 1);
  21102. }
  21103. // ----- Change potential windows directory separator
  21104. if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
  21105. $p_path = strtr($p_path, '\\', '/');
  21106. }
  21107. }
  21108. return $p_path;
  21109. }
  21110. }
  21111. ���������������Archive_Tar-1.4.8/docs/Archive_Tar.txt��������������������������������������������������������������0000644�0000766�0000024�00000045246�13553331435�016626� 0����������������������������������������������������������������������������������������������������ustar �mrook���������������������������staff������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Documentation for class Archive_Tar
  21112. ===================================
  21113. Last update : 2001-08-15
  21114. Overview :
  21115. ----------
  21116. The Archive_Tar class helps in creating and managing GNU TAR format
  21117. files compressed by GNU ZIP or not.
  21118. The class offers basic functions like creating an archive, adding
  21119. files in the archive, extracting files from the archive and listing
  21120. the archive content.
  21121. It also provide advanced functions that allow the adding and
  21122. extraction of files with path manipulation.
  21123. Sample :
  21124. --------
  21125. // ----- Creating the object (uncompressed archive)
  21126. $tar_object = new Archive_Tar("tarname.tar");
  21127. $tar_object->setErrorHandling(PEAR_ERROR_PRINT);
  21128. // ----- Creating the archive
  21129. $v_list[0]="file.txt";
  21130. $v_list[1]="data/";
  21131. $v_list[2]="file.log";
  21132. $tar_object->create($v_list);
  21133. // ----- Adding files
  21134. $v_list[0]="dev/file.txt";
  21135. $v_list[1]="dev/data/";
  21136. $v_list[2]="log/file.log";
  21137. $tar_object->add($v_list);
  21138. // ----- Adding more files
  21139. $tar_object->add("release/newfile.log release/readme.txt");
  21140. // ----- Listing the content
  21141. if (($v_list = $tar_object->listContent()) != 0)
  21142. for ($i=0; $i<sizeof($v_list); $i++)
  21143. {
  21144. echo "Filename :'".$v_list[$i][filename]."'<br>";
  21145. echo " .size :'".$v_list[$i][size]."'<br>";
  21146. echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
  21147. echo " .mode :'".$v_list[$i][mode]."'<br>";
  21148. echo " .uid :'".$v_list[$i][uid]."'<br>";
  21149. echo " .gid :'".$v_list[$i][gid]."'<br>";
  21150. echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
  21151. }
  21152. // ----- Extracting the archive in directory "install"
  21153. $tar_object->extract("install");
  21154. Public arguments :
  21155. ------------------
  21156. None
  21157. Public Methods :
  21158. ----------------
  21159. Method : Archive_Tar($p_tarname, $compress = null)
  21160. Description :
  21161. Archive_Tar Class constructor. This flavour of the constructor only
  21162. declare a new Archive_Tar object, identifying it by the name of the
  21163. tar file.
  21164. If the compress argument is set the tar will be read or created as a
  21165. gzip or bz2 compressed TAR file.
  21166. Arguments :
  21167. $p_tarname : A valid filename for the tar archive file.
  21168. $p_compress : can be null, 'gz' or 'bz2'. For
  21169. compatibility reason it can also be true. This
  21170. parameter indicates if gzip or bz2 compression
  21171. is required.
  21172. Return value :
  21173. The Archive_Tar object.
  21174. Sample :
  21175. $tar_object = new Archive_Tar("tarname.tar");
  21176. $tar_object_compressed = new Archive_Tar("tarname.tgz", true);
  21177. How it works :
  21178. Initialize the object.
  21179. Method : create($p_filelist)
  21180. Description :
  21181. This method creates the archive file and add the files / directories
  21182. that are listed in $p_filelist.
  21183. If the file already exists and is writable, it is replaced by the
  21184. new tar. It is a create and not an add. If the file exists and is
  21185. read-only or is a directory it is not replaced. The method return
  21186. false and a PEAR error text.
  21187. The $p_filelist parameter can be an array of string, each string
  21188. representing a filename or a directory name with their path if
  21189. needed. It can also be a single string with names separated by a
  21190. single blank.
  21191. See also createModify() method for more details.
  21192. Arguments :
  21193. $p_filelist : An array of filenames and directory names, or a single
  21194. string with names separated by a single blank space.
  21195. Return value :
  21196. true on success, false on error.
  21197. Sample 1 :
  21198. $tar_object = new Archive_Tar("tarname.tar");
  21199. $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling
  21200. $v_list[0]="file.txt";
  21201. $v_list[1]="data/"; (Optional '/' at the end)
  21202. $v_list[2]="file.log";
  21203. $tar_object->create($v_list);
  21204. Sample 2 :
  21205. $tar_object = new Archive_Tar("tarname.tar");
  21206. $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling
  21207. $tar_object->create("file.txt data/ file.log");
  21208. How it works :
  21209. Just calling the createModify() method with the right parameters.
  21210. Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "")
  21211. Description :
  21212. This method creates the archive file and add the files / directories
  21213. that are listed in $p_filelist.
  21214. If the file already exists and is writable, it is replaced by the
  21215. new tar. It is a create and not an add. If the file exists and is
  21216. read-only or is a directory it is not replaced. The method return
  21217. false and a PEAR error text.
  21218. The $p_filelist parameter can be an array of string, each string
  21219. representing a filename or a directory name with their path if
  21220. needed. It can also be a single string with names separated by a
  21221. single blank.
  21222. The path indicated in $p_remove_dir will be removed from the
  21223. memorized path of each file / directory listed when this path
  21224. exists. By default nothing is removed (empty path "")
  21225. The path indicated in $p_add_dir will be added at the beginning of
  21226. the memorized path of each file / directory listed. However it can
  21227. be set to empty "". The adding of a path is done after the removing
  21228. of path.
  21229. The path add/remove ability enables the user to prepare an archive
  21230. for extraction in a different path than the origin files are.
  21231. See also addModify() method for file adding properties.
  21232. Arguments :
  21233. $p_filelist : An array of filenames and directory names, or a single
  21234. string with names separated by a single blank space.
  21235. $p_add_dir : A string which contains a path to be added to the
  21236. memorized path of each element in the list.
  21237. $p_remove_dir : A string which contains a path to be removed from
  21238. the memorized path of each element in the list, when
  21239. relevant.
  21240. Return value :
  21241. true on success, false on error.
  21242. Sample 1 :
  21243. $tar_object = new Archive_Tar("tarname.tar");
  21244. $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling
  21245. $v_list[0]="file.txt";
  21246. $v_list[1]="data/"; (Optional '/' at the end)
  21247. $v_list[2]="file.log";
  21248. $tar_object->createModify($v_list, "install");
  21249. // files are stored in the archive as :
  21250. // install/file.txt
  21251. // install/data
  21252. // install/data/file1.txt
  21253. // install/data/... all the files and sub-dirs of data/
  21254. // install/file.log
  21255. Sample 2 :
  21256. $tar_object = new Archive_Tar("tarname.tar");
  21257. $tar_object->setErrorHandling(PEAR_ERROR_PRINT); // Optional error handling
  21258. $v_list[0]="dev/file.txt";
  21259. $v_list[1]="dev/data/"; (Optional '/' at the end)
  21260. $v_list[2]="log/file.log";
  21261. $tar_object->createModify($v_list, "install", "dev");
  21262. // files are stored in the archive as :
  21263. // install/file.txt
  21264. // install/data
  21265. // install/data/file1.txt
  21266. // install/data/... all the files and sub-dirs of data/
  21267. // install/log/file.log
  21268. How it works :
  21269. Open the file in write mode (erasing the existing one if one),
  21270. call the _addList() method for adding the files in an empty archive,
  21271. add the tar footer (512 bytes block), close the tar file.
  21272. Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="")
  21273. Description :
  21274. This method add the files / directories listed in $p_filelist at the
  21275. end of the existing archive. If the archive does not yet exists it
  21276. is created.
  21277. The $p_filelist parameter can be an array of string, each string
  21278. representing a filename or a directory name with their path if
  21279. needed. It can also be a single string with names separated by a
  21280. single blank.
  21281. The path indicated in $p_remove_dir will be removed from the
  21282. memorized path of each file / directory listed when this path
  21283. exists. By default nothing is removed (empty path "")
  21284. The path indicated in $p_add_dir will be added at the beginning of
  21285. the memorized path of each file / directory listed. However it can
  21286. be set to empty "". The adding of a path is done after the removing
  21287. of path.
  21288. The path add/remove ability enables the user to prepare an archive
  21289. for extraction in a different path than the origin files are.
  21290. If a file/dir is already in the archive it will only be added at the
  21291. end of the archive. There is no update of the existing archived
  21292. file/dir. However while extracting the archive, the last file will
  21293. replace the first one. This results in a none optimization of the
  21294. archive size.
  21295. If a file/dir does not exist the file/dir is ignored. However an
  21296. error text is send to PEAR error.
  21297. If a file/dir is not readable the file/dir is ignored. However an
  21298. error text is send to PEAR error.
  21299. If the resulting filename/dirname (after the add/remove option or
  21300. not) string is greater than 99 char, the file/dir is
  21301. ignored. However an error text is send to PEAR error.
  21302. Arguments :
  21303. $p_filelist : An array of filenames and directory names, or a single
  21304. string with names separated by a single blank space.
  21305. $p_add_dir : A string which contains a path to be added to the
  21306. memorized path of each element in the list.
  21307. $p_remove_dir : A string which contains a path to be removed from
  21308. the memorized path of each element in the list, when
  21309. relevant.
  21310. Return value :
  21311. true on success, false on error.
  21312. Sample 1 :
  21313. $tar_object = new Archive_Tar("tarname.tar");
  21314. [...]
  21315. $v_list[0]="dev/file.txt";
  21316. $v_list[1]="dev/data/"; (Optional '/' at the end)
  21317. $v_list[2]="log/file.log";
  21318. $tar_object->addModify($v_list, "install");
  21319. // files are stored in the archive as :
  21320. // install/file.txt
  21321. // install/data
  21322. // install/data/file1.txt
  21323. // install/data/... all the files and sub-dirs of data/
  21324. // install/file.log
  21325. Sample 2 :
  21326. $tar_object = new Archive_Tar("tarname.tar");
  21327. [...]
  21328. $v_list[0]="dev/file.txt";
  21329. $v_list[1]="dev/data/"; (Optional '/' at the end)
  21330. $v_list[2]="log/file.log";
  21331. $tar_object->addModify($v_list, "install", "dev");
  21332. // files are stored in the archive as :
  21333. // install/file.txt
  21334. // install/data
  21335. // install/data/file1.txt
  21336. // install/data/... all the files and sub-dirs of data/
  21337. // install/log/file.log
  21338. How it works :
  21339. If the archive does not exists it create it and add the files.
  21340. If the archive does exists and is not compressed, it open it, jump
  21341. before the last empty 512 bytes block (tar footer) and add the files
  21342. at this point.
  21343. If the archive does exists and is compressed, a temporary copy file
  21344. is created. This temporary file is then 'gzip' read block by block
  21345. until the last empty block. The new files are then added in the
  21346. compressed file.
  21347. The adding of files is done by going through the file/dir list,
  21348. adding files per files, in a recursive way through the
  21349. directory. Each time a path need to be added/removed it is done
  21350. before writing the file header in the archive.
  21351. Method : add($p_filelist)
  21352. Description :
  21353. This method add the files / directories listed in $p_filelist at the
  21354. end of the existing archive. If the archive does not yet exists it
  21355. is created.
  21356. The $p_filelist parameter can be an array of string, each string
  21357. representing a filename or a directory name with their path if
  21358. needed. It can also be a single string with names separated by a
  21359. single blank.
  21360. See addModify() method for details and limitations.
  21361. Arguments :
  21362. $p_filelist : An array of filenames and directory names, or a single
  21363. string with names separated by a single blank space.
  21364. Return value :
  21365. true on success, false on error.
  21366. Sample 1 :
  21367. $tar_object = new Archive_Tar("tarname.tar");
  21368. [...]
  21369. $v_list[0]="dev/file.txt";
  21370. $v_list[1]="dev/data/"; (Optional '/' at the end)
  21371. $v_list[2]="log/file.log";
  21372. $tar_object->add($v_list);
  21373. Sample 2 :
  21374. $tar_object = new Archive_Tar("tarname.tgz", true);
  21375. [...]
  21376. $v_list[0]="dev/file.txt";
  21377. $v_list[1]="dev/data/"; (Optional '/' at the end)
  21378. $v_list[2]="log/file.log";
  21379. $tar_object->add($v_list);
  21380. How it works :
  21381. Simply call the addModify() method with the right parameters.
  21382. Method : addString($p_filename, $p_string, $p_datetime, $p_params)
  21383. Description :
  21384. This method add a single string as a file at the
  21385. end of the existing archive. If the archive does not yet exists it
  21386. is created.
  21387. Arguments :
  21388. $p_filename : A string which contains the full filename path
  21389. that will be associated with the string.
  21390. $p_string : The content of the file added in the archive.
  21391. $p_datetime : (Optional) Timestamp of the file (default = now)
  21392. $p_params : (Optional) Various file metadata:
  21393. stamp - As above, timestamp of the file
  21394. mode - UNIX-style permissions (default 0600)
  21395. type - Is this a regular file or link (see TAR
  21396. format spec for how to create a hard/symlink)
  21397. uid - UNIX-style user ID (default 0 = root)
  21398. gid - UNIX-style group ID (default 0 = root)
  21399. Return value :
  21400. true on success, false on error.
  21401. Sample 1 :
  21402. $v_archive = & new Archive_Tar($p_filename);
  21403. $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  21404. $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string');
  21405. $v_result = $v_archive->addString(
  21406. 'data/test.sh',
  21407. "#!/bin/sh\necho 'Hello'",
  21408. time(),
  21409. array( "mode" => 0755, "uid" => 34 )
  21410. );
  21411. Method : extract($p_path = "")
  21412. Description :
  21413. This method extract all the content of the archive in the directory
  21414. indicated by $p_path.If $p_path is optional, if not set the archive
  21415. is extracted in the current directory.
  21416. While extracting a file, if the directory path does not exists it is
  21417. created.
  21418. See extractModify() for details and limitations.
  21419. Arguments :
  21420. $p_path : Optional path where the files/dir need to by extracted.
  21421. Return value :
  21422. true on success, false on error.
  21423. Sample :
  21424. $tar_object = new Archive_Tar("tarname.tar");
  21425. $tar_object->extract();
  21426. How it works :
  21427. Simply call the extractModify() method with appropriate parameters.
  21428. Method : extractModify($p_path, $p_remove_path)
  21429. Description :
  21430. This method extract all the content of the archive in the directory
  21431. indicated by $p_path. When relevant the memorized path of the
  21432. files/dir can be modified by removing the $p_remove_path path at the
  21433. beginning of the file/dir path.
  21434. While extracting a file, if the directory path does not exists it is
  21435. created.
  21436. While extracting a file, if the file already exists it is replaced
  21437. without looking for last modification date.
  21438. While extracting a file, if the file already exists and is write
  21439. protected, the extraction is aborted.
  21440. While extracting a file, if a directory with the same name already
  21441. exists, the extraction is aborted.
  21442. While extracting a directory, if a file with the same name already
  21443. exists, the extraction is aborted.
  21444. While extracting a file/directory if the destination directory exist
  21445. and is write protected, or does not exist but can not be created,
  21446. the extraction is aborted.
  21447. If after extraction an extracted file does not show the correct
  21448. stored file size, the extraction is aborted.
  21449. When the extraction is aborted, a PEAR error text is set and false
  21450. is returned. However the result can be a partial extraction that may
  21451. need to be manually cleaned.
  21452. Arguments :
  21453. $p_path : The path of the directory where the files/dir need to by
  21454. extracted.
  21455. $p_remove_path : Part of the memorized path that can be removed if
  21456. present at the beginning of the file/dir path.
  21457. Return value :
  21458. true on success, false on error.
  21459. Sample :
  21460. // Imagine tarname.tar with files :
  21461. // dev/data/file.txt
  21462. // dev/data/log.txt
  21463. // readme.txt
  21464. $tar_object = new Archive_Tar("tarname.tar");
  21465. $tar_object->extractModify("install", "dev");
  21466. // Files will be extracted there :
  21467. // install/data/file.txt
  21468. // install/data/log.txt
  21469. // install/readme.txt
  21470. How it works :
  21471. Open the archive and call a more generic function that can extract
  21472. only a part of the archive or all the archive.
  21473. See extractList() method for more details.
  21474. Method : extractInString($p_filename)
  21475. Description :
  21476. This method extract from the archive one file identified by $p_filename.
  21477. The return value is a string with the file content, or NULL on error.
  21478. Arguments :
  21479. $p_filename : The path of the file to extract in a string.
  21480. Return value :
  21481. a string with the file content or NULL.
  21482. Sample :
  21483. // Imagine tarname.tar with files :
  21484. // dev/data/file.txt
  21485. // dev/data/log.txt
  21486. // dev/readme.txt
  21487. $v_archive = & new Archive_Tar('tarname.tar');
  21488. $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  21489. $v_string = $v_archive->extractInString('dev/readme.txt');
  21490. echo $v_string;
  21491. Method : listContent()
  21492. Description :
  21493. This method returns an array of arrays that describe each
  21494. file/directory present in the archive.
  21495. The array is not sorted, so it show the position of the file in the
  21496. archive.
  21497. The file informations are :
  21498. $file[filename] : Name and path of the file/dir.
  21499. $file[mode] : File permissions (result of fileperms())
  21500. $file[uid] : user id
  21501. $file[gid] : group id
  21502. $file[size] : filesize
  21503. $file[mtime] : Last modification time (result of filemtime())
  21504. $file[typeflag] : "" for file, "5" for directory
  21505. Arguments :
  21506. Return value :
  21507. An array of arrays or 0 on error.
  21508. Sample :
  21509. $tar_object = new Archive_Tar("tarname.tar");
  21510. if (($v_list = $tar_object->listContent()) != 0)
  21511. for ($i=0; $i<sizeof($v_list); $i++)
  21512. {
  21513. echo "Filename :'".$v_list[$i][filename]."'<br>";
  21514. echo " .size :'".$v_list[$i][size]."'<br>";
  21515. echo " .mtime :'".$v_list[$i][mtime]."' (".
  21516. date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
  21517. echo " .mode :'".$v_list[$i][mode]."'<br>";
  21518. echo " .uid :'".$v_list[$i][uid]."'<br>";
  21519. echo " .gid :'".$v_list[$i][gid]."'<br>";
  21520. echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
  21521. }
  21522. How it works :
  21523. Call the same function as an extract however with a flag to only go
  21524. through the archive without extracting the files.
  21525. Method : extractList($p_filelist, $p_path = "", $p_remove_path = "")
  21526. Description :
  21527. This method extract from the archive only the files indicated in the
  21528. $p_filelist. These files are extracted in the current directory or
  21529. in the directory indicated by the optional $p_path parameter.
  21530. If indicated the $p_remove_path can be used in the same way as it is
  21531. used in extractModify() method.
  21532. Arguments :
  21533. $p_filelist : An array of filenames and directory names, or a single
  21534. string with names separated by a single blank space.
  21535. $p_path : The path of the directory where the files/dir need to by
  21536. extracted.
  21537. $p_remove_path : Part of the memorized path that can be removed if
  21538. present at the beginning of the file/dir path.
  21539. Return value :
  21540. true on success, false on error.
  21541. Sample :
  21542. // Imagine tarname.tar with files :
  21543. // dev/data/file.txt
  21544. // dev/data/log.txt
  21545. // readme.txt
  21546. $tar_object = new Archive_Tar("tarname.tar");
  21547. $tar_object->extractList("dev/data/file.txt readme.txt", "install",
  21548. "dev");
  21549. // Files will be extracted there :
  21550. // install/data/file.txt
  21551. // install/readme.txt
  21552. How it works :
  21553. Go through the archive and extract only the files present in the
  21554. list.
  21555. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������package.xml�����������������������������������������������������������������������������������������0000644�0001750�0001750�00000016655�13565302573�013071� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?>
  21556. <package packagerversion="1.10.10" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  21557. <name>Console_Getopt</name>
  21558. <channel>pear.php.net</channel>
  21559. <summary>Command-line option parser</summary>
  21560. <description>This is a PHP implementation of &quot;getopt&quot; supporting both
  21561. short and long options.</description>
  21562. <lead>
  21563. <name>Andrei Zmievski</name>
  21564. <user>andrei</user>
  21565. <email>andrei@php.net</email>
  21566. <active>no</active>
  21567. </lead>
  21568. <developer>
  21569. <name>Stig Bakken</name>
  21570. <user>ssb</user>
  21571. <email>stig@php.net</email>
  21572. <active>no</active>
  21573. </developer>
  21574. <helper>
  21575. <name>Greg Beaver</name>
  21576. <user>cellog</user>
  21577. <email>cellog@php.net</email>
  21578. <active>no</active>
  21579. </helper>
  21580. <date>2019-11-20</date>
  21581. <time>18:27:07</time>
  21582. <version>
  21583. <release>1.4.3</release>
  21584. <api>1.4.0</api>
  21585. </version>
  21586. <stability>
  21587. <release>stable</release>
  21588. <api>stable</api>
  21589. </stability>
  21590. <license uri="http://opensource.org/licenses/bsd-license.php">BSD-2-Clause</license>
  21591. <notes>
  21592. * PR #4: Fix PHP 7.4 deprecation: array/string curly braces access
  21593. * PR #5: fix phplint warnings
  21594. </notes>
  21595. <contents>
  21596. <dir name="/">
  21597. <file md5sum="63da5909aa85a0eb76e0ad0b5e00811a" name="Console/Getopt.php" role="php" />
  21598. <file md5sum="5a6fa63ce6f2370cdad11dc24a5addd0" name="tests/001-getopt.phpt" role="test" />
  21599. <file md5sum="7540b630cb8e7bfd8bb06fb65a010ae9" name="tests/bug10557.phpt" role="test" />
  21600. <file md5sum="e469de3628de85779118103b3248a44f" name="tests/bug11068.phpt" role="test" />
  21601. <file md5sum="cdc108b084ad8e82eeb2417f04b49ec8" name="tests/bug13140.phpt" role="test" />
  21602. </dir>
  21603. </contents>
  21604. <compatible>
  21605. <name>PEAR</name>
  21606. <channel>pear.php.net</channel>
  21607. <min>1.4.0</min>
  21608. <max>1.999.999</max>
  21609. </compatible>
  21610. <dependencies>
  21611. <required>
  21612. <php>
  21613. <min>5.4.0</min>
  21614. </php>
  21615. <pearinstaller>
  21616. <min>1.8.0</min>
  21617. </pearinstaller>
  21618. </required>
  21619. </dependencies>
  21620. <phprelease />
  21621. <changelog>
  21622. <release>
  21623. <date>2019-11-20</date>
  21624. <version>
  21625. <release>1.4.3</release>
  21626. <api>1.4.0</api>
  21627. </version>
  21628. <stability>
  21629. <release>stable</release>
  21630. <api>stable</api>
  21631. </stability>
  21632. <license uri="http://opensource.org/licenses/bsd-license.php">BSD-2-Clause</license>
  21633. <notes>
  21634. * PR #4: Fix PHP 7.4 deprecation: array/string curly braces access
  21635. * PR #5: fix phplint warnings
  21636. </notes>
  21637. </release>
  21638. <release>
  21639. <date>2019-02-06</date>
  21640. <version>
  21641. <release>1.4.2</release>
  21642. <api>1.4.0</api>
  21643. </version>
  21644. <stability>
  21645. <release>stable</release>
  21646. <api>stable</api>
  21647. </stability>
  21648. <license uri="http://opensource.org/licenses/bsd-license.php">BSD-2-Clause</license>
  21649. <notes>
  21650. * Remove use of each(), which is removed in PHP 8
  21651. </notes>
  21652. </release>
  21653. <release>
  21654. <date>2015-07-20</date>
  21655. <version>
  21656. <release>1.4.1</release>
  21657. <api>1.4.0</api>
  21658. </version>
  21659. <stability>
  21660. <release>stable</release>
  21661. <api>stable</api>
  21662. </stability>
  21663. <license uri="http://opensource.org/licenses/bsd-license.php">BSD-2-Clause</license>
  21664. <notes>
  21665. * Fix unit test on PHP 7 [cweiske]
  21666. </notes>
  21667. </release>
  21668. <release>
  21669. <date>2015-02-22</date>
  21670. <version>
  21671. <release>1.4.0</release>
  21672. <api>1.4.0</api>
  21673. </version>
  21674. <stability>
  21675. <release>stable</release>
  21676. <api>stable</api>
  21677. </stability>
  21678. <license uri="http://opensource.org/licenses/bsd-license.php">BSD-2-Clause</license>
  21679. <notes>
  21680. * Change license to BSD-2-Clause
  21681. * Set minimum PHP version to 5.4.0
  21682. * Mark static methods with &quot;static&quot; keyword
  21683. </notes>
  21684. </release>
  21685. <release>
  21686. <date>2011-03-07</date>
  21687. <version>
  21688. <release>1.3.1</release>
  21689. <api>1.3.0</api>
  21690. </version>
  21691. <stability>
  21692. <release>stable</release>
  21693. <api>stable</api>
  21694. </stability>
  21695. <license uri="http://www.php.net/license">PHP License</license>
  21696. <notes>
  21697. * Change the minimum PEAR installer dep to be lower
  21698. </notes>
  21699. </release>
  21700. <release>
  21701. <date>2010-12-11</date>
  21702. <time>20:20:13</time>
  21703. <version>
  21704. <release>1.3.0</release>
  21705. <api>1.3.0</api>
  21706. </version>
  21707. <stability>
  21708. <release>stable</release>
  21709. <api>stable</api>
  21710. </stability>
  21711. <license uri="http://www.php.net/license">PHP License</license>
  21712. <notes>
  21713. * Implement Request #13140: [PATCH] to skip unknown parameters. [patch by rquadling, improved on by dufuz]
  21714. </notes>
  21715. </release>
  21716. <release>
  21717. <date>2007-06-12</date>
  21718. <version>
  21719. <release>1.2.3</release>
  21720. <api>1.2.1</api>
  21721. </version>
  21722. <stability>
  21723. <release>stable</release>
  21724. <api>stable</api>
  21725. </stability>
  21726. <license uri="http://www.php.net/license">PHP License</license>
  21727. <notes>
  21728. * fix Bug #11068: No way to read plain &quot;-&quot; option [cardoe]
  21729. </notes>
  21730. </release>
  21731. <release>
  21732. <version>
  21733. <release>1.2.2</release>
  21734. <api>1.2.1</api>
  21735. </version>
  21736. <stability>
  21737. <release>stable</release>
  21738. <api>stable</api>
  21739. </stability>
  21740. <date>2007-02-17</date>
  21741. <license uri="http://www.php.net/license">PHP License</license>
  21742. <notes>
  21743. * fix Bug #4475: An ambiguous error occurred when specifying similar longoption name.
  21744. * fix Bug #10055: Not failing properly on short options missing required values
  21745. </notes>
  21746. </release>
  21747. <release>
  21748. <version>
  21749. <release>1.2.1</release>
  21750. <api>1.2.1</api>
  21751. </version>
  21752. <stability>
  21753. <release>stable</release>
  21754. <api>stable</api>
  21755. </stability>
  21756. <date>2006-12-08</date>
  21757. <license uri="http://www.php.net/license">PHP License</license>
  21758. <notes>
  21759. Fixed bugs #4448 (Long parameter values truncated with longoption parameter) and #7444 (Trailing spaces after php closing tag)
  21760. </notes>
  21761. </release>
  21762. <release>
  21763. <version>
  21764. <release>1.2</release>
  21765. <api>1.2</api>
  21766. </version>
  21767. <stability>
  21768. <release>stable</release>
  21769. <api>stable</api>
  21770. </stability>
  21771. <date>2003-12-11</date>
  21772. <license uri="http://www.php.net/license">PHP License</license>
  21773. <notes>
  21774. Fix to preserve BC with 1.0 and allow correct behaviour for new users
  21775. </notes>
  21776. </release>
  21777. <release>
  21778. <version>
  21779. <release>1.0</release>
  21780. <api>1.0</api>
  21781. </version>
  21782. <stability>
  21783. <release>stable</release>
  21784. <api>stable</api>
  21785. </stability>
  21786. <date>2002-09-13</date>
  21787. <license uri="http://www.php.net/license">PHP License</license>
  21788. <notes>
  21789. Stable release
  21790. </notes>
  21791. </release>
  21792. <release>
  21793. <version>
  21794. <release>0.11</release>
  21795. <api>0.11</api>
  21796. </version>
  21797. <stability>
  21798. <release>beta</release>
  21799. <api>beta</api>
  21800. </stability>
  21801. <date>2002-05-26</date>
  21802. <license uri="http://www.php.net/license">PHP License</license>
  21803. <notes>
  21804. POSIX getopt compatibility fix: treat first element of args
  21805. array as command name
  21806. </notes>
  21807. </release>
  21808. <release>
  21809. <version>
  21810. <release>0.10</release>
  21811. <api>0.10</api>
  21812. </version>
  21813. <stability>
  21814. <release>beta</release>
  21815. <api>beta</api>
  21816. </stability>
  21817. <date>2002-05-12</date>
  21818. <license uri="http://www.php.net/license">PHP License</license>
  21819. <notes>
  21820. Packaging fix
  21821. </notes>
  21822. </release>
  21823. <release>
  21824. <version>
  21825. <release>0.9</release>
  21826. <api>0.9</api>
  21827. </version>
  21828. <stability>
  21829. <release>beta</release>
  21830. <api>beta</api>
  21831. </stability>
  21832. <date>2002-05-12</date>
  21833. <license uri="http://www.php.net/license">PHP License</license>
  21834. <notes>
  21835. Initial release
  21836. </notes>
  21837. </release>
  21838. </changelog>
  21839. </package>
  21840. �����������������������������������������������������������������������������������Console_Getopt-1.4.3/Console/Getopt.php�������������������������������������������������������������0000644�0001750�0001750�00000032503�13565302573�017704� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  21841. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  21842. /**
  21843. * PHP Version 5
  21844. *
  21845. * Copyright (c) 2001-2015, The PEAR developers
  21846. *
  21847. * This source file is subject to the BSD-2-Clause license,
  21848. * that is bundled with this package in the file LICENSE, and is
  21849. * available through the world-wide-web at the following url:
  21850. * http://opensource.org/licenses/bsd-license.php.
  21851. *
  21852. * @category Console
  21853. * @package Console_Getopt
  21854. * @author Andrei Zmievski <andrei@php.net>
  21855. * @license http://opensource.org/licenses/bsd-license.php BSD-2-Clause
  21856. * @version CVS: $Id$
  21857. * @link http://pear.php.net/package/Console_Getopt
  21858. */
  21859. require_once 'PEAR.php';
  21860. /**
  21861. * Command-line options parsing class.
  21862. *
  21863. * @category Console
  21864. * @package Console_Getopt
  21865. * @author Andrei Zmievski <andrei@php.net>
  21866. * @license http://opensource.org/licenses/bsd-license.php BSD-2-Clause
  21867. * @link http://pear.php.net/package/Console_Getopt
  21868. */
  21869. class Console_Getopt
  21870. {
  21871. /**
  21872. * Parses the command-line options.
  21873. *
  21874. * The first parameter to this function should be the list of command-line
  21875. * arguments without the leading reference to the running program.
  21876. *
  21877. * The second parameter is a string of allowed short options. Each of the
  21878. * option letters can be followed by a colon ':' to specify that the option
  21879. * requires an argument, or a double colon '::' to specify that the option
  21880. * takes an optional argument.
  21881. *
  21882. * The third argument is an optional array of allowed long options. The
  21883. * leading '--' should not be included in the option name. Options that
  21884. * require an argument should be followed by '=', and options that take an
  21885. * option argument should be followed by '=='.
  21886. *
  21887. * The return value is an array of two elements: the list of parsed
  21888. * options and the list of non-option command-line arguments. Each entry in
  21889. * the list of parsed options is a pair of elements - the first one
  21890. * specifies the option, and the second one specifies the option argument,
  21891. * if there was one.
  21892. *
  21893. * Long and short options can be mixed.
  21894. *
  21895. * Most of the semantics of this function are based on GNU getopt_long().
  21896. *
  21897. * @param array $args an array of command-line arguments
  21898. * @param string $short_options specifies the list of allowed short options
  21899. * @param array $long_options specifies the list of allowed long options
  21900. * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
  21901. *
  21902. * @return array two-element array containing the list of parsed options and
  21903. * the non-option arguments
  21904. */
  21905. public static function getopt2($args, $short_options, $long_options = null, $skip_unknown = false)
  21906. {
  21907. return Console_Getopt::doGetopt(2, $args, $short_options, $long_options, $skip_unknown);
  21908. }
  21909. /**
  21910. * This function expects $args to start with the script name (POSIX-style).
  21911. * Preserved for backwards compatibility.
  21912. *
  21913. * @param array $args an array of command-line arguments
  21914. * @param string $short_options specifies the list of allowed short options
  21915. * @param array $long_options specifies the list of allowed long options
  21916. *
  21917. * @see getopt2()
  21918. * @return array two-element array containing the list of parsed options and
  21919. * the non-option arguments
  21920. */
  21921. public static function getopt($args, $short_options, $long_options = null, $skip_unknown = false)
  21922. {
  21923. return Console_Getopt::doGetopt(1, $args, $short_options, $long_options, $skip_unknown);
  21924. }
  21925. /**
  21926. * The actual implementation of the argument parsing code.
  21927. *
  21928. * @param int $version Version to use
  21929. * @param array $args an array of command-line arguments
  21930. * @param string $short_options specifies the list of allowed short options
  21931. * @param array $long_options specifies the list of allowed long options
  21932. * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
  21933. *
  21934. * @return array
  21935. */
  21936. public static function doGetopt($version, $args, $short_options, $long_options = null, $skip_unknown = false)
  21937. {
  21938. // in case you pass directly readPHPArgv() as the first arg
  21939. if (PEAR::isError($args)) {
  21940. return $args;
  21941. }
  21942. if (empty($args)) {
  21943. return array(array(), array());
  21944. }
  21945. $non_opts = $opts = array();
  21946. settype($args, 'array');
  21947. if ($long_options) {
  21948. sort($long_options);
  21949. }
  21950. /*
  21951. * Preserve backwards compatibility with callers that relied on
  21952. * erroneous POSIX fix.
  21953. */
  21954. if ($version < 2) {
  21955. if (isset($args[0][0]) && $args[0][0] != '-') {
  21956. array_shift($args);
  21957. }
  21958. }
  21959. for ($i = 0; $i < count($args); $i++) {
  21960. $arg = $args[$i];
  21961. /* The special element '--' means explicit end of
  21962. options. Treat the rest of the arguments as non-options
  21963. and end the loop. */
  21964. if ($arg == '--') {
  21965. $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  21966. break;
  21967. }
  21968. if ($arg[0] != '-' || (strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) {
  21969. $non_opts = array_merge($non_opts, array_slice($args, $i));
  21970. break;
  21971. } elseif (strlen($arg) > 1 && $arg[1] == '-') {
  21972. $error = Console_Getopt::_parseLongOption(substr($arg, 2),
  21973. $long_options,
  21974. $opts,
  21975. $i,
  21976. $args,
  21977. $skip_unknown);
  21978. if (PEAR::isError($error)) {
  21979. return $error;
  21980. }
  21981. } elseif ($arg == '-') {
  21982. // - is stdin
  21983. $non_opts = array_merge($non_opts, array_slice($args, $i));
  21984. break;
  21985. } else {
  21986. $error = Console_Getopt::_parseShortOption(substr($arg, 1),
  21987. $short_options,
  21988. $opts,
  21989. $i,
  21990. $args,
  21991. $skip_unknown);
  21992. if (PEAR::isError($error)) {
  21993. return $error;
  21994. }
  21995. }
  21996. }
  21997. return array($opts, $non_opts);
  21998. }
  21999. /**
  22000. * Parse short option
  22001. *
  22002. * @param string $arg Argument
  22003. * @param string[] $short_options Available short options
  22004. * @param string[][] &$opts
  22005. * @param int &$argIdx
  22006. * @param string[] $args
  22007. * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
  22008. *
  22009. * @return void
  22010. */
  22011. protected static function _parseShortOption($arg, $short_options, &$opts, &$argIdx, $args, $skip_unknown)
  22012. {
  22013. for ($i = 0; $i < strlen($arg); $i++) {
  22014. $opt = $arg[$i];
  22015. $opt_arg = null;
  22016. /* Try to find the short option in the specifier string. */
  22017. if (($spec = strstr($short_options, $opt)) === false || $arg[$i] == ':') {
  22018. if ($skip_unknown === true) {
  22019. break;
  22020. }
  22021. $msg = "Console_Getopt: unrecognized option -- $opt";
  22022. return PEAR::raiseError($msg);
  22023. }
  22024. if (strlen($spec) > 1 && $spec[1] == ':') {
  22025. if (strlen($spec) > 2 && $spec[2] == ':') {
  22026. if ($i + 1 < strlen($arg)) {
  22027. /* Option takes an optional argument. Use the remainder of
  22028. the arg string if there is anything left. */
  22029. $opts[] = array($opt, substr($arg, $i + 1));
  22030. break;
  22031. }
  22032. } else {
  22033. /* Option requires an argument. Use the remainder of the arg
  22034. string if there is anything left. */
  22035. if ($i + 1 < strlen($arg)) {
  22036. $opts[] = array($opt, substr($arg, $i + 1));
  22037. break;
  22038. } else if (isset($args[++$argIdx])) {
  22039. $opt_arg = $args[$argIdx];
  22040. /* Else use the next argument. */;
  22041. if (Console_Getopt::_isShortOpt($opt_arg)
  22042. || Console_Getopt::_isLongOpt($opt_arg)) {
  22043. $msg = "option requires an argument --$opt";
  22044. return PEAR::raiseError("Console_Getopt: " . $msg);
  22045. }
  22046. } else {
  22047. $msg = "option requires an argument --$opt";
  22048. return PEAR::raiseError("Console_Getopt: " . $msg);
  22049. }
  22050. }
  22051. }
  22052. $opts[] = array($opt, $opt_arg);
  22053. }
  22054. }
  22055. /**
  22056. * Checks if an argument is a short option
  22057. *
  22058. * @param string $arg Argument to check
  22059. *
  22060. * @return bool
  22061. */
  22062. protected static function _isShortOpt($arg)
  22063. {
  22064. return strlen($arg) == 2 && $arg[0] == '-'
  22065. && preg_match('/[a-zA-Z]/', $arg[1]);
  22066. }
  22067. /**
  22068. * Checks if an argument is a long option
  22069. *
  22070. * @param string $arg Argument to check
  22071. *
  22072. * @return bool
  22073. */
  22074. protected static function _isLongOpt($arg)
  22075. {
  22076. return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
  22077. preg_match('/[a-zA-Z]+$/', substr($arg, 2));
  22078. }
  22079. /**
  22080. * Parse long option
  22081. *
  22082. * @param string $arg Argument
  22083. * @param string[] $long_options Available long options
  22084. * @param string[][] &$opts
  22085. * @param int &$argIdx
  22086. * @param string[] $args
  22087. *
  22088. * @return void|PEAR_Error
  22089. */
  22090. protected static function _parseLongOption($arg, $long_options, &$opts, &$argIdx, $args, $skip_unknown)
  22091. {
  22092. @list($opt, $opt_arg) = explode('=', $arg, 2);
  22093. $opt_len = strlen($opt);
  22094. for ($i = 0; $i < count($long_options); $i++) {
  22095. $long_opt = $long_options[$i];
  22096. $opt_start = substr($long_opt, 0, $opt_len);
  22097. $long_opt_name = str_replace('=', '', $long_opt);
  22098. /* Option doesn't match. Go on to the next one. */
  22099. if ($long_opt_name != $opt) {
  22100. continue;
  22101. }
  22102. $opt_rest = substr($long_opt, $opt_len);
  22103. /* Check that the options uniquely matches one of the allowed
  22104. options. */
  22105. if ($i + 1 < count($long_options)) {
  22106. $next_option_rest = substr($long_options[$i + 1], $opt_len);
  22107. } else {
  22108. $next_option_rest = '';
  22109. }
  22110. if ($opt_rest != '' && $opt[0] != '=' &&
  22111. $i + 1 < count($long_options) &&
  22112. $opt == substr($long_options[$i+1], 0, $opt_len) &&
  22113. $next_option_rest != '' &&
  22114. $next_option_rest[0] != '=') {
  22115. $msg = "Console_Getopt: option --$opt is ambiguous";
  22116. return PEAR::raiseError($msg);
  22117. }
  22118. if (substr($long_opt, -1) == '=') {
  22119. if (substr($long_opt, -2) != '==') {
  22120. /* Long option requires an argument.
  22121. Take the next argument if one wasn't specified. */;
  22122. if (!strlen($opt_arg)) {
  22123. if (!isset($args[++$argIdx])) {
  22124. $msg = "Console_Getopt: option requires an argument --$opt";
  22125. return PEAR::raiseError($msg);
  22126. }
  22127. $opt_arg = $args[$argIdx];
  22128. }
  22129. if (Console_Getopt::_isShortOpt($opt_arg)
  22130. || Console_Getopt::_isLongOpt($opt_arg)) {
  22131. $msg = "Console_Getopt: option requires an argument --$opt";
  22132. return PEAR::raiseError($msg);
  22133. }
  22134. }
  22135. } else if ($opt_arg) {
  22136. $msg = "Console_Getopt: option --$opt doesn't allow an argument";
  22137. return PEAR::raiseError($msg);
  22138. }
  22139. $opts[] = array('--' . $opt, $opt_arg);
  22140. return;
  22141. }
  22142. if ($skip_unknown === true) {
  22143. return;
  22144. }
  22145. return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  22146. }
  22147. /**
  22148. * Safely read the $argv PHP array across different PHP configurations.
  22149. * Will take care on register_globals and register_argc_argv ini directives
  22150. *
  22151. * @return mixed the $argv PHP array or PEAR error if not registered
  22152. */
  22153. public static function readPHPArgv()
  22154. {
  22155. global $argv;
  22156. if (!is_array($argv)) {
  22157. if (!@is_array($_SERVER['argv'])) {
  22158. if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  22159. $msg = "Could not read cmd args (register_argc_argv=Off?)";
  22160. return PEAR::raiseError("Console_Getopt: " . $msg);
  22161. }
  22162. return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  22163. }
  22164. return $_SERVER['argv'];
  22165. }
  22166. return $argv;
  22167. }
  22168. }
  22169. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Console_Getopt-1.4.3/tests/001-getopt.phpt����������������������������������������������������������0000644�0001750�0001750�00000002316�13565302573�020165� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--TEST--
  22170. Console_Getopt
  22171. --FILE--
  22172. <?php
  22173. require_once 'Console/Getopt.php';
  22174. PEAR::setErrorHandling(PEAR_ERROR_PRINT, "%s\n\n");
  22175. function test($argstr, $optstr) {
  22176. $argv = preg_split('/[[:space:]]+/', $argstr);
  22177. if (PEAR::isError($options = Console_Getopt::getopt($argv, $optstr))) {
  22178. return;
  22179. }
  22180. $opts = $options[0];
  22181. $non_opts = $options[1];
  22182. $i = 0;
  22183. print "options: ";
  22184. foreach ($opts as $o => $d) {
  22185. if ($i++ > 0) {
  22186. print ", ";
  22187. }
  22188. print $d[0] . '=' . $d[1];
  22189. }
  22190. print "\n";
  22191. print "params: " . implode(", ", $non_opts) . "\n";
  22192. print "\n";
  22193. }
  22194. test("-abc", "abc");
  22195. test("-abc foo", "abc");
  22196. test("-abc foo", "abc:");
  22197. test("-abc foo bar gazonk", "abc");
  22198. test("-abc foo bar gazonk", "abc:");
  22199. test("-a -b -c", "abc");
  22200. test("-a -b -c", "abc:");
  22201. test("-abc", "ab:c");
  22202. test("-abc foo -bar gazonk", "abc");
  22203. ?>
  22204. --EXPECT--
  22205. options: a=, b=, c=
  22206. params:
  22207. options: a=, b=, c=
  22208. params: foo
  22209. options: a=, b=, c=foo
  22210. params:
  22211. options: a=, b=, c=
  22212. params: foo, bar, gazonk
  22213. options: a=, b=, c=foo
  22214. params: bar, gazonk
  22215. options: a=, b=, c=
  22216. params:
  22217. Console_Getopt: option requires an argument --c
  22218. options: a=, b=c
  22219. params:
  22220. options: a=, b=, c=
  22221. params: foo, -bar, gazonk
  22222. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Console_Getopt-1.4.3/tests/bug10557.phpt������������������������������������������������������������0000644�0001750�0001750�00000000756�13565302573�017552� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--TEST--
  22223. Console_Getopt [bug 10557]
  22224. --SKIPIF--
  22225. --FILE--
  22226. <?php
  22227. $_SERVER['argv'] =
  22228. $argv = array('hi', '-fjjohnston@mail.com', '--to', '--mailpack', '--debug');
  22229. require_once 'Console/Getopt.php';
  22230. $ret = Console_Getopt::getopt(Console_Getopt::readPHPArgv(), 'f:t:',
  22231. array('from=','to=','mailpack=','direction=','verbose','debug'));
  22232. if(PEAR::isError($ret))
  22233. {
  22234. echo $ret->getMessage()."\n";
  22235. echo 'FATAL';
  22236. exit;
  22237. }
  22238. print_r($ret);
  22239. ?>
  22240. --EXPECT--
  22241. Console_Getopt: option requires an argument --to
  22242. FATAL������������������Console_Getopt-1.4.3/tests/bug11068.phpt������������������������������������������������������������0000644�0001750�0001750�00000001431�13565302573�017537� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--TEST--
  22243. Console_Getopt [bug 11068]
  22244. --SKIPIF--
  22245. --FILE--
  22246. <?php
  22247. $_SERVER['argv'] =
  22248. $argv = array('hi', '-fjjohnston@mail.com', '--to', 'hi', '-');
  22249. require_once 'Console/Getopt.php';
  22250. $ret = Console_Getopt::getopt(Console_Getopt::readPHPArgv(), 'f:t:',
  22251. array('from=','to=','mailpack=','direction=','verbose','debug'));
  22252. if(PEAR::isError($ret))
  22253. {
  22254. echo $ret->getMessage()."\n";
  22255. echo 'FATAL';
  22256. exit;
  22257. }
  22258. print_r($ret);
  22259. ?>
  22260. --EXPECT--
  22261. Array
  22262. (
  22263. [0] => Array
  22264. (
  22265. [0] => Array
  22266. (
  22267. [0] => f
  22268. [1] => jjohnston@mail.com
  22269. )
  22270. [1] => Array
  22271. (
  22272. [0] => --to
  22273. [1] => hi
  22274. )
  22275. )
  22276. [1] => Array
  22277. (
  22278. [0] => -
  22279. )
  22280. )���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Console_Getopt-1.4.3/tests/bug13140.phpt������������������������������������������������������������0000644�0001750�0001750�00000002505�13565302573�017533� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--TEST--
  22281. Console_Getopt [bug 13140]
  22282. --SKIPIF--
  22283. --FILE--
  22284. <?php
  22285. $_SERVER['argv'] = $argv =
  22286. array('--bob', '--foo' , '-bar', '--test', '-rq', 'thisshouldbehere');
  22287. require_once 'Console/Getopt.php';
  22288. $cg = new Console_GetOpt();
  22289. print_r($cg->getopt2($cg->readPHPArgv(), 't', array('test'), true));
  22290. print_r($cg->getopt2($cg->readPHPArgv(), 'bar', array('foo'), true));
  22291. ?>
  22292. --EXPECT--
  22293. Array
  22294. (
  22295. [0] => Array
  22296. (
  22297. [0] => Array
  22298. (
  22299. [0] => --test
  22300. [1] =>
  22301. )
  22302. )
  22303. [1] => Array
  22304. (
  22305. [0] => thisshouldbehere
  22306. )
  22307. )
  22308. Array
  22309. (
  22310. [0] => Array
  22311. (
  22312. [0] => Array
  22313. (
  22314. [0] => --foo
  22315. [1] =>
  22316. )
  22317. [1] => Array
  22318. (
  22319. [0] => b
  22320. [1] =>
  22321. )
  22322. [2] => Array
  22323. (
  22324. [0] => a
  22325. [1] =>
  22326. )
  22327. [3] => Array
  22328. (
  22329. [0] => r
  22330. [1] =>
  22331. )
  22332. [4] => Array
  22333. (
  22334. [0] => r
  22335. [1] =>
  22336. )
  22337. )
  22338. [1] => Array
  22339. (
  22340. [0] => thisshouldbehere
  22341. )
  22342. )
  22343. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������package.sig�����������������������������������������������������������������������������������������0000644�0001750�0001750�00000000243�13565302626�013034� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN PGP SIGNATURE-----
  22344. iEYEABECAAYFAl3VhZYACgkQcqMhusJF8XWkbwCeJw8BhTgPII9JdBbLToOrPgEz
  22345. 2jUAoMVHVsygadk15z7oTUbdXMGxTKb7
  22346. =XENS
  22347. -----END PGP SIGNATURE-----
  22348. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������package.xml�����������������������������������������������������������������������������������������0000644�0001750�0001750�00000163736�13565304531�013070� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?>
  22349. <package packagerversion="1.10.10" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  22350. <name>PEAR</name>
  22351. <channel>pear.php.net</channel>
  22352. <summary>PEAR Base System</summary>
  22353. <description>The PEAR package contains:
  22354. * the PEAR installer, for creating, distributing
  22355. and installing packages
  22356. * the PEAR_Exception PHP5 error handling mechanism
  22357. * the PEAR_ErrorStack advanced error handling mechanism
  22358. * the PEAR_Error error handling mechanism
  22359. * the OS_Guess class for retrieving info about the OS
  22360. where PHP is running on
  22361. * the System class for quick handling of common operations
  22362. with files and directories
  22363. * the PEAR base class
  22364. Features in a nutshell:
  22365. * full support for channels
  22366. * pre-download dependency validation
  22367. * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
  22368. * support for optional dependency groups and limited support for sub-packaging
  22369. * robust dependency support
  22370. * full dependency validation on uninstall
  22371. * remote install for hosts with only ftp access - no more problems with
  22372. restricted host installation
  22373. * full support for mirroring
  22374. * support for bundling several packages into a single tarball
  22375. * support for static dependencies on a url-based package
  22376. * support for custom file roles and installation tasks</description>
  22377. <lead>
  22378. <name>Greg Beaver</name>
  22379. <user>cellog</user>
  22380. <email>cellog@php.net</email>
  22381. <active>no</active>
  22382. </lead>
  22383. <lead>
  22384. <name>Pierre-Alain Joye</name>
  22385. <user>pajoye</user>
  22386. <email>pierre@php.net</email>
  22387. <active>no</active>
  22388. </lead>
  22389. <lead>
  22390. <name>Stig Bakken</name>
  22391. <user>ssb</user>
  22392. <email>stig@php.net</email>
  22393. <active>no</active>
  22394. </lead>
  22395. <lead>
  22396. <name>Tomas V.V.Cox</name>
  22397. <user>cox</user>
  22398. <email>cox@idecnet.com</email>
  22399. <active>no</active>
  22400. </lead>
  22401. <lead>
  22402. <name>Helgi Thormar</name>
  22403. <user>dufuz</user>
  22404. <email>dufuz@php.net</email>
  22405. <active>no</active>
  22406. </lead>
  22407. <lead>
  22408. <name>Christian Weiske</name>
  22409. <user>cweiske</user>
  22410. <email>cweiske@php.net</email>
  22411. <active>yes</active>
  22412. </lead>
  22413. <lead>
  22414. <name>Chuck Burgess</name>
  22415. <user>ashnazg</user>
  22416. <email>ashnazg@php.net</email>
  22417. <active>yes</active>
  22418. </lead>
  22419. <developer>
  22420. <name>Tias Guns</name>
  22421. <user>tias</user>
  22422. <email>tias@php.net</email>
  22423. <active>no</active>
  22424. </developer>
  22425. <helper>
  22426. <name>Tim Jackson</name>
  22427. <user>timj</user>
  22428. <email>timj@php.net</email>
  22429. <active>no</active>
  22430. </helper>
  22431. <helper>
  22432. <name>Bertrand Gugger</name>
  22433. <user>toggg</user>
  22434. <email>toggg@php.net</email>
  22435. <active>no</active>
  22436. </helper>
  22437. <helper>
  22438. <name>Martin Jansen</name>
  22439. <user>mj</user>
  22440. <email>mj@php.net</email>
  22441. <active>no</active>
  22442. </helper>
  22443. <date>2019-11-20</date>
  22444. <time>18:43:37</time>
  22445. <version>
  22446. <release>1.10.10</release>
  22447. <api>1.10.1</api>
  22448. </version>
  22449. <stability>
  22450. <release>stable</release>
  22451. <api>stable</api>
  22452. </stability>
  22453. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  22454. <notes>
  22455. * PR #89: Fix scripts/* include paths
  22456. * PR #90: Non-interactive configureoption answers
  22457. * PR #91: Added missing preg quote
  22458. * PR #92: handle &quot;lib64&quot; case for glibc detection
  22459. * PR #93: Fix PHP Notice: Trying to access array offset on value of type bool with 7.4
  22460. * PR #94: Updated logic in useLocalCache to reuse getCacheId
  22461. * PR #95: Fix manpage warning
  22462. * PR #96: Implement the SOURCE_DATE_EPOCH specification
  22463. * PR #97: Fix PHP 7.4 deprecation: array/string curly braces access
  22464. * PR #98: Fix use of null/false as array
  22465. * PR #99: Fix Travis builds on PHP 5.4 and 5.5
  22466. * PR #100: Honor PHP temp directory config
  22467. * PR #101: Fix documentation: the `--force` is required
  22468. </notes>
  22469. <contents>
  22470. <dir name="/">
  22471. <file md5sum="6a5b25cf1ec0dae5d1d45d2c772177af" name="OS/Guess.php" role="php">
  22472. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22473. </file>
  22474. <file md5sum="4945b6bf10a18a8bfce5713b5f9d237a" name="PEAR/ChannelFile/Parser.php" role="php">
  22475. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22476. </file>
  22477. <file md5sum="8fd87e64002e11fd86eb2f3fbfee6599" name="PEAR/Command/Auth.xml" role="php" />
  22478. <file md5sum="3f7e84c3ce6a0ee1da05ac17230ed3e2" name="PEAR/Command/Auth.php" role="php">
  22479. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22480. </file>
  22481. <file md5sum="ce6bb5b6fdc02e0f50e7676403fd84a4" name="PEAR/Command/Build.xml" role="php" />
  22482. <file md5sum="1364b6c7bfa6990760e0e9eb1b770420" name="PEAR/Command/Build.php" role="php">
  22483. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22484. </file>
  22485. <file md5sum="6d5aab4d4308c3005b5f584c7783a031" name="PEAR/Command/Channels.xml" role="php" />
  22486. <file md5sum="1c6b2a9e9d6cfea7dc55dccbe6f6081b" name="PEAR/Command/Channels.php" role="php">
  22487. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22488. </file>
  22489. <file md5sum="90a2d9a1bdbb6fe10dba1ff089eba7c3" name="PEAR/Command/Common.php" role="php">
  22490. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22491. </file>
  22492. <file md5sum="91f189cb9423b5e87ee0abc5ea1a2be3" name="PEAR/Command/Config.xml" role="php" />
  22493. <file md5sum="f258823378391076958e2e8947417fa4" name="PEAR/Command/Config.php" role="php">
  22494. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22495. </file>
  22496. <file md5sum="24d05213cae7faa3880bbb5e40998867" name="PEAR/Command/Install.xml" role="php" />
  22497. <file md5sum="dd1dd2b9f4c2915f02691fb2c2afb1a3" name="PEAR/Command/Install.php" role="php">
  22498. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22499. </file>
  22500. <file md5sum="5cb62a04c0a268f4edd64a49a3895c92" name="PEAR/Command/Mirror.xml" role="php" />
  22501. <file md5sum="8bf708dc196a265df57e07eb2ffc9e60" name="PEAR/Command/Mirror.php" role="php">
  22502. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22503. </file>
  22504. <file md5sum="9367dcd7e4dbdde423f9c4c7d3f3a919" name="PEAR/Command/Package.xml" role="php" />
  22505. <file md5sum="57521ff1e89bcd23a853134f30836990" name="PEAR/Command/Package.php" role="php">
  22506. <tasks:replace from="@DATA-DIR@" to="data_dir" type="pear-config" />
  22507. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22508. </file>
  22509. <file md5sum="28dc842ea725d8787b9f9c3dbca5aa22" name="PEAR/Command/Pickle.xml" role="php" />
  22510. <file md5sum="9942911ded2011a66136968d9b384861" name="PEAR/Command/Pickle.php" role="php">
  22511. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22512. </file>
  22513. <file md5sum="49b046cfc14747f0365e02e9c3f0e6dc" name="PEAR/Command/Registry.xml" role="php" />
  22514. <file md5sum="55f6de8d32bdfcb50efda09d132e073f" name="PEAR/Command/Registry.php" role="php">
  22515. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22516. </file>
  22517. <file md5sum="29c02e823879b4e3e291f6b36fb339f1" name="PEAR/Command/Remote.xml" role="php" />
  22518. <file md5sum="b3f37812882bcd3d7a6f8658240906ed" name="PEAR/Command/Remote.php" role="php">
  22519. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22520. </file>
  22521. <file md5sum="a50c32015005e0761cc3b04679b29ed0" name="PEAR/Command/Test.xml" role="php" />
  22522. <file md5sum="cb1553c7104d9149119a8163a3c48fb6" name="PEAR/Command/Test.php" role="php">
  22523. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22524. </file>
  22525. <file md5sum="a01fa891f2940c26bf56d6d95ad3cc39" name="PEAR/Downloader/Package.php" role="php">
  22526. <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22527. </file>
  22528. <file md5sum="2a09770525a8de1b9006f869c3ea96f7" name="PEAR/Frontend/CLI.php" role="php">
  22529. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22530. </file>
  22531. <file md5sum="da58088eae1c0185d7cc4253b72d732b" name="PEAR/Installer/Role/Common.php" role="php">
  22532. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22533. </file>
  22534. <file md5sum="d8c62e6275e3aaa7784290912406092c" name="PEAR/Installer/Role/Cfg.xml" role="php" />
  22535. <file md5sum="0fd62e3e077960e6f7697bd329105cd9" name="PEAR/Installer/Role/Cfg.php" role="php">
  22536. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22537. </file>
  22538. <file md5sum="89a4a2a286e842d45a98974f40a0565c" name="PEAR/Installer/Role/Data.xml" role="php" />
  22539. <file md5sum="aa4108cbe36ee92d59b2acae82fe1c37" name="PEAR/Installer/Role/Data.php" role="php">
  22540. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22541. </file>
  22542. <file md5sum="b1ce0fe105251c3b75209d6518ee69ac" name="PEAR/Installer/Role/Doc.xml" role="php" />
  22543. <file md5sum="f0c7d5429b73a0f1dc28462a0c6e5841" name="PEAR/Installer/Role/Doc.php" role="php">
  22544. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22545. </file>
  22546. <file md5sum="af71c0ad42d16a323afe24a4f884ef15" name="PEAR/Installer/Role/Ext.xml" role="php" />
  22547. <file md5sum="1cfa2f3d4e0efc4ecdf1620df4003dd2" name="PEAR/Installer/Role/Ext.php" role="php">
  22548. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22549. </file>
  22550. <file md5sum="da6743f1e45cce72ea13aef5cdb14867" name="PEAR/Installer/Role/Man.xml" role="php" />
  22551. <file md5sum="1fb74dbb0c588f55482f40c540c230b2" name="PEAR/Installer/Role/Man.php" role="php">
  22552. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22553. </file>
  22554. <file md5sum="ef88f0321d3e481c2130c95122cf76d8" name="PEAR/Installer/Role/Php.xml" role="php" />
  22555. <file md5sum="bf246b4012ec3b84a486cd8d60926443" name="PEAR/Installer/Role/Php.php" role="php">
  22556. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22557. </file>
  22558. <file md5sum="746461dc3b48af6d24094cb0211608f2" name="PEAR/Installer/Role/Script.xml" role="php" />
  22559. <file md5sum="c987dced9b4689fe0798714223ac8094" name="PEAR/Installer/Role/Script.php" role="php">
  22560. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22561. </file>
  22562. <file md5sum="e147d63f168ea156fc2be38caaa63804" name="PEAR/Installer/Role/Src.xml" role="php" />
  22563. <file md5sum="908cc87e04f8d269256fce29f106af4d" name="PEAR/Installer/Role/Src.php" role="php">
  22564. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22565. </file>
  22566. <file md5sum="a24b596ec987aa5688fc19e8ed4e97ea" name="PEAR/Installer/Role/Test.xml" role="php" />
  22567. <file md5sum="cb180c66078c0787c118433f1274ba65" name="PEAR/Installer/Role/Test.php" role="php">
  22568. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22569. </file>
  22570. <file md5sum="7641e71c5785bb33a4261ebe25ed0fd7" name="PEAR/Installer/Role/Www.xml" role="php" />
  22571. <file md5sum="4130250d17c1bd49461c0ca995d034e5" name="PEAR/Installer/Role/Www.php" role="php">
  22572. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22573. </file>
  22574. <file md5sum="9e4c8992c3640c354570c88942df58fc" name="PEAR/Installer/Role.php" role="php">
  22575. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22576. </file>
  22577. <file md5sum="bf01705d6dd7c57596fe250042f9ea7e" name="PEAR/PackageFile/Generator/v1.php" role="php">
  22578. <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22579. </file>
  22580. <file md5sum="579a08a695107d32039edb614dada65f" name="PEAR/PackageFile/Generator/v2.php" role="php">
  22581. <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22582. </file>
  22583. <file md5sum="a2206e0e32ad2ba2f4e2a0c1797f295c" name="PEAR/PackageFile/Parser/v1.php" role="php">
  22584. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22585. </file>
  22586. <file md5sum="3857f4b60878d64551a7cdae783437f7" name="PEAR/PackageFile/Parser/v2.php" role="php">
  22587. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22588. </file>
  22589. <file md5sum="2999fc7b5617dd550f03d264b14bda69" name="PEAR/PackageFile/v2/rw.php" role="php">
  22590. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22591. </file>
  22592. <file md5sum="4b29d17199be54b2ac96caeffa5d9d2a" name="PEAR/PackageFile/v2/Validator.php" role="php">
  22593. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22594. </file>
  22595. <file md5sum="62143cd49d99ca8a7724d9fdb39ceeac" name="PEAR/PackageFile/v1.php" role="php">
  22596. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22597. </file>
  22598. <file md5sum="6c65702c3aa747dbed38b1359edc4d52" name="PEAR/PackageFile/v2.php" role="php">
  22599. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22600. </file>
  22601. <file md5sum="17fa739b764a3511163cebc2d2bf8a34" name="PEAR/REST/10.php" role="php">
  22602. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22603. </file>
  22604. <file md5sum="9bba40f3c3afc05a20f91dc057c497d8" name="PEAR/REST/11.php" role="php">
  22605. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22606. </file>
  22607. <file md5sum="134ac7fdd79567ed49d77a9739bfa2e8" name="PEAR/REST/13.php" role="php">
  22608. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22609. </file>
  22610. <file md5sum="93e5140ac0c5d8fe488d6f94dbc18013" name="PEAR/Task/Postinstallscript/rw.php" role="php">
  22611. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22612. </file>
  22613. <file md5sum="89a1859966c38fd75498430a61ee08af" name="PEAR/Task/Replace/rw.php" role="php">
  22614. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22615. </file>
  22616. <file md5sum="ffba3c3ef65f7b146c1e7fbfdcb3fe2b" name="PEAR/Task/Unixeol/rw.php" role="php">
  22617. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22618. </file>
  22619. <file md5sum="5ad48af0d328b404a4bfa520cd715d02" name="PEAR/Task/Windowseol/rw.php" role="php">
  22620. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22621. </file>
  22622. <file md5sum="f7c71446e8aefefa53fac75f1af740df" name="PEAR/Task/Common.php" role="php">
  22623. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22624. </file>
  22625. <file md5sum="8719f6cda15a53f6f4b785f0967aac09" name="PEAR/Task/Postinstallscript.php" role="php">
  22626. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22627. </file>
  22628. <file md5sum="a038ffd4580522738a0bb0422f02f8d8" name="PEAR/Task/Replace.php" role="php">
  22629. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22630. </file>
  22631. <file md5sum="4530dc166e0e5b1a0a3336c3c6b00c2b" name="PEAR/Task/Unixeol.php" role="php">
  22632. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22633. </file>
  22634. <file md5sum="dde63fa8f3a57c30e149c9d5b588b26e" name="PEAR/Task/Windowseol.php" role="php">
  22635. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22636. </file>
  22637. <file md5sum="1b60d353ff700a0d344f180cf932a924" name="PEAR/Validator/PECL.php" role="php">
  22638. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22639. </file>
  22640. <file md5sum="1dba4ba7da7fd6410951682441a46031" name="PEAR/Builder.php" role="php">
  22641. <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22642. </file>
  22643. <file md5sum="8f405806766c827414870a0a357fc90e" name="PEAR/ChannelFile.php" role="php">
  22644. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22645. </file>
  22646. <file md5sum="f49d275dd33516ab902a1950eb71b7a9" name="PEAR/Command.php" role="php">
  22647. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22648. </file>
  22649. <file md5sum="25bb0a3ebb8ffb95b9c869d58e42f7dc" name="PEAR/Common.php" role="php">
  22650. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22651. </file>
  22652. <file md5sum="fe092bab9e52dcac19b88d66a892fb47" name="PEAR/Config.php" role="php">
  22653. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22654. </file>
  22655. <file md5sum="f4ea827d4d516b269db2ccbad1cf683d" name="PEAR/DependencyDB.php" role="php">
  22656. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22657. </file>
  22658. <file md5sum="b588db6070297a3c53269a19e97569cd" name="PEAR/Dependency2.php" role="php">
  22659. <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22660. </file>
  22661. <file md5sum="08a6404c810684027ec76700ddf727d0" name="PEAR/Downloader.php" role="php">
  22662. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22663. </file>
  22664. <file md5sum="21f353cda7dd5644ecc8d8e6f347ebc8" name="PEAR/ErrorStack.php" role="php">
  22665. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22666. </file>
  22667. <file md5sum="e7377c43b9dcdd937ca19bdc13c96e89" name="PEAR/Exception.php" role="php">
  22668. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22669. </file>
  22670. <file md5sum="c748d8dbe5ac1a6522075d723de2ab90" name="PEAR/Frontend.php" role="php">
  22671. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22672. </file>
  22673. <file md5sum="61556688fd9623f891255efb2bc8c50d" name="PEAR/Installer.php" role="php">
  22674. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22675. </file>
  22676. <file md5sum="a3608c54f424a91f50e2a5d36ed260e4" name="PEAR/PackageFile.php" role="php">
  22677. <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  22678. </file>
  22679. <file md5sum="083db4cc2062c793ff10f7f97bc0d20e" name="PEAR/Packager.php" role="php">
  22680. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22681. </file>
  22682. <file md5sum="5249b350cba81635819afafbaa418210" name="PEAR/Proxy.php" role="php">
  22683. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22684. </file>
  22685. <file md5sum="27dcdcace0c267f8c6352ee7bcd392ac" name="PEAR/Registry.php" role="php">
  22686. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22687. </file>
  22688. <file md5sum="c0f004787497627c1e3ea69a084bce93" name="PEAR/REST.php" role="php">
  22689. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22690. </file>
  22691. <file md5sum="1a861d103008becd003e380b3935dd65" name="PEAR/RunTest.php" role="php">
  22692. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22693. </file>
  22694. <file md5sum="26ce023911f5ffbd1204764c116ad622" name="PEAR/Validate.php" role="php">
  22695. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22696. </file>
  22697. <file md5sum="33c3df366ed677a139b456ff5261e828" name="PEAR/XMLParser.php" role="php">
  22698. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22699. </file>
  22700. <file baseinstalldir="/" md5sum="d888d06143e3cac0dae78bbb2e761366" name="scripts/pear.bat" role="script">
  22701. <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  22702. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22703. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22704. <tasks:windowseol />
  22705. </file>
  22706. <file baseinstalldir="/" md5sum="762c9aeb3a91f7160a12896ce197acb6" name="scripts/peardev.bat" role="script">
  22707. <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  22708. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22709. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22710. <tasks:windowseol />
  22711. </file>
  22712. <file baseinstalldir="/" md5sum="2bd742ce721c8dd5aa164613c063a8a9" name="scripts/pecl.bat" role="script">
  22713. <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  22714. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22715. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22716. <tasks:windowseol />
  22717. </file>
  22718. <file baseinstalldir="/" md5sum="8ac139504e80bede470aef6d405100b6" name="scripts/pear.sh" role="script">
  22719. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22720. <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22721. <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22722. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22723. <tasks:unixeol />
  22724. </file>
  22725. <file baseinstalldir="/" md5sum="08ea03525b4ba914dfd9ec69c4238cf4" name="scripts/peardev.sh" role="script">
  22726. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22727. <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22728. <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22729. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22730. <tasks:unixeol />
  22731. </file>
  22732. <file baseinstalldir="/" md5sum="bde09b17fa816d58bb136375a13119c3" name="scripts/pecl.sh" role="script">
  22733. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22734. <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22735. <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22736. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22737. <tasks:unixeol />
  22738. </file>
  22739. <file baseinstalldir="/" md5sum="ac3d7d245d35e7348c33e9d235986278" name="scripts/pearcmd.php" role="php">
  22740. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22741. <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22742. <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22743. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22744. </file>
  22745. <file baseinstalldir="/" md5sum="48867dfbb41f2532d034f56a79565893" name="scripts/peclcmd.php" role="php">
  22746. <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  22747. <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  22748. <tasks:replace from="@pear_version@" to="version" type="package-info" />
  22749. <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  22750. </file>
  22751. <file md5sum="45b44486d8090de17b2a8b4211fab247" name="LICENSE" role="doc" />
  22752. <file md5sum="eaac3d33068c6e67573ed44155b149ae" name="INSTALL" role="doc" />
  22753. <file md5sum="4a49bc83a392934e57af45c70a589fda" name="package.dtd" role="data" />
  22754. <file md5sum="a592c1f104b440d353fa6268be79c4cf" name="PEAR.php" role="php">
  22755. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22756. </file>
  22757. <file md5sum="f69ce47ad09e4a71b82e5ada6c6b2cf2" name="README.rst" role="doc" />
  22758. <file md5sum="74e44820222b0799da6998da3c90c846" name="System.php" role="php">
  22759. <tasks:replace from="@package_version@" to="version" type="package-info" />
  22760. </file>
  22761. <file md5sum="acd010e3bc43c0f72df584acde7b9158" name="template.spec" role="data" />
  22762. </dir>
  22763. </contents>
  22764. <dependencies>
  22765. <required>
  22766. <php>
  22767. <min>5.4.0</min>
  22768. </php>
  22769. <pearinstaller>
  22770. <min>1.9.0</min>
  22771. </pearinstaller>
  22772. <package>
  22773. <name>Archive_Tar</name>
  22774. <channel>pear.php.net</channel>
  22775. <min>1.4.0</min>
  22776. <recommended>1.4.4</recommended>
  22777. </package>
  22778. <package>
  22779. <name>Structures_Graph</name>
  22780. <channel>pear.php.net</channel>
  22781. <min>1.1.0</min>
  22782. <recommended>1.1.1</recommended>
  22783. </package>
  22784. <package>
  22785. <name>Console_Getopt</name>
  22786. <channel>pear.php.net</channel>
  22787. <min>1.4.1</min>
  22788. <recommended>1.4.1</recommended>
  22789. </package>
  22790. <package>
  22791. <name>XML_Util</name>
  22792. <channel>pear.php.net</channel>
  22793. <min>1.3.0</min>
  22794. <recommended>1.4.3</recommended>
  22795. </package>
  22796. <package>
  22797. <name>PEAR_Frontend_Web</name>
  22798. <channel>pear.php.net</channel>
  22799. <max>0.4</max>
  22800. <conflicts />
  22801. </package>
  22802. <package>
  22803. <name>PEAR_Frontend_Gtk</name>
  22804. <channel>pear.php.net</channel>
  22805. <max>0.4.0</max>
  22806. <exclude>0.4.0</exclude>
  22807. <conflicts />
  22808. </package>
  22809. <extension>
  22810. <name>xml</name>
  22811. </extension>
  22812. <extension>
  22813. <name>pcre</name>
  22814. </extension>
  22815. </required>
  22816. <group hint="PEAR&apos;s web-based installer" name="webinstaller">
  22817. <package>
  22818. <name>PEAR_Frontend_Web</name>
  22819. <channel>pear.php.net</channel>
  22820. <min>0.5.1</min>
  22821. </package>
  22822. </group>
  22823. <group hint="PEAR&apos;s PHP-GTK-based installer" name="gtkinstaller">
  22824. <package>
  22825. <name>PEAR_Frontend_Gtk</name>
  22826. <channel>pear.php.net</channel>
  22827. <min>0.4.0</min>
  22828. </package>
  22829. </group>
  22830. <group hint="PEAR&apos;s PHP-GTK2-based installer" name="gtk2installer">
  22831. <package>
  22832. <name>PEAR_Frontend_Gtk2</name>
  22833. <channel>pear.php.net</channel>
  22834. </package>
  22835. </group>
  22836. </dependencies>
  22837. <phprelease>
  22838. <installconditions>
  22839. <os>
  22840. <name>windows</name>
  22841. </os>
  22842. </installconditions>
  22843. <filelist>
  22844. <install as="pear.bat" name="scripts/pear.bat" />
  22845. <install as="peardev.bat" name="scripts/peardev.bat" />
  22846. <install as="pecl.bat" name="scripts/pecl.bat" />
  22847. <install as="pearcmd.php" name="scripts/pearcmd.php" />
  22848. <install as="peclcmd.php" name="scripts/peclcmd.php" />
  22849. <ignore name="scripts/peardev.sh" />
  22850. <ignore name="scripts/pear.sh" />
  22851. <ignore name="scripts/pecl.sh" />
  22852. </filelist>
  22853. </phprelease>
  22854. <phprelease>
  22855. <filelist>
  22856. <install as="pear" name="scripts/pear.sh" />
  22857. <install as="peardev" name="scripts/peardev.sh" />
  22858. <install as="pecl" name="scripts/pecl.sh" />
  22859. <install as="pearcmd.php" name="scripts/pearcmd.php" />
  22860. <install as="peclcmd.php" name="scripts/peclcmd.php" />
  22861. <ignore name="scripts/pear.bat" />
  22862. <ignore name="scripts/peardev.bat" />
  22863. <ignore name="scripts/pecl.bat" />
  22864. </filelist>
  22865. </phprelease>
  22866. <changelog>
  22867. <release>
  22868. <version>
  22869. <release>1.8.0alpha1</release>
  22870. <api>1.8.0</api>
  22871. </version>
  22872. <stability>
  22873. <release>alpha</release>
  22874. <api>stable</api>
  22875. </stability>
  22876. <date>2009-03-09</date>
  22877. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  22878. <notes>
  22879. * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz]
  22880. * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz]
  22881. * Implement Request #10825: Only display the &quot;invalid or missing package file&quot;-error if it makes sense [dufuz]
  22882. * Implement Request #11170: script to generate Command/[command].xml [dufuz]
  22883. * Implement Request #11176: improve channel ... has updated its protocols message [dufuz]
  22884. * Implement Request #12706: pear list -a hard to read [dufuz]
  22885. * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz]
  22886. * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos]
  22887. * Implement Request #13927: install-pear.php should have option to set www_dir [timj]
  22888. * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz]
  22889. * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz]
  22890. - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate
  22891. better what other package managers are doing. upgrade-all will still work as intended.
  22892. * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz]
  22893. - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for
  22894. channel specific upgrades
  22895. * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske]
  22896. * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle]
  22897. * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog]
  22898. * Fix PHP Bug #47323: strotime warnings in make install [dufuz]
  22899. * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz]
  22900. * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj]
  22901. * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit]
  22902. * Fix Bug #13953: config-set/config-show with channel alias fail [cellog]
  22903. * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz]
  22904. * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz]
  22905. * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz]
  22906. * Fix Bug #14210: pear list -ia brings warnings [dufuz]
  22907. * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz]
  22908. * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz]
  22909. * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos]
  22910. * Fix Bug #14437: openbasedir warning when loading config [dufuz]
  22911. * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske]
  22912. * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali]
  22913. * Fix Bug #14977: PEAR/Frontend.php doesn&apos;t require_once PEAR.php [dufuz]
  22914. * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz]
  22915. * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz]
  22916. * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz]
  22917. NOTE!
  22918. Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment
  22919. to migrate over to one of the alternatives that have ben provided:
  22920. * PEAR_Common-&gt;downloadHttp (use PEAR_Downloader-&gt;downloadHttp instead)
  22921. * PEAR_Common-&gt;infoFromTgzFile (use PEAR_PackageFile-&gt;fromTgzFile instead)
  22922. * PEAR_Common-&gt;infoFromDescriptionFile (use PEAR_PackageFile-&gt;fromPackageFile instead)
  22923. * PEAR_Common-&gt;infoFromString (use PEAR_PackageFile-&gt;fromXmlstring instead)
  22924. * PEAR_Common-&gt;infoFromArray (use PEAR_PackageFile-&gt;fromAnyFile instead)
  22925. * PEAR_Common-&gt;xmlFromInfo (use a PEAR_PackageFile_v* object&apos;s generator instead)
  22926. * PEAR_Common-&gt;validatePackageInfo (use the validation of PEAR_PackageFile objects)
  22927. * PEAR_Common-&gt;analyzeSourceCode (use a PEAR_PackageFile_v* object instead)
  22928. * PEAR_Common-&gt;detectDependencies (use PEAR_Downloader_Package-&gt;detectDependencies instead)
  22929. * PEAR_Common-&gt;buildProvidesArray (use PEAR_PackageFile_v1-&gt;_buildProvidesArray or
  22930. PEAR_PackageFile_v2_Validator-&gt;_buildProvidesArray)
  22931. PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls
  22932. pear upgrade -f PEAR will allow people with lower versions
  22933. to upgrade to this release but no guarantees will be made that it will work properly.
  22934. Support for XML RPC channels has been dropped - The only ones that used it
  22935. (pear.php.net and pecl.php.net) have used the REST interface for years now.
  22936. SOAP support also removed as it was only proof of concept.
  22937. Move codebase from the PHP License to New BSD 2 clause license
  22938. </notes>
  22939. </release>
  22940. <release>
  22941. <date>2009-03-27</date>
  22942. <version>
  22943. <release>1.8.0RC1</release>
  22944. <api>1.8.0</api>
  22945. </version>
  22946. <stability>
  22947. <release>beta</release>
  22948. <api>stable</api>
  22949. </stability>
  22950. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  22951. <notes>
  22952. * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz]
  22953. * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz]
  22954. * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz]
  22955. * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz]
  22956. </notes>
  22957. </release>
  22958. <release>
  22959. <date>2009-04-10</date>
  22960. <version>
  22961. <release>1.8.0</release>
  22962. <api>1.8.0</api>
  22963. </version>
  22964. <stability>
  22965. <release>stable</release>
  22966. <api>stable</api>
  22967. </stability>
  22968. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  22969. <notes>
  22970. Changes since RC1:
  22971. * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz]
  22972. * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz]
  22973. * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz]
  22974. Remove custom XML_Util class in favor of using upstream XML_Util package as dependency
  22975. RC1 Release Notes:
  22976. * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz]
  22977. * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz]
  22978. * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz]
  22979. * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz]
  22980. Alpha1 Release Notes:
  22981. * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz]
  22982. * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz]
  22983. * Implement Request #10825: Only display the &quot;invalid or missing package file&quot;-error if it makes sense [dufuz]
  22984. * Implement Request #11170: script to generate Command/[command].xml [dufuz]
  22985. * Implement Request #11176: improve channel ... has updated its protocols message [dufuz]
  22986. * Implement Request #12706: pear list -a hard to read [dufuz]
  22987. * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz]
  22988. * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos]
  22989. * Implement Request #13927: install-pear.php should have option to set www_dir [timj]
  22990. * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz]
  22991. * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz]
  22992. - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate
  22993. better what other package managers are doing. upgrade-all will still work as intended.
  22994. * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz]
  22995. - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for
  22996. channel specific upgrades
  22997. * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske]
  22998. * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle]
  22999. * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog]
  23000. * Fix PHP Bug #47323: strotime warnings in make install [dufuz]
  23001. * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz]
  23002. * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj]
  23003. * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit]
  23004. * Fix Bug #13953: config-set/config-show with channel alias fail [cellog]
  23005. * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz]
  23006. * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz]
  23007. * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz]
  23008. * Fix Bug #14210: pear list -ia brings warnings [dufuz]
  23009. * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz]
  23010. * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz]
  23011. * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos]
  23012. * Fix Bug #14437: openbasedir warning when loading config [dufuz]
  23013. * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske]
  23014. * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali]
  23015. * Fix Bug #14977: PEAR/Frontend.php doesn&apos;t require_once PEAR.php [dufuz]
  23016. * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz]
  23017. * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz]
  23018. * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz]
  23019. NOTE!
  23020. Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment
  23021. to migrate over to one of the alternatives that have ben provided:
  23022. * PEAR_Common-&gt;downloadHttp (use PEAR_Downloader-&gt;downloadHttp instead)
  23023. * PEAR_Common-&gt;infoFromTgzFile (use PEAR_PackageFile-&gt;fromTgzFile instead)
  23024. * PEAR_Common-&gt;infoFromDescriptionFile (use PEAR_PackageFile-&gt;fromPackageFile instead)
  23025. * PEAR_Common-&gt;infoFromString (use PEAR_PackageFile-&gt;fromXmlstring instead)
  23026. * PEAR_Common-&gt;infoFromArray (use PEAR_PackageFile-&gt;fromAnyFile instead)
  23027. * PEAR_Common-&gt;xmlFromInfo (use a PEAR_PackageFile_v* object&apos;s generator instead)
  23028. * PEAR_Common-&gt;validatePackageInfo (use the validation of PEAR_PackageFile objects)
  23029. * PEAR_Common-&gt;analyzeSourceCode (use a PEAR_PackageFile_v* object instead)
  23030. * PEAR_Common-&gt;detectDependencies (use PEAR_Downloader_Package-&gt;detectDependencies instead)
  23031. * PEAR_Common-&gt;buildProvidesArray (use PEAR_PackageFile_v1-&gt;_buildProvidesArray or
  23032. PEAR_PackageFile_v2_Validator-&gt;_buildProvidesArray)
  23033. PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls
  23034. pear upgrade -f PEAR will allow people with lower versions
  23035. to upgrade to this release but no guarantees will be made that it will work properly.
  23036. Support for XML RPC channels has been dropped - The only ones that used it
  23037. (pear.php.net and pecl.php.net) have used the REST interface for years now.
  23038. SOAP support also removed as it was only proof of concept.
  23039. Move codebase from the PHP License to New BSD 2 clause license
  23040. </notes>
  23041. </release>
  23042. <release>
  23043. <date>2009-04-15</date>
  23044. <version>
  23045. <release>1.8.1</release>
  23046. <api>1.8.1</api>
  23047. </version>
  23048. <stability>
  23049. <release>stable</release>
  23050. <api>stable</api>
  23051. </stability>
  23052. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23053. <notes>
  23054. * Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz]
  23055. </notes>
  23056. </release>
  23057. <release>
  23058. <date>2009-08-18</date>
  23059. <version>
  23060. <release>1.9.0RC1</release>
  23061. <api>1.9.0RC1</api>
  23062. </version>
  23063. <stability>
  23064. <release>beta</release>
  23065. <api>stable</api>
  23066. </stability>
  23067. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23068. <notes>
  23069. * Implement Request #16213: add alias to list-channels output [dufuz]
  23070. * Implement Request #16378: pear svntag [dufuz]
  23071. * Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj]
  23072. * Implement Request #16396: package-dependencies should allow package names [dufuz]
  23073. * Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz]
  23074. * Fix Bug #14493: pear install --offline doesn&apos;t print out errors [dufuz]
  23075. * Fix Bug #11348: pear package-dependencies isn&apos;t well explained [dufuz]
  23076. * Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz]
  23077. * Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz]
  23078. * Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz]
  23079. * Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz]
  23080. * Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj]
  23081. * Fix Bug #16444: Setting preferred mirror fails [dufuz]
  23082. * Fix the shutdown functions where a index might not exist and thus raise a notice [derick]
  23083. </notes>
  23084. </release>
  23085. <release>
  23086. <date>2009-08-20</date>
  23087. <version>
  23088. <release>1.9.0RC2</release>
  23089. <api>1.9.0RC2</api>
  23090. </version>
  23091. <stability>
  23092. <release>beta</release>
  23093. <api>stable</api>
  23094. </stability>
  23095. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23096. <notes>
  23097. * REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz]
  23098. </notes>
  23099. </release>
  23100. <release>
  23101. <date>2009-08-21</date>
  23102. <version>
  23103. <release>1.9.0RC3</release>
  23104. <api>1.9.0RC3</api>
  23105. </version>
  23106. <stability>
  23107. <release>beta</release>
  23108. <api>stable</api>
  23109. </stability>
  23110. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23111. <notes>
  23112. * Improved svntag support to handle packages like PEAR it self [dufuz]
  23113. </notes>
  23114. </release>
  23115. <release>
  23116. <date>2009-08-23</date>
  23117. <version>
  23118. <release>1.9.0RC4</release>
  23119. <api>1.9.0RC4</api>
  23120. </version>
  23121. <stability>
  23122. <release>beta</release>
  23123. <api>stable</api>
  23124. </stability>
  23125. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23126. <notes>
  23127. * Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz]
  23128. * Make sure channel aliases can&apos;t be made to start with - [dufuz]
  23129. * Output issues with pear search [dufuz]
  23130. * Fixed couple of stray notices [dufuz]
  23131. </notes>
  23132. </release>
  23133. <release>
  23134. <date>2009-09-03</date>
  23135. <version>
  23136. <release>1.9.0</release>
  23137. <api>1.9.0</api>
  23138. </version>
  23139. <stability>
  23140. <release>stable</release>
  23141. <api>stable</api>
  23142. </stability>
  23143. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23144. <notes>
  23145. * Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz]
  23146. </notes>
  23147. </release>
  23148. <release>
  23149. <date>2010-05-26</date>
  23150. <version>
  23151. <release>1.9.1</release>
  23152. <api>1.9.1</api>
  23153. </version>
  23154. <stability>
  23155. <release>stable</release>
  23156. <api>stable</api>
  23157. </stability>
  23158. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23159. <notes>
  23160. * svntag improvements, tag package files passed into the command and better directory checks [dufuz]
  23161. * rely on Structures_Graph minimum version instead of recommended version [saltybeagle]
  23162. * Fix Bug #12613: running go-pear.phar from C:\ fails [dufuz]
  23163. * Fix Bug #14841: Installing pear into directory with space fails [dufuz]
  23164. * Fix Bug #16644: pear.bat returns syntax error when parenthesis are in install path. [dufuz] [patch by bwaters (Bryan Waters)]
  23165. * Fix Bug #16767: Use of Depreciated HTML Attributes in the Exception class [dufuz] [patch by fuhrysteve (Stephen J. Fuhry)]
  23166. * Fix Bug #16864: &quot;pear list-upgrades -i&quot; issues E_WARNINGS [dufuz] [patch by rquadling (Richard Quadling)]
  23167. * Fix Bug #17220: command `pear help` outputs to stderr instead of stdout [dufuz]
  23168. * Fix Bug #17234: channel-discover adds port to HTTP Host header [dufuz]
  23169. * Fix Bug #17292: Code Coverage in PEAR_RunTest does not work with namespaces [sebastian]
  23170. * Fix Bug #17359: loadExtension() fails over missing dl() when used in multithread env [dufuz]
  23171. * Fix Bug #17378: pear info $package fails if directory with that name exists [dufuz]
  23172. </notes>
  23173. </release>
  23174. <release>
  23175. <date>2011-02-28</date>
  23176. <time>18:30:00</time>
  23177. <version>
  23178. <release>1.9.2</release>
  23179. <api>1.9.2</api>
  23180. </version>
  23181. <stability>
  23182. <release>stable</release>
  23183. <api>stable</api>
  23184. </stability>
  23185. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23186. <notes>
  23187. Important! This is a security fix release. The advisory can be found at
  23188. http://pear.php.net/advisory-20110228.txt
  23189. Bugs:
  23190. * Fixed Bug #17463: Regression: On Windows, svntag [patch by doconnor]
  23191. * Fixed Bug #17641: pecl-list doesn&apos;t sort packages by name [dufuz]
  23192. * Fixed Bug #17781: invalid argument warning on foreach due to an empty optional dependencie [dufuz]
  23193. * Fixed Bug #17801: PEAR run-tests wrongly detects php-cgi [patch by David Jean Louis (izi)]
  23194. * Fixed Bug #17839: pear svntag does not tag package.xml file [dufuz]
  23195. * Fixed Bug #17986: PEAR Installer cannot handle files moved between packages [dufuz]
  23196. * Fixed Bug #17997: Strange output if directories are not writeable [dufuz]
  23197. * Fixed Bug #18001: PEAR/RunTest coverage fails [dufuz]
  23198. * Fixed Bug #18056 [SECURITY]: Symlink attack in PEAR install [dufuz]
  23199. * Fixed Bug #18218: &quot;pear package&quot; does not allow the use of late static binding [dufuz and Christer Edvartsen]
  23200. * Fixed Bug #18238: Wrong return code from &quot;pear help&quot; [till]
  23201. * Fixed Bug #18308: Broken error message about missing channel validator [yunosh]
  23202. This feature is implemented as a result of #18056
  23203. * Implemented Request #16648: Use TMPDIR for builds instead of /var/tmp [dufuz]
  23204. </notes>
  23205. </release>
  23206. <release>
  23207. <date>2011-06-04</date>
  23208. <time>15:30:00</time>
  23209. <version>
  23210. <release>1.9.3</release>
  23211. <api>1.9.2</api>
  23212. </version>
  23213. <stability>
  23214. <release>stable</release>
  23215. <api>stable</api>
  23216. </stability>
  23217. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23218. <notes>
  23219. * Fixed Bug #17744: Empty changelog causes fatal error in setChangelogentry [dufuz]
  23220. * Fixed Bug #18340: raiseErro typo [doconnor]
  23221. * Fixed Bug #18349: package.xml version not recognized when single quoted [dufuz]
  23222. * Fixed Bug #18364: date.timezone errors for sh/bat files when TZ is not set in php.ini [dufuz]
  23223. * Fixed Bug #18388: Parentheses error in REST.php line 232 [dufuz]
  23224. * Fixed Bug #18428: invalid preg_match patterns [glen]
  23225. * Fixed Bug #18486: REST/10.php does not check error condition [dufuz]
  23226. * Fixed a problem in RunTest and code coverage. Correctly register the
  23227. code coverage shutdown function in case we are inside a namespace. [sebastian]
  23228. * Fixed a bug with extensions not providing their config.m4 and co in the root directory of
  23229. their pecl package but rather in a sub directory, such as xhprof. [dufuz]
  23230. </notes>
  23231. </release>
  23232. <release>
  23233. <date>2011-07-06</date>
  23234. <time>15:30:00</time>
  23235. <version>
  23236. <release>1.9.4</release>
  23237. <api>1.9.4</api>
  23238. </version>
  23239. <stability>
  23240. <release>stable</release>
  23241. <api>stable</api>
  23242. </stability>
  23243. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23244. <notes>
  23245. Bug Fixes:
  23246. * Bug #17350: &quot;pear install --force&quot; doesn&apos;t uninstall files from previous pkg versions [dufuz]
  23247. * Bug #18362: A whitespace TEMP_DIR path breaks install/upgrade functionality [dufuz]
  23248. * Bug #18440: bad tmp folder path on install : Unable to create path for C:/Program/tmp [dufuz]
  23249. * Bug #18581: &quot;config-get -c&quot; not returning channel&apos;s configuration when using alias [dufuz]
  23250. * Bug #18639: regression: installing xdebug fails most likely due to another fix [dufuz]
  23251. Features
  23252. * All System (the class) functions can now take in spaced paths as long as they are surrounded in quotes.
  23253. Prior to this it was possible to do that by passing all values in as an array (by product of #18362, #18440) [dufuz]
  23254. </notes>
  23255. </release>
  23256. <release>
  23257. <date>2014-06-27</date>
  23258. <time>18:17:00</time>
  23259. <version>
  23260. <release>1.9.5dev1</release>
  23261. <api>1.9.5</api>
  23262. </version>
  23263. <stability>
  23264. <release>devel</release>
  23265. <api>devel</api>
  23266. </stability>
  23267. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23268. <notes>
  23269. Bug fixes:
  23270. * Fix bug #18343: Entities in file names decoded during packaging [cweiske]
  23271. * Fix bug #18665: pecl extensions not enabled in empty php.ini files [Louis Opter]
  23272. * Fix bug #18834: Do not truncate cache file if it is a symlink [avb]
  23273. * Fix bug #18892: Parse error in Installer.php [ashnazg]
  23274. * Fix bug #19482: fix pearcmd for include paths with trailing backslash [cweiske]
  23275. * Fix bug #19793: PHP Notice about ob_end_clean() [cweiske]
  23276. * Fix bug #20086: Invalid regexp in PEAR_Builder::build() [avb]
  23277. * Fix bug #20203: split content-type and get real mime type [Samu Voutilainen]
  23278. * Fix bug #20283: use full path for &quot;zend_extension=...&quot; [cweiske]
  23279. * Fix bug #20284: Reset interpreter before running --CLEAN-- section php-cgi run [Mats Lindh]
  23280. * Fix bug #20285: fix spelling mistakes [Veres Lajos]
  23281. * Fix bug #20286: Support access of static variables on objects in validator [cweiske]
  23282. * Fix bug #20321: Correctly detect name of current user during installation [cweiske]
  23283. * Fix bug: let pear run-tests fail when there are failed tests [cweiske]
  23284. * Prepare a test for bug #18056 / bug #18834 [avb]
  23285. </notes>
  23286. </release>
  23287. <release>
  23288. <date>2014-07-12</date>
  23289. <time>14:22:23</time>
  23290. <version>
  23291. <release>1.9.5</release>
  23292. <api>1.9.5</api>
  23293. </version>
  23294. <stability>
  23295. <release>stable</release>
  23296. <api>stable</api>
  23297. </stability>
  23298. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23299. <notes>
  23300. No changes since 1.9.5.dev1.
  23301. Bug fixes in 1.9.5.dev1:
  23302. * Fix bug #18343: Entities in file names decoded during packaging [cweiske]
  23303. * Fix bug #18665: pecl extensions not enabled in empty php.ini files [Louis Opter]
  23304. * Fix bug #18834: Do not truncate cache file if it is a symlink [avb]
  23305. * Fix bug #18892: Parse error in Installer.php [ashnazg]
  23306. * Fix bug #19482: fix pearcmd for include paths with trailing backslash [cweiske]
  23307. * Fix bug #19793: PHP Notice about ob_end_clean() [cweiske]
  23308. * Fix bug #20086: Invalid regexp in PEAR_Builder::build() [avb]
  23309. * Fix bug #20203: split content-type and get real mime type [Samu Voutilainen]
  23310. * Fix bug #20283: use full path for &quot;zend_extension=...&quot; [cweiske]
  23311. * Fix bug #20284: Reset interpreter before running --CLEAN-- section php-cgi run [Mats Lindh]
  23312. * Fix bug #20285: fix spelling mistakes [Veres Lajos]
  23313. * Fix bug #20286: Support access of static variables on objects in validator [cweiske]
  23314. * Fix bug #20321: Correctly detect name of current user during installation [cweiske]
  23315. * Fix bug: let pear run-tests fail when there are failed tests [cweiske]
  23316. * Prepare a test for bug #18056 / bug #18834 [avb]
  23317. </notes>
  23318. </release>
  23319. <release>
  23320. <date>2015-07-25</date>
  23321. <time>13:42:42</time>
  23322. <version>
  23323. <release>1.10.0dev1</release>
  23324. <api>1.10.0</api>
  23325. </version>
  23326. <stability>
  23327. <release>devel</release>
  23328. <api>devel</api>
  23329. </stability>
  23330. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23331. <notes>
  23332. * Implement #20488: Add support for PHP 7 [cweiske]
  23333. * Drop support for PHP 4 and 5.0 - 5.3 [cweiske]
  23334. * Remove deprecated methods [cweiske]
  23335. * Fix static warnings [cweiske]
  23336. * Fix #17045: avoid overwriting include path [glen]
  23337. * Fix #17399: &quot;pear help&quot; doesn&apos;t mention the &quot;version&quot; command [kguest]
  23338. * Add --showdiff to &quot;pear run-tests&quot; to print diff for failed tests [tyrael]
  23339. * Fix channel.xml downloading from https if it did not change [cweiske]
  23340. </notes>
  23341. </release>
  23342. <release>
  23343. <date>2015-07-31</date>
  23344. <time>09:42:42</time>
  23345. <version>
  23346. <release>1.10.0dev2</release>
  23347. <api>1.10.0</api>
  23348. </version>
  23349. <stability>
  23350. <release>devel</release>
  23351. <api>devel</api>
  23352. </stability>
  23353. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23354. <notes>
  23355. * Fix #18638 and #18405: Make PEAR::loadExtension static [cweiske]
  23356. * Fix #20319: allow pear to work when cache_dir is not writable [remicollet]
  23357. * Implement #20333: New role=man for man pages [bjori]
  23358. * Implement #20334: add &quot;metadata_dir&quot; configuration option [remicollet]
  23359. * Add long option names to install-pear.php [remicollet]
  23360. </notes>
  23361. </release>
  23362. <release>
  23363. <date>2015-09-28</date>
  23364. <time>09:42:42</time>
  23365. <version>
  23366. <release>1.10.0dev3</release>
  23367. <api>1.10.0</api>
  23368. </version>
  23369. <stability>
  23370. <release>devel</release>
  23371. <api>devel</api>
  23372. </stability>
  23373. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23374. <notes>
  23375. * Fix #20507: pear list-upgrades does not take PHP version into account [cweiske]
  23376. * Fix #20927: Use correct php-config [cweiske]
  23377. * Fix #20946: PEAR_Builder::log() declaration [remicollet]
  23378. * Remove PEAR/ErrorStack5.php [cweiske]
  23379. </notes>
  23380. </release>
  23381. <release>
  23382. <date>2015-10-07</date>
  23383. <time>11:22:42</time>
  23384. <version>
  23385. <release>1.10.0</release>
  23386. <api>1.10.0</api>
  23387. </version>
  23388. <stability>
  23389. <release>stable</release>
  23390. <api>stable</api>
  23391. </stability>
  23392. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23393. <notes>
  23394. No changes since version 1.10.0dev3.
  23395. Changes since version 1.9.5:
  23396. * Implement #20488: Add support for PHP 7 [cweiske]
  23397. * Drop support for PHP 4 and 5.0 - 5.3 [cweiske]
  23398. * Remove deprecated methods [cweiske]
  23399. * Add --showdiff to &quot;pear run-tests&quot; to print diff for failed tests [tyrael]
  23400. * Implement #20333: New role=man for man pages [bjori]
  23401. * Implement #20334: add &quot;metadata_dir&quot; configuration option [remicollet]
  23402. * Add long option names to install-pear.php [remicollet]
  23403. * Remove PEAR/ErrorStack5.php [cweiske]
  23404. * Fix #17045: avoid overwriting include path [glen]
  23405. * Fix #17399: &quot;pear help&quot; doesn&apos;t mention the &quot;version&quot; command [kguest]
  23406. * Fix #18638 and #18405: Make PEAR::loadExtension static [cweiske]
  23407. * Fix #20319: allow pear to work when cache_dir is not writable [remicollet]
  23408. * Fix #20507: pear list-upgrades does not take PHP version into account [cweiske]
  23409. * Fix #20927: Use correct php-config [cweiske]
  23410. * Fix #20946: PEAR_Builder::log() declaration [remicollet]
  23411. * Fix channel.xml downloading from https if it did not change [cweiske]
  23412. * Fix static warnings [cweiske]
  23413. </notes>
  23414. </release>
  23415. <release>
  23416. <date>2015-10-17</date>
  23417. <time>13:22:42</time>
  23418. <version>
  23419. <release>1.10.1</release>
  23420. <api>1.10.1</api>
  23421. </version>
  23422. <stability>
  23423. <release>stable</release>
  23424. <api>stable</api>
  23425. </stability>
  23426. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23427. <notes>
  23428. * Fix bug #20959: Crash on channel discovery with channel.xml redirect [cweiske]
  23429. * Fix bug #20968: Incorrect call to __construct() from PEAR() [edlman]
  23430. * Add legacy constructor for PEAR_Error for backwards compatibility [cweiske]
  23431. </notes>
  23432. </release>
  23433. <release>
  23434. <date>2017-02-28</date>
  23435. <time>07:40:00</time>
  23436. <version>
  23437. <release>1.10.2</release>
  23438. <api>1.10.1</api>
  23439. </version>
  23440. <stability>
  23441. <release>stable</release>
  23442. <api>stable</api>
  23443. </stability>
  23444. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23445. <notes>
  23446. * Fix Bug #4426: PEAR_Autoloader __call() must take only 2 arguments [kna]
  23447. * Fix Bug #20989: fatal error/bug in the postinstallscript task [kguest]
  23448. * Fix Bug #20991: Strict Standards: startSession and run methods in PEAR_Task_Postinstallscript [kguest]
  23449. * Fix Bug #21001: PEAR_ERROR_DIE exit code is 0 [danielc]
  23450. * Pull Request #52: Channel&apos;s _lastmodified is an int and not a string [sathieu]
  23451. * Pull Request #53: Add proper HTTPS proxy support through the CONNECT verb [youknow0]
  23452. * Pull Request #58: Make method signatures compatible. [yunosh]
  23453. </notes>
  23454. </release>
  23455. <release>
  23456. <date>2017-02-28</date>
  23457. <time>10:15:00</time>
  23458. <version>
  23459. <release>1.10.3</release>
  23460. <api>1.10.1</api>
  23461. </version>
  23462. <stability>
  23463. <release>stable</release>
  23464. <api>stable</api>
  23465. </stability>
  23466. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23467. <notes>
  23468. * Bug #21188: Class &apos;PEAR_Proxy&apos; not found
  23469. </notes>
  23470. </release>
  23471. <release>
  23472. <date>2017-04-25</date>
  23473. <version>
  23474. <release>1.10.4</release>
  23475. <api>1.10.1</api>
  23476. </version>
  23477. <stability>
  23478. <release>stable</release>
  23479. <api>stable</api>
  23480. </stability>
  23481. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23482. <notes>
  23483. * Bug #18102: pear install does not fail on error
  23484. </notes>
  23485. </release>
  23486. <release>
  23487. <date>2017-06-27</date>
  23488. <version>
  23489. <release>1.10.5</release>
  23490. <api>1.10.1</api>
  23491. </version>
  23492. <stability>
  23493. <release>stable</release>
  23494. <api>stable</api>
  23495. </stability>
  23496. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23497. <notes>
  23498. * Bug #21222: PHP 7.2 compatibility: Upgrade to Archive_Tar 1.4.3 needed
  23499. </notes>
  23500. </release>
  23501. <release>
  23502. <date>2018-08-22</date>
  23503. <version>
  23504. <release>1.10.6</release>
  23505. <api>1.10.1</api>
  23506. </version>
  23507. <stability>
  23508. <release>stable</release>
  23509. <api>stable</api>
  23510. </stability>
  23511. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23512. <notes>
  23513. * PR #70: Fix notice undefined variable metadata_dir
  23514. * PR #71: fix Warning: count(): Parameter must be an array or an object
  23515. * PR #74: Bug #23744 Remove is_executable check
  23516. * Bug #23744: The is_executable check in the Which method when run on Windows is unnecessary
  23517. * PR #75: Migrate old while(list() = each()) constructs to foreach
  23518. * PR #76: Fix PHP Warning: &quot;continue&quot; targeting switch is equivalent to &quot;break&quot;
  23519. * PR #77: proxy server auth
  23520. * PR #72: Correctly authenticate at proxy server
  23521. * PR #78: array or Countable error in 7.2
  23522. </notes>
  23523. </release>
  23524. <release>
  23525. <date>2018-12-05</date>
  23526. <version>
  23527. <release>1.10.7</release>
  23528. <api>1.10.1</api>
  23529. </version>
  23530. <stability>
  23531. <release>stable</release>
  23532. <api>stable</api>
  23533. </stability>
  23534. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23535. <notes>
  23536. * PR #79: Prevent Unable to find the wrapper &quot;channel&quot; Warning
  23537. * PR #80: fix Warning: &quot;continue&quot; targeting switch is equivalent to &quot;break&quot;. Did you mean to use &quot;continue 2&quot;
  23538. * PR #81: Add flags to PECL shell script for shared extensions
  23539. </notes>
  23540. </release>
  23541. <release>
  23542. <date>2019-02-07</date>
  23543. <version>
  23544. <release>1.10.8</release>
  23545. <api>1.10.1</api>
  23546. </version>
  23547. <stability>
  23548. <release>stable</release>
  23549. <api>stable</api>
  23550. </stability>
  23551. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23552. <notes>
  23553. * PR #83: Drop track_errors from options
  23554. * PR #84: Fix PHP 8 compatibility issues
  23555. </notes>
  23556. </release>
  23557. <release>
  23558. <date>2019-03-13</date>
  23559. <version>
  23560. <release>1.10.9</release>
  23561. <api>1.10.1</api>
  23562. </version>
  23563. <stability>
  23564. <release>stable</release>
  23565. <api>stable</api>
  23566. </stability>
  23567. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23568. <notes>
  23569. * PR #85: Fixes static calls for PHP 8
  23570. * PR #86: Adjust silencing check for PHP 8
  23571. * PR #87: Comparison fixes
  23572. * PR #88: Only add bin_dir to PATH if not already there (fixes PHP Bug #75852)
  23573. </notes>
  23574. </release>
  23575. <release>
  23576. <date>2019-11-19</date>
  23577. <version>
  23578. <release>1.10.10</release>
  23579. <api>1.10.1</api>
  23580. </version>
  23581. <stability>
  23582. <release>stable</release>
  23583. <api>stable</api>
  23584. </stability>
  23585. <license uri="http://opensource.org/licenses/bsd-license.php">New BSD License</license>
  23586. <notes>
  23587. * PR #89: Fix scripts/* include paths
  23588. * PR #90: Non-interactive configureoption answers
  23589. * PR #91: Added missing preg quote
  23590. * PR #92: handle &quot;lib64&quot; case for glibc detection
  23591. * PR #93: Fix PHP Notice: Trying to access array offset on value of type bool with 7.4
  23592. * PR #94: Updated logic in useLocalCache to reuse getCacheId
  23593. * PR #95: Fix manpage warning
  23594. * PR #96: Implement the SOURCE_DATE_EPOCH specification
  23595. * PR #97: Fix PHP 7.4 deprecation: array/string curly braces access
  23596. * PR #98: Fix use of null/false as array
  23597. * PR #99: Fix Travis builds on PHP 5.4 and 5.5
  23598. * PR #100: Honor PHP temp directory config
  23599. * PR #101: Fix documentation: the `--force` is required
  23600. </notes>
  23601. </release>
  23602. </changelog>
  23603. </package>
  23604. ����������������������������������PEAR-1.10.10/OS/Guess.php���������������������������������������������������������������������������0000644�0001750�0001750�00000025210�13565304531�014376� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  23605. /**
  23606. * The OS_Guess class
  23607. *
  23608. * PHP versions 4 and 5
  23609. *
  23610. * @category pear
  23611. * @package PEAR
  23612. * @author Stig Bakken <ssb@php.net>
  23613. * @author Gregory Beaver <cellog@php.net>
  23614. * @copyright 1997-2009 The Authors
  23615. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  23616. * @link http://pear.php.net/package/PEAR
  23617. * @since File available since PEAR 0.1
  23618. */
  23619. // {{{ uname examples
  23620. // php_uname() without args returns the same as 'uname -a', or a PHP-custom
  23621. // string for Windows.
  23622. // PHP versions prior to 4.3 return the uname of the host where PHP was built,
  23623. // as of 4.3 it returns the uname of the host running the PHP code.
  23624. //
  23625. // PC RedHat Linux 7.1:
  23626. // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
  23627. //
  23628. // PC Debian Potato:
  23629. // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
  23630. //
  23631. // PC FreeBSD 3.3:
  23632. // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386
  23633. //
  23634. // PC FreeBSD 4.3:
  23635. // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386
  23636. //
  23637. // PC FreeBSD 4.5:
  23638. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386
  23639. //
  23640. // PC FreeBSD 4.5 w/uname from GNU shellutils:
  23641. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown
  23642. //
  23643. // HP 9000/712 HP-UX 10:
  23644. // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
  23645. //
  23646. // HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
  23647. // HP-UX host B.10.10 A 9000/712 unknown
  23648. //
  23649. // IBM RS6000/550 AIX 4.3:
  23650. // AIX host 3 4 000003531C00
  23651. //
  23652. // AIX 4.3 w/uname from GNU shellutils:
  23653. // AIX host 3 4 000003531C00 unknown
  23654. //
  23655. // SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
  23656. // IRIX64 host 6.5 01091820 IP19 mips
  23657. //
  23658. // SGI Onyx IRIX 6.5:
  23659. // IRIX64 host 6.5 01091820 IP19
  23660. //
  23661. // SparcStation 20 Solaris 8 w/uname from GNU shellutils:
  23662. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
  23663. //
  23664. // SparcStation 20 Solaris 8:
  23665. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
  23666. //
  23667. // Mac OS X (Darwin)
  23668. // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh
  23669. //
  23670. // Mac OS X early versions
  23671. //
  23672. // }}}
  23673. /* TODO:
  23674. * - define endianness, to allow matchSignature("bigend") etc.
  23675. */
  23676. /**
  23677. * Retrieves information about the current operating system
  23678. *
  23679. * This class uses php_uname() to grok information about the current OS
  23680. *
  23681. * @category pear
  23682. * @package PEAR
  23683. * @author Stig Bakken <ssb@php.net>
  23684. * @author Gregory Beaver <cellog@php.net>
  23685. * @copyright 1997-2009 The Authors
  23686. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  23687. * @version Release: 1.10.10
  23688. * @link http://pear.php.net/package/PEAR
  23689. * @since Class available since Release 0.1
  23690. */
  23691. class OS_Guess
  23692. {
  23693. var $sysname;
  23694. var $nodename;
  23695. var $cpu;
  23696. var $release;
  23697. var $extra;
  23698. function __construct($uname = null)
  23699. {
  23700. list($this->sysname,
  23701. $this->release,
  23702. $this->cpu,
  23703. $this->extra,
  23704. $this->nodename) = $this->parseSignature($uname);
  23705. }
  23706. function parseSignature($uname = null)
  23707. {
  23708. static $sysmap = array(
  23709. 'HP-UX' => 'hpux',
  23710. 'IRIX64' => 'irix',
  23711. );
  23712. static $cpumap = array(
  23713. 'i586' => 'i386',
  23714. 'i686' => 'i386',
  23715. 'ppc' => 'powerpc',
  23716. );
  23717. if ($uname === null) {
  23718. $uname = php_uname();
  23719. }
  23720. $parts = preg_split('/\s+/', trim($uname));
  23721. $n = count($parts);
  23722. $release = $machine = $cpu = '';
  23723. $sysname = $parts[0];
  23724. $nodename = $parts[1];
  23725. $cpu = $parts[$n-1];
  23726. $extra = '';
  23727. if ($cpu == 'unknown') {
  23728. $cpu = $parts[$n - 2];
  23729. }
  23730. switch ($sysname) {
  23731. case 'AIX' :
  23732. $release = "$parts[3].$parts[2]";
  23733. break;
  23734. case 'Windows' :
  23735. switch ($parts[1]) {
  23736. case '95/98':
  23737. $release = '9x';
  23738. break;
  23739. default:
  23740. $release = $parts[1];
  23741. break;
  23742. }
  23743. $cpu = 'i386';
  23744. break;
  23745. case 'Linux' :
  23746. $extra = $this->_detectGlibcVersion();
  23747. // use only the first two digits from the kernel version
  23748. $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
  23749. break;
  23750. case 'Mac' :
  23751. $sysname = 'darwin';
  23752. $nodename = $parts[2];
  23753. $release = $parts[3];
  23754. if ($cpu == 'Macintosh') {
  23755. if ($parts[$n - 2] == 'Power') {
  23756. $cpu = 'powerpc';
  23757. }
  23758. }
  23759. break;
  23760. case 'Darwin' :
  23761. if ($cpu == 'Macintosh') {
  23762. if ($parts[$n - 2] == 'Power') {
  23763. $cpu = 'powerpc';
  23764. }
  23765. }
  23766. $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
  23767. break;
  23768. default:
  23769. $release = preg_replace('/-.*/', '', $parts[2]);
  23770. break;
  23771. }
  23772. if (isset($sysmap[$sysname])) {
  23773. $sysname = $sysmap[$sysname];
  23774. } else {
  23775. $sysname = strtolower($sysname);
  23776. }
  23777. if (isset($cpumap[$cpu])) {
  23778. $cpu = $cpumap[$cpu];
  23779. }
  23780. return array($sysname, $release, $cpu, $extra, $nodename);
  23781. }
  23782. function _detectGlibcVersion()
  23783. {
  23784. static $glibc = false;
  23785. if ($glibc !== false) {
  23786. return $glibc; // no need to run this multiple times
  23787. }
  23788. $major = $minor = 0;
  23789. include_once "System.php";
  23790. if (@is_link('/lib64/libc.so.6')) {
  23791. // Let's try reading the libc.so.6 symlink
  23792. if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib64/libc.so.6')), $matches)) {
  23793. list($major, $minor) = explode('.', $matches[1]);
  23794. }
  23795. } else if (@is_link('/lib/libc.so.6')) {
  23796. // Let's try reading the libc.so.6 symlink
  23797. if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) {
  23798. list($major, $minor) = explode('.', $matches[1]);
  23799. }
  23800. }
  23801. // Use glibc's <features.h> header file to
  23802. // get major and minor version number:
  23803. if (!($major && $minor) &&
  23804. @file_exists('/usr/include/features.h') &&
  23805. @is_readable('/usr/include/features.h')) {
  23806. if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
  23807. $features_file = fopen('/usr/include/features.h', 'rb');
  23808. while (!feof($features_file)) {
  23809. $line = fgets($features_file, 8192);
  23810. if (!$line || (strpos($line, '#define') === false)) {
  23811. continue;
  23812. }
  23813. if (strpos($line, '__GLIBC__')) {
  23814. // major version number #define __GLIBC__ version
  23815. $line = preg_split('/\s+/', $line);
  23816. $glibc_major = trim($line[2]);
  23817. if (isset($glibc_minor)) {
  23818. break;
  23819. }
  23820. continue;
  23821. }
  23822. if (strpos($line, '__GLIBC_MINOR__')) {
  23823. // got the minor version number
  23824. // #define __GLIBC_MINOR__ version
  23825. $line = preg_split('/\s+/', $line);
  23826. $glibc_minor = trim($line[2]);
  23827. if (isset($glibc_major)) {
  23828. break;
  23829. }
  23830. continue;
  23831. }
  23832. }
  23833. fclose($features_file);
  23834. if (!isset($glibc_major) || !isset($glibc_minor)) {
  23835. return $glibc = '';
  23836. }
  23837. return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
  23838. } // no cpp
  23839. $tmpfile = System::mktemp("glibctest");
  23840. $fp = fopen($tmpfile, "w");
  23841. fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
  23842. fclose($fp);
  23843. $cpp = popen("/usr/bin/cpp $tmpfile", "r");
  23844. while ($line = fgets($cpp, 1024)) {
  23845. if ($line[0] == '#' || trim($line) == '') {
  23846. continue;
  23847. }
  23848. if (list($major, $minor) = explode(' ', trim($line))) {
  23849. break;
  23850. }
  23851. }
  23852. pclose($cpp);
  23853. unlink($tmpfile);
  23854. } // features.h
  23855. if (!($major && $minor)) {
  23856. return $glibc = '';
  23857. }
  23858. return $glibc = "glibc{$major}.{$minor}";
  23859. }
  23860. function getSignature()
  23861. {
  23862. if (empty($this->extra)) {
  23863. return "{$this->sysname}-{$this->release}-{$this->cpu}";
  23864. }
  23865. return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
  23866. }
  23867. function getSysname()
  23868. {
  23869. return $this->sysname;
  23870. }
  23871. function getNodename()
  23872. {
  23873. return $this->nodename;
  23874. }
  23875. function getCpu()
  23876. {
  23877. return $this->cpu;
  23878. }
  23879. function getRelease()
  23880. {
  23881. return $this->release;
  23882. }
  23883. function getExtra()
  23884. {
  23885. return $this->extra;
  23886. }
  23887. function matchSignature($match)
  23888. {
  23889. $fragments = is_array($match) ? $match : explode('-', $match);
  23890. $n = count($fragments);
  23891. $matches = 0;
  23892. if ($n > 0) {
  23893. $matches += $this->_matchFragment($fragments[0], $this->sysname);
  23894. }
  23895. if ($n > 1) {
  23896. $matches += $this->_matchFragment($fragments[1], $this->release);
  23897. }
  23898. if ($n > 2) {
  23899. $matches += $this->_matchFragment($fragments[2], $this->cpu);
  23900. }
  23901. if ($n > 3) {
  23902. $matches += $this->_matchFragment($fragments[3], $this->extra);
  23903. }
  23904. return ($matches == $n);
  23905. }
  23906. function _matchFragment($fragment, $value)
  23907. {
  23908. if (strcspn($fragment, '*?') < strlen($fragment)) {
  23909. $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/';
  23910. return preg_match($reg, $value);
  23911. }
  23912. return ($fragment == '*' || !strcasecmp($fragment, $value));
  23913. }
  23914. }
  23915. /*
  23916. * Local Variables:
  23917. * indent-tabs-mode: nil
  23918. * c-basic-offset: 4
  23919. * End:
  23920. */
  23921. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/ChannelFile/Parser.php������������������������������������������������������������0000644�0001750�0001750�00000003254�13565304531�017126� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  23922. /**
  23923. * PEAR_ChannelFile_Parser for parsing channel.xml
  23924. *
  23925. * PHP versions 4 and 5
  23926. *
  23927. * @category pear
  23928. * @package PEAR
  23929. * @author Greg Beaver <cellog@php.net>
  23930. * @copyright 1997-2009 The Authors
  23931. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  23932. * @link http://pear.php.net/package/PEAR
  23933. * @since File available since Release 1.4.0a1
  23934. */
  23935. /**
  23936. * base xml parser class
  23937. */
  23938. require_once 'PEAR/XMLParser.php';
  23939. require_once 'PEAR/ChannelFile.php';
  23940. /**
  23941. * Parser for channel.xml
  23942. * @category pear
  23943. * @package PEAR
  23944. * @author Greg Beaver <cellog@php.net>
  23945. * @copyright 1997-2009 The Authors
  23946. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  23947. * @version Release: 1.10.10
  23948. * @link http://pear.php.net/package/PEAR
  23949. * @since Class available since Release 1.4.0a1
  23950. */
  23951. class PEAR_ChannelFile_Parser extends PEAR_XMLParser
  23952. {
  23953. var $_config;
  23954. var $_logger;
  23955. var $_registry;
  23956. function setConfig(&$c)
  23957. {
  23958. $this->_config = &$c;
  23959. $this->_registry = &$c->getRegistry();
  23960. }
  23961. function setLogger(&$l)
  23962. {
  23963. $this->_logger = &$l;
  23964. }
  23965. function parse($data, $file)
  23966. {
  23967. if (PEAR::isError($err = parent::parse($data, $file))) {
  23968. return $err;
  23969. }
  23970. $ret = new PEAR_ChannelFile;
  23971. $ret->setConfig($this->_config);
  23972. if (isset($this->_logger)) {
  23973. $ret->setLogger($this->_logger);
  23974. }
  23975. $ret->fromArray($this->_unserializedData);
  23976. // make sure the filelist is in the easy to read format needed
  23977. $ret->flattenFilelist();
  23978. $ret->setPackagefile($file, $archive);
  23979. return $ret;
  23980. }
  23981. }����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Auth.xml������������������������������������������������������������������0000644�0001750�0001750�00000002314�13565304531�016006� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  23982. <login>
  23983. <summary>Connects and authenticates to remote server [Deprecated in favor of channel-login]</summary>
  23984. <function>doLogin</function>
  23985. <shortcut>li</shortcut>
  23986. <options />
  23987. <doc>&lt;channel name&gt;
  23988. WARNING: This function is deprecated in favor of using channel-login
  23989. Log in to a remote channel server. If &lt;channel name&gt; is not supplied,
  23990. the default channel is used. To use remote functions in the installer
  23991. that require any kind of privileges, you need to log in first. The
  23992. username and password you enter here will be stored in your per-user
  23993. PEAR configuration (~/.pearrc on Unix-like systems). After logging
  23994. in, your username and password will be sent along in subsequent
  23995. operations on the remote server.</doc>
  23996. </login>
  23997. <logout>
  23998. <summary>Logs out from the remote server [Deprecated in favor of channel-logout]</summary>
  23999. <function>doLogout</function>
  24000. <shortcut>lo</shortcut>
  24001. <options />
  24002. <doc>
  24003. WARNING: This function is deprecated in favor of using channel-logout
  24004. Logs out from the remote server. This command does not actually
  24005. connect to the remote server, it only deletes the stored username and
  24006. password from your user configuration.</doc>
  24007. </logout>
  24008. </commands>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Auth.php������������������������������������������������������������������0000644�0001750�0001750�00000005013�13565304531�015774� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  24009. /**
  24010. * PEAR_Command_Auth (login, logout commands)
  24011. *
  24012. * PHP versions 4 and 5
  24013. *
  24014. * @category pear
  24015. * @package PEAR
  24016. * @author Stig Bakken <ssb@php.net>
  24017. * @author Greg Beaver <cellog@php.net>
  24018. * @copyright 1997-2009 The Authors
  24019. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  24020. * @link http://pear.php.net/package/PEAR
  24021. * @since File available since Release 0.1
  24022. * @deprecated since 1.8.0alpha1
  24023. */
  24024. /**
  24025. * base class
  24026. */
  24027. require_once 'PEAR/Command/Channels.php';
  24028. /**
  24029. * PEAR commands for login/logout
  24030. *
  24031. * @category pear
  24032. * @package PEAR
  24033. * @author Stig Bakken <ssb@php.net>
  24034. * @author Greg Beaver <cellog@php.net>
  24035. * @copyright 1997-2009 The Authors
  24036. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  24037. * @version Release: 1.10.10
  24038. * @link http://pear.php.net/package/PEAR
  24039. * @since Class available since Release 0.1
  24040. * @deprecated since 1.8.0alpha1
  24041. */
  24042. class PEAR_Command_Auth extends PEAR_Command_Channels
  24043. {
  24044. var $commands = array(
  24045. 'login' => array(
  24046. 'summary' => 'Connects and authenticates to remote server [Deprecated in favor of channel-login]',
  24047. 'shortcut' => 'li',
  24048. 'function' => 'doLogin',
  24049. 'options' => array(),
  24050. 'doc' => '<channel name>
  24051. WARNING: This function is deprecated in favor of using channel-login
  24052. Log in to a remote channel server. If <channel name> is not supplied,
  24053. the default channel is used. To use remote functions in the installer
  24054. that require any kind of privileges, you need to log in first. The
  24055. username and password you enter here will be stored in your per-user
  24056. PEAR configuration (~/.pearrc on Unix-like systems). After logging
  24057. in, your username and password will be sent along in subsequent
  24058. operations on the remote server.',
  24059. ),
  24060. 'logout' => array(
  24061. 'summary' => 'Logs out from the remote server [Deprecated in favor of channel-logout]',
  24062. 'shortcut' => 'lo',
  24063. 'function' => 'doLogout',
  24064. 'options' => array(),
  24065. 'doc' => '
  24066. WARNING: This function is deprecated in favor of using channel-logout
  24067. Logs out from the remote server. This command does not actually
  24068. connect to the remote server, it only deletes the stored username and
  24069. password from your user configuration.',
  24070. )
  24071. );
  24072. /**
  24073. * PEAR_Command_Auth constructor.
  24074. *
  24075. * @access public
  24076. */
  24077. function __construct(&$ui, &$config)
  24078. {
  24079. parent::__construct($ui, $config);
  24080. }
  24081. }
  24082. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Build.xml�����������������������������������������������������������������0000644�0001750�0001750�00000000604�13565304531�016144� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  24083. <build>
  24084. <summary>Build an Extension From C Source</summary>
  24085. <function>doBuild</function>
  24086. <shortcut>b</shortcut>
  24087. <options>
  24088. <configureoptions>
  24089. <shortopt>D</shortopt>
  24090. <arg>OPTION1=VALUE[ OPTION2=VALUE]</arg>
  24091. </configureoptions>
  24092. </options>
  24093. <doc>[package.xml]
  24094. Builds one or more extensions contained in a package.</doc>
  24095. </build>
  24096. </commands>����������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Build.php�����������������������������������������������������������������0000644�0001750�0001750�00000005123�13565304531�016134� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  24097. /**
  24098. * PEAR_Command_Auth (build command)
  24099. *
  24100. * PHP versions 4 and 5
  24101. *
  24102. * @category pear
  24103. * @package PEAR
  24104. * @author Stig Bakken <ssb@php.net>
  24105. * @author Tomas V.V.Cox <cox@idecnet.com>
  24106. * @author Greg Beaver <cellog@php.net>
  24107. * @copyright 1997-2009 The Authors
  24108. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  24109. * @link http://pear.php.net/package/PEAR
  24110. * @since File available since Release 0.1
  24111. */
  24112. /**
  24113. * base class
  24114. */
  24115. require_once 'PEAR/Command/Common.php';
  24116. /**
  24117. * PEAR commands for building extensions.
  24118. *
  24119. * @category pear
  24120. * @package PEAR
  24121. * @author Stig Bakken <ssb@php.net>
  24122. * @author Tomas V.V.Cox <cox@idecnet.com>
  24123. * @author Greg Beaver <cellog@php.net>
  24124. * @copyright 1997-2009 The Authors
  24125. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  24126. * @version Release: 1.10.10
  24127. * @link http://pear.php.net/package/PEAR
  24128. * @since Class available since Release 0.1
  24129. */
  24130. class PEAR_Command_Build extends PEAR_Command_Common
  24131. {
  24132. var $commands = array(
  24133. 'build' => array(
  24134. 'summary' => 'Build an Extension From C Source',
  24135. 'function' => 'doBuild',
  24136. 'shortcut' => 'b',
  24137. 'options' => array(
  24138. 'configureoptions' => array(
  24139. 'shortopt' => 'D',
  24140. 'arg' => 'OPTION1=VALUE[ OPTION2=VALUE]',
  24141. 'doc' => 'space-delimited list of configure options',
  24142. ),
  24143. ),
  24144. 'doc' => '[package.xml]
  24145. Builds one or more extensions contained in a package.'
  24146. ),
  24147. );
  24148. /**
  24149. * PEAR_Command_Build constructor.
  24150. *
  24151. * @access public
  24152. */
  24153. function __construct(&$ui, &$config)
  24154. {
  24155. parent::__construct($ui, $config);
  24156. }
  24157. function doBuild($command, $options, $params)
  24158. {
  24159. require_once 'PEAR/Builder.php';
  24160. if (sizeof($params) < 1) {
  24161. $params[0] = 'package.xml';
  24162. }
  24163. $configureoptions = empty($options['configureoptions']) ? '' : $options['configureoptions'];
  24164. $builder = new PEAR_Builder($configureoptions, $this->ui);
  24165. $this->debug = $this->config->get('verbose');
  24166. $err = $builder->build($params[0], array(&$this, 'buildCallback'));
  24167. if (PEAR::isError($err)) {
  24168. return $err;
  24169. }
  24170. return true;
  24171. }
  24172. function buildCallback($what, $data)
  24173. {
  24174. if (($what == 'cmdoutput' && $this->debug > 1) ||
  24175. ($what == 'output' && $this->debug > 0)) {
  24176. $this->ui->outputData(rtrim($data), 'build');
  24177. }
  24178. }
  24179. }
  24180. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Channels.xml��������������������������������������������������������������0000644�0001750�0001750�00000010172�13565304531�016641� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  24181. <list-channels>
  24182. <summary>List Available Channels</summary>
  24183. <function>doList</function>
  24184. <shortcut>lc</shortcut>
  24185. <options />
  24186. <doc>
  24187. List all available channels for installation.
  24188. </doc>
  24189. </list-channels>
  24190. <update-channels>
  24191. <summary>Update the Channel List</summary>
  24192. <function>doUpdateAll</function>
  24193. <shortcut>uc</shortcut>
  24194. <options />
  24195. <doc>
  24196. List all installed packages in all channels.
  24197. </doc>
  24198. </update-channels>
  24199. <channel-delete>
  24200. <summary>Remove a Channel From the List</summary>
  24201. <function>doDelete</function>
  24202. <shortcut>cde</shortcut>
  24203. <options />
  24204. <doc>&lt;channel name&gt;
  24205. Delete a channel from the registry. You may not
  24206. remove any channel that has installed packages.
  24207. </doc>
  24208. </channel-delete>
  24209. <channel-add>
  24210. <summary>Add a Channel</summary>
  24211. <function>doAdd</function>
  24212. <shortcut>ca</shortcut>
  24213. <options />
  24214. <doc>&lt;channel.xml&gt;
  24215. Add a private channel to the channel list. Note that all
  24216. public channels should be synced using &quot;update-channels&quot;.
  24217. Parameter may be either a local file or remote URL to a
  24218. channel.xml.
  24219. </doc>
  24220. </channel-add>
  24221. <channel-update>
  24222. <summary>Update an Existing Channel</summary>
  24223. <function>doUpdate</function>
  24224. <shortcut>cu</shortcut>
  24225. <options>
  24226. <force>
  24227. <shortopt>f</shortopt>
  24228. <doc>will force download of new channel.xml if an existing channel name is used</doc>
  24229. </force>
  24230. <channel>
  24231. <shortopt>c</shortopt>
  24232. <doc>will force download of new channel.xml if an existing channel name is used</doc>
  24233. <arg>CHANNEL</arg>
  24234. </channel>
  24235. </options>
  24236. <doc>[&lt;channel.xml&gt;|&lt;channel name&gt;]
  24237. Update a channel in the channel list directly. Note that all
  24238. public channels can be synced using &quot;update-channels&quot;.
  24239. Parameter may be a local or remote channel.xml, or the name of
  24240. an existing channel.
  24241. </doc>
  24242. </channel-update>
  24243. <channel-info>
  24244. <summary>Retrieve Information on a Channel</summary>
  24245. <function>doInfo</function>
  24246. <shortcut>ci</shortcut>
  24247. <options />
  24248. <doc>&lt;package&gt;
  24249. List the files in an installed package.
  24250. </doc>
  24251. </channel-info>
  24252. <channel-alias>
  24253. <summary>Specify an alias to a channel name</summary>
  24254. <function>doAlias</function>
  24255. <shortcut>cha</shortcut>
  24256. <options />
  24257. <doc>&lt;channel&gt; &lt;alias&gt;
  24258. Specify a specific alias to use for a channel name.
  24259. The alias may not be an existing channel name or
  24260. alias.
  24261. </doc>
  24262. </channel-alias>
  24263. <channel-discover>
  24264. <summary>Initialize a Channel from its server</summary>
  24265. <function>doDiscover</function>
  24266. <shortcut>di</shortcut>
  24267. <options />
  24268. <doc>[&lt;channel.xml&gt;|&lt;channel name&gt;]
  24269. Initialize a channel from its server and create a local channel.xml.
  24270. If &lt;channel name&gt; is in the format &quot;&lt;username&gt;:&lt;password&gt;@&lt;channel&gt;&quot; then
  24271. &lt;username&gt; and &lt;password&gt; will be set as the login username/password for
  24272. &lt;channel&gt;. Use caution when passing the username/password in this way, as
  24273. it may allow other users on your computer to briefly view your username/
  24274. password via the system&#039;s process list.
  24275. </doc>
  24276. </channel-discover>
  24277. <channel-login>
  24278. <summary>Connects and authenticates to remote channel server</summary>
  24279. <function>doLogin</function>
  24280. <shortcut>cli</shortcut>
  24281. <options />
  24282. <doc>&lt;channel name&gt;
  24283. Log in to a remote channel server. If &lt;channel name&gt; is not supplied,
  24284. the default channel is used. To use remote functions in the installer
  24285. that require any kind of privileges, you need to log in first. The
  24286. username and password you enter here will be stored in your per-user
  24287. PEAR configuration (~/.pearrc on Unix-like systems). After logging
  24288. in, your username and password will be sent along in subsequent
  24289. operations on the remote server.</doc>
  24290. </channel-login>
  24291. <channel-logout>
  24292. <summary>Logs out from the remote channel server</summary>
  24293. <function>doLogout</function>
  24294. <shortcut>clo</shortcut>
  24295. <options />
  24296. <doc>&lt;channel name&gt;
  24297. Logs out from a remote channel server. If &lt;channel name&gt; is not supplied,
  24298. the default channel is used. This command does not actually connect to the
  24299. remote server, it only deletes the stored username and password from your user
  24300. configuration.</doc>
  24301. </channel-logout>
  24302. </commands>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Channels.php��������������������������������������������������������������0000644�0001750�0001750�00000101245�13565304531�016632� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  24303. // /* vim: set expandtab tabstop=4 shiftwidth=4: */
  24304. /**
  24305. * PEAR_Command_Channels (list-channels, update-channels, channel-delete, channel-add,
  24306. * channel-update, channel-info, channel-alias, channel-discover commands)
  24307. *
  24308. * PHP versions 4 and 5
  24309. *
  24310. * @category pear
  24311. * @package PEAR
  24312. * @author Stig Bakken <ssb@php.net>
  24313. * @author Greg Beaver <cellog@php.net>
  24314. * @copyright 1997-2009 The Authors
  24315. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  24316. * @link http://pear.php.net/package/PEAR
  24317. * @since File available since Release 1.4.0a1
  24318. */
  24319. /**
  24320. * base class
  24321. */
  24322. require_once 'PEAR/Command/Common.php';
  24323. define('PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS', -500);
  24324. /**
  24325. * PEAR commands for managing channels.
  24326. *
  24327. * @category pear
  24328. * @package PEAR
  24329. * @author Greg Beaver <cellog@php.net>
  24330. * @copyright 1997-2009 The Authors
  24331. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  24332. * @version Release: 1.10.10
  24333. * @link http://pear.php.net/package/PEAR
  24334. * @since Class available since Release 1.4.0a1
  24335. */
  24336. class PEAR_Command_Channels extends PEAR_Command_Common
  24337. {
  24338. var $commands = array(
  24339. 'list-channels' => array(
  24340. 'summary' => 'List Available Channels',
  24341. 'function' => 'doList',
  24342. 'shortcut' => 'lc',
  24343. 'options' => array(),
  24344. 'doc' => '
  24345. List all available channels for installation.
  24346. ',
  24347. ),
  24348. 'update-channels' => array(
  24349. 'summary' => 'Update the Channel List',
  24350. 'function' => 'doUpdateAll',
  24351. 'shortcut' => 'uc',
  24352. 'options' => array(),
  24353. 'doc' => '
  24354. List all installed packages in all channels.
  24355. '
  24356. ),
  24357. 'channel-delete' => array(
  24358. 'summary' => 'Remove a Channel From the List',
  24359. 'function' => 'doDelete',
  24360. 'shortcut' => 'cde',
  24361. 'options' => array(),
  24362. 'doc' => '<channel name>
  24363. Delete a channel from the registry. You may not
  24364. remove any channel that has installed packages.
  24365. '
  24366. ),
  24367. 'channel-add' => array(
  24368. 'summary' => 'Add a Channel',
  24369. 'function' => 'doAdd',
  24370. 'shortcut' => 'ca',
  24371. 'options' => array(),
  24372. 'doc' => '<channel.xml>
  24373. Add a private channel to the channel list. Note that all
  24374. public channels should be synced using "update-channels".
  24375. Parameter may be either a local file or remote URL to a
  24376. channel.xml.
  24377. '
  24378. ),
  24379. 'channel-update' => array(
  24380. 'summary' => 'Update an Existing Channel',
  24381. 'function' => 'doUpdate',
  24382. 'shortcut' => 'cu',
  24383. 'options' => array(
  24384. 'force' => array(
  24385. 'shortopt' => 'f',
  24386. 'doc' => 'will force download of new channel.xml if an existing channel name is used',
  24387. ),
  24388. 'channel' => array(
  24389. 'shortopt' => 'c',
  24390. 'arg' => 'CHANNEL',
  24391. 'doc' => 'will force download of new channel.xml if an existing channel name is used',
  24392. ),
  24393. ),
  24394. 'doc' => '[<channel.xml>|<channel name>]
  24395. Update a channel in the channel list directly. Note that all
  24396. public channels can be synced using "update-channels".
  24397. Parameter may be a local or remote channel.xml, or the name of
  24398. an existing channel.
  24399. '
  24400. ),
  24401. 'channel-info' => array(
  24402. 'summary' => 'Retrieve Information on a Channel',
  24403. 'function' => 'doInfo',
  24404. 'shortcut' => 'ci',
  24405. 'options' => array(),
  24406. 'doc' => '<package>
  24407. List the files in an installed package.
  24408. '
  24409. ),
  24410. 'channel-alias' => array(
  24411. 'summary' => 'Specify an alias to a channel name',
  24412. 'function' => 'doAlias',
  24413. 'shortcut' => 'cha',
  24414. 'options' => array(),
  24415. 'doc' => '<channel> <alias>
  24416. Specify a specific alias to use for a channel name.
  24417. The alias may not be an existing channel name or
  24418. alias.
  24419. '
  24420. ),
  24421. 'channel-discover' => array(
  24422. 'summary' => 'Initialize a Channel from its server',
  24423. 'function' => 'doDiscover',
  24424. 'shortcut' => 'di',
  24425. 'options' => array(),
  24426. 'doc' => '[<channel.xml>|<channel name>]
  24427. Initialize a channel from its server and create a local channel.xml.
  24428. If <channel name> is in the format "<username>:<password>@<channel>" then
  24429. <username> and <password> will be set as the login username/password for
  24430. <channel>. Use caution when passing the username/password in this way, as
  24431. it may allow other users on your computer to briefly view your username/
  24432. password via the system\'s process list.
  24433. '
  24434. ),
  24435. 'channel-login' => array(
  24436. 'summary' => 'Connects and authenticates to remote channel server',
  24437. 'shortcut' => 'cli',
  24438. 'function' => 'doLogin',
  24439. 'options' => array(),
  24440. 'doc' => '<channel name>
  24441. Log in to a remote channel server. If <channel name> is not supplied,
  24442. the default channel is used. To use remote functions in the installer
  24443. that require any kind of privileges, you need to log in first. The
  24444. username and password you enter here will be stored in your per-user
  24445. PEAR configuration (~/.pearrc on Unix-like systems). After logging
  24446. in, your username and password will be sent along in subsequent
  24447. operations on the remote server.',
  24448. ),
  24449. 'channel-logout' => array(
  24450. 'summary' => 'Logs out from the remote channel server',
  24451. 'shortcut' => 'clo',
  24452. 'function' => 'doLogout',
  24453. 'options' => array(),
  24454. 'doc' => '<channel name>
  24455. Logs out from a remote channel server. If <channel name> is not supplied,
  24456. the default channel is used. This command does not actually connect to the
  24457. remote server, it only deletes the stored username and password from your user
  24458. configuration.',
  24459. ),
  24460. );
  24461. /**
  24462. * PEAR_Command_Registry constructor.
  24463. *
  24464. * @access public
  24465. */
  24466. function __construct(&$ui, &$config)
  24467. {
  24468. parent::__construct($ui, $config);
  24469. }
  24470. function _sortChannels($a, $b)
  24471. {
  24472. return strnatcasecmp($a->getName(), $b->getName());
  24473. }
  24474. function doList($command, $options, $params)
  24475. {
  24476. $reg = &$this->config->getRegistry();
  24477. $registered = $reg->getChannels();
  24478. usort($registered, array(&$this, '_sortchannels'));
  24479. $i = $j = 0;
  24480. $data = array(
  24481. 'caption' => 'Registered Channels:',
  24482. 'border' => true,
  24483. 'headline' => array('Channel', 'Alias', 'Summary')
  24484. );
  24485. foreach ($registered as $channel) {
  24486. $data['data'][] = array($channel->getName(),
  24487. $channel->getAlias(),
  24488. $channel->getSummary());
  24489. }
  24490. if (count($registered) === 0) {
  24491. $data = '(no registered channels)';
  24492. }
  24493. $this->ui->outputData($data, $command);
  24494. return true;
  24495. }
  24496. function doUpdateAll($command, $options, $params)
  24497. {
  24498. $reg = &$this->config->getRegistry();
  24499. $channels = $reg->getChannels();
  24500. $success = true;
  24501. foreach ($channels as $channel) {
  24502. if ($channel->getName() != '__uri') {
  24503. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24504. $err = $this->doUpdate('channel-update',
  24505. $options,
  24506. array($channel->getName()));
  24507. if (PEAR::isError($err)) {
  24508. $this->ui->outputData($err->getMessage(), $command);
  24509. $success = false;
  24510. } else {
  24511. $success &= $err;
  24512. }
  24513. }
  24514. }
  24515. return $success;
  24516. }
  24517. function doInfo($command, $options, $params)
  24518. {
  24519. if (count($params) !== 1) {
  24520. return $this->raiseError("No channel specified");
  24521. }
  24522. $reg = &$this->config->getRegistry();
  24523. $channel = strtolower($params[0]);
  24524. if ($reg->channelExists($channel)) {
  24525. $chan = $reg->getChannel($channel);
  24526. if (PEAR::isError($chan)) {
  24527. return $this->raiseError($chan);
  24528. }
  24529. } else {
  24530. if (strpos($channel, '://')) {
  24531. $downloader = &$this->getDownloader();
  24532. $tmpdir = $this->config->get('temp_dir');
  24533. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24534. $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
  24535. PEAR::staticPopErrorHandling();
  24536. if (PEAR::isError($loc)) {
  24537. return $this->raiseError('Cannot open "' . $channel .
  24538. '" (' . $loc->getMessage() . ')');
  24539. } else {
  24540. $contents = implode('', file($loc));
  24541. }
  24542. } else {
  24543. if (!file_exists($params[0])) {
  24544. return $this->raiseError('Unknown channel "' . $channel . '"');
  24545. }
  24546. $fp = fopen($params[0], 'r');
  24547. if (!$fp) {
  24548. return $this->raiseError('Cannot open "' . $params[0] . '"');
  24549. }
  24550. $contents = '';
  24551. while (!feof($fp)) {
  24552. $contents .= fread($fp, 1024);
  24553. }
  24554. fclose($fp);
  24555. }
  24556. if (!class_exists('PEAR_ChannelFile')) {
  24557. require_once 'PEAR/ChannelFile.php';
  24558. }
  24559. $chan = new PEAR_ChannelFile;
  24560. $chan->fromXmlString($contents);
  24561. $chan->validate();
  24562. if ($errs = $chan->getErrors(true)) {
  24563. foreach ($errs as $err) {
  24564. $this->ui->outputData($err['level'] . ': ' . $err['message']);
  24565. }
  24566. return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
  24567. }
  24568. }
  24569. if (!$chan) {
  24570. return $this->raiseError('Serious error: Channel "' . $params[0] .
  24571. '" has a corrupted registry entry');
  24572. }
  24573. $channel = $chan->getName();
  24574. $caption = 'Channel ' . $channel . ' Information:';
  24575. $data1 = array(
  24576. 'caption' => $caption,
  24577. 'border' => true);
  24578. $data1['data']['server'] = array('Name and Server', $chan->getName());
  24579. if ($chan->getAlias() != $chan->getName()) {
  24580. $data1['data']['alias'] = array('Alias', $chan->getAlias());
  24581. }
  24582. $data1['data']['summary'] = array('Summary', $chan->getSummary());
  24583. $validate = $chan->getValidationPackage();
  24584. $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
  24585. $data1['data']['vpackageversion'] =
  24586. array('Validation Package Version', $validate['attribs']['version']);
  24587. $d = array();
  24588. $d['main'] = $data1;
  24589. $data['data'] = array();
  24590. $data['caption'] = 'Server Capabilities';
  24591. $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  24592. if ($chan->supportsREST()) {
  24593. if ($chan->supportsREST()) {
  24594. $funcs = $chan->getFunctions('rest');
  24595. if (!isset($funcs[0])) {
  24596. $funcs = array($funcs);
  24597. }
  24598. foreach ($funcs as $protocol) {
  24599. $data['data'][] = array('rest', $protocol['attribs']['type'],
  24600. $protocol['_content']);
  24601. }
  24602. }
  24603. } else {
  24604. $data['data'][] = array('No supported protocols');
  24605. }
  24606. $d['protocols'] = $data;
  24607. $data['data'] = array();
  24608. $mirrors = $chan->getMirrors();
  24609. if ($mirrors) {
  24610. $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
  24611. unset($data['headline']);
  24612. foreach ($mirrors as $mirror) {
  24613. $data['data'][] = array($mirror['attribs']['host']);
  24614. $d['mirrors'] = $data;
  24615. }
  24616. foreach ($mirrors as $i => $mirror) {
  24617. $data['data'] = array();
  24618. $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
  24619. $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  24620. if ($chan->supportsREST($mirror['attribs']['host'])) {
  24621. if ($chan->supportsREST($mirror['attribs']['host'])) {
  24622. $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
  24623. if (!isset($funcs[0])) {
  24624. $funcs = array($funcs);
  24625. }
  24626. foreach ($funcs as $protocol) {
  24627. $data['data'][] = array('rest', $protocol['attribs']['type'],
  24628. $protocol['_content']);
  24629. }
  24630. }
  24631. } else {
  24632. $data['data'][] = array('No supported protocols');
  24633. }
  24634. $d['mirrorprotocols' . $i] = $data;
  24635. }
  24636. }
  24637. $this->ui->outputData($d, 'channel-info');
  24638. }
  24639. // }}}
  24640. function doDelete($command, $options, $params)
  24641. {
  24642. if (count($params) !== 1) {
  24643. return $this->raiseError('channel-delete: no channel specified');
  24644. }
  24645. $reg = &$this->config->getRegistry();
  24646. if (!$reg->channelExists($params[0])) {
  24647. return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
  24648. }
  24649. $channel = $reg->channelName($params[0]);
  24650. if ($channel == 'pear.php.net') {
  24651. return $this->raiseError('Cannot delete the pear.php.net channel');
  24652. }
  24653. if ($channel == 'pecl.php.net') {
  24654. return $this->raiseError('Cannot delete the pecl.php.net channel');
  24655. }
  24656. if ($channel == 'doc.php.net') {
  24657. return $this->raiseError('Cannot delete the doc.php.net channel');
  24658. }
  24659. if ($channel == '__uri') {
  24660. return $this->raiseError('Cannot delete the __uri pseudo-channel');
  24661. }
  24662. if (PEAR::isError($err = $reg->listPackages($channel))) {
  24663. return $err;
  24664. }
  24665. if (count($err)) {
  24666. return $this->raiseError('Channel "' . $channel .
  24667. '" has installed packages, cannot delete');
  24668. }
  24669. if (!$reg->deleteChannel($channel)) {
  24670. return $this->raiseError('Channel "' . $channel . '" deletion failed');
  24671. } else {
  24672. $this->config->deleteChannel($channel);
  24673. $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
  24674. }
  24675. }
  24676. function doAdd($command, $options, $params)
  24677. {
  24678. if (count($params) !== 1) {
  24679. return $this->raiseError('channel-add: no channel file specified');
  24680. }
  24681. if (strpos($params[0], '://')) {
  24682. $downloader = &$this->getDownloader();
  24683. $tmpdir = $this->config->get('temp_dir');
  24684. if (!file_exists($tmpdir)) {
  24685. require_once 'System.php';
  24686. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24687. $err = System::mkdir(array('-p', $tmpdir));
  24688. PEAR::staticPopErrorHandling();
  24689. if (PEAR::isError($err)) {
  24690. return $this->raiseError('channel-add: temp_dir does not exist: "' .
  24691. $tmpdir .
  24692. '" - You can change this location with "pear config-set temp_dir"');
  24693. }
  24694. }
  24695. if (!is_writable($tmpdir)) {
  24696. return $this->raiseError('channel-add: temp_dir is not writable: "' .
  24697. $tmpdir .
  24698. '" - You can change this location with "pear config-set temp_dir"');
  24699. }
  24700. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24701. $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
  24702. PEAR::staticPopErrorHandling();
  24703. if (PEAR::isError($loc)) {
  24704. return $this->raiseError('channel-add: Cannot open "' . $params[0] .
  24705. '" (' . $loc->getMessage() . ')');
  24706. }
  24707. list($loc, $lastmodified) = $loc;
  24708. $contents = implode('', file($loc));
  24709. } else {
  24710. $lastmodified = $fp = false;
  24711. if (file_exists($params[0])) {
  24712. $fp = fopen($params[0], 'r');
  24713. }
  24714. if (!$fp) {
  24715. return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
  24716. }
  24717. $contents = '';
  24718. while (!feof($fp)) {
  24719. $contents .= fread($fp, 1024);
  24720. }
  24721. fclose($fp);
  24722. }
  24723. if (!class_exists('PEAR_ChannelFile')) {
  24724. require_once 'PEAR/ChannelFile.php';
  24725. }
  24726. $channel = new PEAR_ChannelFile;
  24727. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24728. $result = $channel->fromXmlString($contents);
  24729. PEAR::staticPopErrorHandling();
  24730. if (!$result) {
  24731. $exit = false;
  24732. if (count($errors = $channel->getErrors(true))) {
  24733. foreach ($errors as $error) {
  24734. $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  24735. if (!$exit) {
  24736. $exit = $error['level'] == 'error' ? true : false;
  24737. }
  24738. }
  24739. if ($exit) {
  24740. return $this->raiseError('channel-add: invalid channel.xml file');
  24741. }
  24742. }
  24743. }
  24744. $reg = &$this->config->getRegistry();
  24745. if ($reg->channelExists($channel->getName())) {
  24746. return $this->raiseError('channel-add: Channel "' . $channel->getName() .
  24747. '" exists, use channel-update to update entry', PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS);
  24748. }
  24749. $ret = $reg->addChannel($channel, $lastmodified);
  24750. if (PEAR::isError($ret)) {
  24751. return $ret;
  24752. }
  24753. if (!$ret) {
  24754. return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
  24755. '" to registry failed');
  24756. }
  24757. $this->config->setChannels($reg->listChannels());
  24758. $this->config->writeConfigFile();
  24759. $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
  24760. }
  24761. function doUpdate($command, $options, $params)
  24762. {
  24763. if (count($params) !== 1) {
  24764. return $this->raiseError("No channel file specified");
  24765. }
  24766. $tmpdir = $this->config->get('temp_dir');
  24767. if (!file_exists($tmpdir)) {
  24768. require_once 'System.php';
  24769. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24770. $err = System::mkdir(array('-p', $tmpdir));
  24771. PEAR::staticPopErrorHandling();
  24772. if (PEAR::isError($err)) {
  24773. return $this->raiseError('channel-add: temp_dir does not exist: "' .
  24774. $tmpdir .
  24775. '" - You can change this location with "pear config-set temp_dir"');
  24776. }
  24777. }
  24778. if (!is_writable($tmpdir)) {
  24779. return $this->raiseError('channel-add: temp_dir is not writable: "' .
  24780. $tmpdir .
  24781. '" - You can change this location with "pear config-set temp_dir"');
  24782. }
  24783. $reg = &$this->config->getRegistry();
  24784. $lastmodified = false;
  24785. if ((!file_exists($params[0]) || is_dir($params[0]))
  24786. && $reg->channelExists(strtolower($params[0]))) {
  24787. $c = $reg->getChannel(strtolower($params[0]));
  24788. if (PEAR::isError($c)) {
  24789. return $this->raiseError($c);
  24790. }
  24791. $this->ui->outputData("Updating channel \"$params[0]\"", $command);
  24792. $dl = &$this->getDownloader(array());
  24793. // if force is specified, use a timestamp of "1" to force retrieval
  24794. $lastmodified = isset($options['force']) ? false : $c->lastModified();
  24795. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24796. $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
  24797. $this->ui, $tmpdir, null, $lastmodified);
  24798. PEAR::staticPopErrorHandling();
  24799. if (PEAR::isError($contents)) {
  24800. // Attempt to fall back to https
  24801. $this->ui->outputData("Channel \"$params[0]\" is not responding over http://, failed with message: " . $contents->getMessage());
  24802. $this->ui->outputData("Trying channel \"$params[0]\" over https:// instead");
  24803. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24804. $contents = $dl->downloadHttp('https://' . $c->getName() . '/channel.xml',
  24805. $this->ui, $tmpdir, null, $lastmodified);
  24806. PEAR::staticPopErrorHandling();
  24807. if (PEAR::isError($contents)) {
  24808. return $this->raiseError('Cannot retrieve channel.xml for channel "' .
  24809. $c->getName() . '" (' . $contents->getMessage() . ')');
  24810. }
  24811. }
  24812. list($contents, $lastmodified) = $contents;
  24813. if (!$contents) {
  24814. $this->ui->outputData("Channel \"$params[0]\" is up to date");
  24815. return;
  24816. }
  24817. $contents = implode('', file($contents));
  24818. if (!class_exists('PEAR_ChannelFile')) {
  24819. require_once 'PEAR/ChannelFile.php';
  24820. }
  24821. $channel = new PEAR_ChannelFile;
  24822. $channel->fromXmlString($contents);
  24823. if (!$channel->getErrors()) {
  24824. // security check: is the downloaded file for the channel we got it from?
  24825. if (strtolower($channel->getName()) != strtolower($c->getName())) {
  24826. if (!isset($options['force'])) {
  24827. return $this->raiseError('ERROR: downloaded channel definition file' .
  24828. ' for channel "' . $channel->getName() . '" from channel "' .
  24829. strtolower($c->getName()) . '"');
  24830. }
  24831. $this->ui->log(0, 'WARNING: downloaded channel definition file' .
  24832. ' for channel "' . $channel->getName() . '" from channel "' .
  24833. strtolower($c->getName()) . '"');
  24834. }
  24835. }
  24836. } else {
  24837. if (strpos($params[0], '://')) {
  24838. $dl = &$this->getDownloader();
  24839. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24840. $loc = $dl->downloadHttp($params[0],
  24841. $this->ui, $tmpdir, null, $lastmodified);
  24842. PEAR::staticPopErrorHandling();
  24843. if (PEAR::isError($loc)) {
  24844. return $this->raiseError("Cannot open " . $params[0] .
  24845. ' (' . $loc->getMessage() . ')');
  24846. }
  24847. list($loc, $lastmodified) = $loc;
  24848. $contents = implode('', file($loc));
  24849. } else {
  24850. $fp = false;
  24851. if (file_exists($params[0])) {
  24852. $fp = fopen($params[0], 'r');
  24853. }
  24854. if (!$fp) {
  24855. return $this->raiseError("Cannot open " . $params[0]);
  24856. }
  24857. $contents = '';
  24858. while (!feof($fp)) {
  24859. $contents .= fread($fp, 1024);
  24860. }
  24861. fclose($fp);
  24862. }
  24863. if (!class_exists('PEAR_ChannelFile')) {
  24864. require_once 'PEAR/ChannelFile.php';
  24865. }
  24866. $channel = new PEAR_ChannelFile;
  24867. $channel->fromXmlString($contents);
  24868. }
  24869. $exit = false;
  24870. if (count($errors = $channel->getErrors(true))) {
  24871. foreach ($errors as $error) {
  24872. $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  24873. if (!$exit) {
  24874. $exit = $error['level'] == 'error' ? true : false;
  24875. }
  24876. }
  24877. if ($exit) {
  24878. return $this->raiseError('Invalid channel.xml file');
  24879. }
  24880. }
  24881. if (!$reg->channelExists($channel->getName())) {
  24882. return $this->raiseError('Error: Channel "' . $channel->getName() .
  24883. '" does not exist, use channel-add to add an entry');
  24884. }
  24885. $ret = $reg->updateChannel($channel, $lastmodified);
  24886. if (PEAR::isError($ret)) {
  24887. return $ret;
  24888. }
  24889. if (!$ret) {
  24890. return $this->raiseError('Updating Channel "' . $channel->getName() .
  24891. '" in registry failed');
  24892. }
  24893. $this->config->setChannels($reg->listChannels());
  24894. $this->config->writeConfigFile();
  24895. $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
  24896. }
  24897. function &getDownloader()
  24898. {
  24899. if (!class_exists('PEAR_Downloader')) {
  24900. require_once 'PEAR/Downloader.php';
  24901. }
  24902. $a = new PEAR_Downloader($this->ui, array(), $this->config);
  24903. return $a;
  24904. }
  24905. function doAlias($command, $options, $params)
  24906. {
  24907. if (count($params) === 1) {
  24908. return $this->raiseError('No channel alias specified');
  24909. }
  24910. if (count($params) !== 2 || (!empty($params[1]) && $params[1][0] == '-')) {
  24911. return $this->raiseError(
  24912. 'Invalid format, correct is: channel-alias channel alias');
  24913. }
  24914. $reg = &$this->config->getRegistry();
  24915. if (!$reg->channelExists($params[0], true)) {
  24916. $extra = '';
  24917. if ($reg->isAlias($params[0])) {
  24918. $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
  24919. strtolower($params[1]) . '")';
  24920. }
  24921. return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
  24922. }
  24923. if ($reg->isAlias($params[1])) {
  24924. return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
  24925. 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
  24926. }
  24927. $chan = $reg->getChannel($params[0]);
  24928. if (PEAR::isError($chan)) {
  24929. return $this->raiseError('Corrupt registry? Error retrieving channel "' . $params[0] .
  24930. '" information (' . $chan->getMessage() . ')');
  24931. }
  24932. // make it a local alias
  24933. if (!$chan->setAlias(strtolower($params[1]), true)) {
  24934. return $this->raiseError('Alias "' . strtolower($params[1]) .
  24935. '" is not a valid channel alias');
  24936. }
  24937. $reg->updateChannel($chan);
  24938. $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
  24939. strtolower($params[1]) . '"');
  24940. }
  24941. /**
  24942. * The channel-discover command
  24943. *
  24944. * @param string $command command name
  24945. * @param array $options option_name => value
  24946. * @param array $params list of additional parameters.
  24947. * $params[0] should contain a string with either:
  24948. * - <channel name> or
  24949. * - <username>:<password>@<channel name>
  24950. * @return null|PEAR_Error
  24951. */
  24952. function doDiscover($command, $options, $params)
  24953. {
  24954. if (count($params) !== 1) {
  24955. return $this->raiseError("No channel server specified");
  24956. }
  24957. // Look for the possible input format "<username>:<password>@<channel>"
  24958. if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) {
  24959. $username = $matches[1];
  24960. $password = $matches[2];
  24961. $channel = $matches[3];
  24962. } else {
  24963. $channel = $params[0];
  24964. }
  24965. $reg = &$this->config->getRegistry();
  24966. if ($reg->channelExists($channel)) {
  24967. if (!$reg->isAlias($channel)) {
  24968. return $this->raiseError("Channel \"$channel\" is already initialized", PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS);
  24969. }
  24970. return $this->raiseError("A channel alias named \"$channel\" " .
  24971. 'already exists, aliasing channel "' . $reg->channelName($channel)
  24972. . '"');
  24973. }
  24974. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  24975. $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml'));
  24976. $this->popErrorHandling();
  24977. if (PEAR::isError($err)) {
  24978. if ($err->getCode() === PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS) {
  24979. return $this->raiseError("Discovery of channel \"$channel\" failed (" .
  24980. $err->getMessage() . ')');
  24981. }
  24982. // Attempt fetch via https
  24983. $this->ui->outputData("Discovering channel $channel over http:// failed with message: " . $err->getMessage());
  24984. $this->ui->outputData("Trying to discover channel $channel over https:// instead");
  24985. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  24986. $err = $this->doAdd($command, $options, array('https://' . $channel . '/channel.xml'));
  24987. $this->popErrorHandling();
  24988. if (PEAR::isError($err)) {
  24989. return $this->raiseError("Discovery of channel \"$channel\" failed (" .
  24990. $err->getMessage() . ')');
  24991. }
  24992. }
  24993. // Store username/password if they were given
  24994. // Arguably we should do a logintest on the channel here, but since
  24995. // that's awkward on a REST-based channel (even "pear login" doesn't
  24996. // do it for those), and XML-RPC is deprecated, it's fairly pointless.
  24997. if (isset($username)) {
  24998. $this->config->set('username', $username, 'user', $channel);
  24999. $this->config->set('password', $password, 'user', $channel);
  25000. $this->config->store();
  25001. $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command);
  25002. }
  25003. $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command);
  25004. }
  25005. /**
  25006. * Execute the 'login' command.
  25007. *
  25008. * @param string $command command name
  25009. * @param array $options option_name => value
  25010. * @param array $params list of additional parameters
  25011. *
  25012. * @return bool TRUE on success or
  25013. * a PEAR error on failure
  25014. *
  25015. * @access public
  25016. */
  25017. function doLogin($command, $options, $params)
  25018. {
  25019. $reg = &$this->config->getRegistry();
  25020. // If a parameter is supplied, use that as the channel to log in to
  25021. $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel');
  25022. $chan = $reg->getChannel($channel);
  25023. if (PEAR::isError($chan)) {
  25024. return $this->raiseError($chan);
  25025. }
  25026. $server = $this->config->get('preferred_mirror', null, $channel);
  25027. $username = $this->config->get('username', null, $channel);
  25028. if (empty($username)) {
  25029. $username = isset($_ENV['USER']) ? $_ENV['USER'] : null;
  25030. }
  25031. $this->ui->outputData("Logging in to $server.", $command);
  25032. list($username, $password) = $this->ui->userDialog(
  25033. $command,
  25034. array('Username', 'Password'),
  25035. array('text', 'password'),
  25036. array($username, '')
  25037. );
  25038. $username = trim($username);
  25039. $password = trim($password);
  25040. $ourfile = $this->config->getConfFile('user');
  25041. if (!$ourfile) {
  25042. $ourfile = $this->config->getConfFile('system');
  25043. }
  25044. $this->config->set('username', $username, 'user', $channel);
  25045. $this->config->set('password', $password, 'user', $channel);
  25046. if ($chan->supportsREST()) {
  25047. $ok = true;
  25048. }
  25049. if ($ok !== true) {
  25050. return $this->raiseError('Login failed!');
  25051. }
  25052. $this->ui->outputData("Logged in.", $command);
  25053. // avoid changing any temporary settings changed with -d
  25054. $ourconfig = new PEAR_Config($ourfile, $ourfile);
  25055. $ourconfig->set('username', $username, 'user', $channel);
  25056. $ourconfig->set('password', $password, 'user', $channel);
  25057. $ourconfig->store();
  25058. return true;
  25059. }
  25060. /**
  25061. * Execute the 'logout' command.
  25062. *
  25063. * @param string $command command name
  25064. * @param array $options option_name => value
  25065. * @param array $params list of additional parameters
  25066. *
  25067. * @return bool TRUE on success or
  25068. * a PEAR error on failure
  25069. *
  25070. * @access public
  25071. */
  25072. function doLogout($command, $options, $params)
  25073. {
  25074. $reg = &$this->config->getRegistry();
  25075. // If a parameter is supplied, use that as the channel to log in to
  25076. $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel');
  25077. $chan = $reg->getChannel($channel);
  25078. if (PEAR::isError($chan)) {
  25079. return $this->raiseError($chan);
  25080. }
  25081. $server = $this->config->get('preferred_mirror', null, $channel);
  25082. $this->ui->outputData("Logging out from $server.", $command);
  25083. $this->config->remove('username', 'user', $channel);
  25084. $this->config->remove('password', 'user', $channel);
  25085. $this->config->store();
  25086. return true;
  25087. }
  25088. }
  25089. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Common.php����������������������������������������������������������������0000644�0001750�0001750�00000020026�13565304531�016324� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  25090. /**
  25091. * PEAR_Command_Common base class
  25092. *
  25093. * PHP versions 4 and 5
  25094. *
  25095. * @category pear
  25096. * @package PEAR
  25097. * @author Stig Bakken <ssb@php.net>
  25098. * @author Greg Beaver <cellog@php.net>
  25099. * @copyright 1997-2009 The Authors
  25100. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  25101. * @link http://pear.php.net/package/PEAR
  25102. * @since File available since Release 0.1
  25103. */
  25104. /**
  25105. * base class
  25106. */
  25107. require_once 'PEAR.php';
  25108. /**
  25109. * PEAR commands base class
  25110. *
  25111. * @category pear
  25112. * @package PEAR
  25113. * @author Stig Bakken <ssb@php.net>
  25114. * @author Greg Beaver <cellog@php.net>
  25115. * @copyright 1997-2009 The Authors
  25116. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  25117. * @version Release: 1.10.10
  25118. * @link http://pear.php.net/package/PEAR
  25119. * @since Class available since Release 0.1
  25120. */
  25121. class PEAR_Command_Common extends PEAR
  25122. {
  25123. /**
  25124. * PEAR_Config object used to pass user system and configuration
  25125. * on when executing commands
  25126. *
  25127. * @var PEAR_Config
  25128. */
  25129. var $config;
  25130. /**
  25131. * @var PEAR_Registry
  25132. * @access protected
  25133. */
  25134. var $_registry;
  25135. /**
  25136. * User Interface object, for all interaction with the user.
  25137. * @var object
  25138. */
  25139. var $ui;
  25140. var $_deps_rel_trans = array(
  25141. 'lt' => '<',
  25142. 'le' => '<=',
  25143. 'eq' => '=',
  25144. 'ne' => '!=',
  25145. 'gt' => '>',
  25146. 'ge' => '>=',
  25147. 'has' => '=='
  25148. );
  25149. var $_deps_type_trans = array(
  25150. 'pkg' => 'package',
  25151. 'ext' => 'extension',
  25152. 'php' => 'PHP',
  25153. 'prog' => 'external program',
  25154. 'ldlib' => 'external library for linking',
  25155. 'rtlib' => 'external runtime library',
  25156. 'os' => 'operating system',
  25157. 'websrv' => 'web server',
  25158. 'sapi' => 'SAPI backend'
  25159. );
  25160. /**
  25161. * PEAR_Command_Common constructor.
  25162. *
  25163. * @access public
  25164. */
  25165. function __construct(&$ui, &$config)
  25166. {
  25167. parent::__construct();
  25168. $this->config = &$config;
  25169. $this->ui = &$ui;
  25170. }
  25171. /**
  25172. * Return a list of all the commands defined by this class.
  25173. * @return array list of commands
  25174. * @access public
  25175. */
  25176. function getCommands()
  25177. {
  25178. $ret = array();
  25179. foreach (array_keys($this->commands) as $command) {
  25180. $ret[$command] = $this->commands[$command]['summary'];
  25181. }
  25182. return $ret;
  25183. }
  25184. /**
  25185. * Return a list of all the command shortcuts defined by this class.
  25186. * @return array shortcut => command
  25187. * @access public
  25188. */
  25189. function getShortcuts()
  25190. {
  25191. $ret = array();
  25192. foreach (array_keys($this->commands) as $command) {
  25193. if (isset($this->commands[$command]['shortcut'])) {
  25194. $ret[$this->commands[$command]['shortcut']] = $command;
  25195. }
  25196. }
  25197. return $ret;
  25198. }
  25199. function getOptions($command)
  25200. {
  25201. $shortcuts = $this->getShortcuts();
  25202. if (isset($shortcuts[$command])) {
  25203. $command = $shortcuts[$command];
  25204. }
  25205. if (isset($this->commands[$command]) &&
  25206. isset($this->commands[$command]['options'])) {
  25207. return $this->commands[$command]['options'];
  25208. }
  25209. return null;
  25210. }
  25211. function getGetoptArgs($command, &$short_args, &$long_args)
  25212. {
  25213. $short_args = '';
  25214. $long_args = array();
  25215. if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
  25216. return;
  25217. }
  25218. reset($this->commands[$command]['options']);
  25219. foreach ($this->commands[$command]['options'] as $option => $info) {
  25220. $larg = $sarg = '';
  25221. if (isset($info['arg'])) {
  25222. if ($info['arg'][0] == '(') {
  25223. $larg = '==';
  25224. $sarg = '::';
  25225. $arg = substr($info['arg'], 1, -1);
  25226. } else {
  25227. $larg = '=';
  25228. $sarg = ':';
  25229. $arg = $info['arg'];
  25230. }
  25231. }
  25232. if (isset($info['shortopt'])) {
  25233. $short_args .= $info['shortopt'] . $sarg;
  25234. }
  25235. $long_args[] = $option . $larg;
  25236. }
  25237. }
  25238. /**
  25239. * Returns the help message for the given command
  25240. *
  25241. * @param string $command The command
  25242. * @return mixed A fail string if the command does not have help or
  25243. * a two elements array containing [0]=>help string,
  25244. * [1]=> help string for the accepted cmd args
  25245. */
  25246. function getHelp($command)
  25247. {
  25248. $config = &PEAR_Config::singleton();
  25249. if (!isset($this->commands[$command])) {
  25250. return "No such command \"$command\"";
  25251. }
  25252. $help = null;
  25253. if (isset($this->commands[$command]['doc'])) {
  25254. $help = $this->commands[$command]['doc'];
  25255. }
  25256. if (empty($help)) {
  25257. // XXX (cox) Fallback to summary if there is no doc (show both?)
  25258. if (!isset($this->commands[$command]['summary'])) {
  25259. return "No help for command \"$command\"";
  25260. }
  25261. $help = $this->commands[$command]['summary'];
  25262. }
  25263. if (preg_match_all('/{config\s+([^\}]+)}/', $help, $matches)) {
  25264. foreach($matches[0] as $k => $v) {
  25265. $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
  25266. }
  25267. }
  25268. return array($help, $this->getHelpArgs($command));
  25269. }
  25270. /**
  25271. * Returns the help for the accepted arguments of a command
  25272. *
  25273. * @param string $command
  25274. * @return string The help string
  25275. */
  25276. function getHelpArgs($command)
  25277. {
  25278. if (isset($this->commands[$command]['options']) &&
  25279. count($this->commands[$command]['options']))
  25280. {
  25281. $help = "Options:\n";
  25282. foreach ($this->commands[$command]['options'] as $k => $v) {
  25283. if (isset($v['arg'])) {
  25284. if ($v['arg'][0] == '(') {
  25285. $arg = substr($v['arg'], 1, -1);
  25286. $sapp = " [$arg]";
  25287. $lapp = "[=$arg]";
  25288. } else {
  25289. $sapp = " $v[arg]";
  25290. $lapp = "=$v[arg]";
  25291. }
  25292. } else {
  25293. $sapp = $lapp = "";
  25294. }
  25295. if (isset($v['shortopt'])) {
  25296. $s = $v['shortopt'];
  25297. $help .= " -$s$sapp, --$k$lapp\n";
  25298. } else {
  25299. $help .= " --$k$lapp\n";
  25300. }
  25301. $p = " ";
  25302. $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
  25303. $help .= " $doc\n";
  25304. }
  25305. return $help;
  25306. }
  25307. return null;
  25308. }
  25309. function run($command, $options, $params)
  25310. {
  25311. if (empty($this->commands[$command]['function'])) {
  25312. // look for shortcuts
  25313. foreach (array_keys($this->commands) as $cmd) {
  25314. if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
  25315. if (empty($this->commands[$cmd]['function'])) {
  25316. return $this->raiseError("unknown command `$command'");
  25317. } else {
  25318. $func = $this->commands[$cmd]['function'];
  25319. }
  25320. $command = $cmd;
  25321. //$command = $this->commands[$cmd]['function'];
  25322. break;
  25323. }
  25324. }
  25325. } else {
  25326. $func = $this->commands[$command]['function'];
  25327. }
  25328. return $this->$func($command, $options, $params);
  25329. }
  25330. }
  25331. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Config.xml����������������������������������������������������������������0000644�0001750�0001750�00000006466�13565304531�016326� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  25332. <config-show>
  25333. <summary>Show All Settings</summary>
  25334. <function>doConfigShow</function>
  25335. <shortcut>csh</shortcut>
  25336. <options>
  25337. <channel>
  25338. <shortopt>c</shortopt>
  25339. <doc>show configuration variables for another channel</doc>
  25340. <arg>CHAN</arg>
  25341. </channel>
  25342. </options>
  25343. <doc>[layer]
  25344. Displays all configuration values. An optional argument
  25345. may be used to tell which configuration layer to display. Valid
  25346. configuration layers are &quot;user&quot;, &quot;system&quot; and &quot;default&quot;. To display
  25347. configurations for different channels, set the default_channel
  25348. configuration variable and run config-show again.
  25349. </doc>
  25350. </config-show>
  25351. <config-get>
  25352. <summary>Show One Setting</summary>
  25353. <function>doConfigGet</function>
  25354. <shortcut>cg</shortcut>
  25355. <options>
  25356. <channel>
  25357. <shortopt>c</shortopt>
  25358. <doc>show configuration variables for another channel</doc>
  25359. <arg>CHAN</arg>
  25360. </channel>
  25361. </options>
  25362. <doc>&lt;parameter&gt; [layer]
  25363. Displays the value of one configuration parameter. The
  25364. first argument is the name of the parameter, an optional second argument
  25365. may be used to tell which configuration layer to look in. Valid configuration
  25366. layers are &quot;user&quot;, &quot;system&quot; and &quot;default&quot;. If no layer is specified, a value
  25367. will be picked from the first layer that defines the parameter, in the order
  25368. just specified. The configuration value will be retrieved for the channel
  25369. specified by the default_channel configuration variable.
  25370. </doc>
  25371. </config-get>
  25372. <config-set>
  25373. <summary>Change Setting</summary>
  25374. <function>doConfigSet</function>
  25375. <shortcut>cs</shortcut>
  25376. <options>
  25377. <channel>
  25378. <shortopt>c</shortopt>
  25379. <doc>show configuration variables for another channel</doc>
  25380. <arg>CHAN</arg>
  25381. </channel>
  25382. </options>
  25383. <doc>&lt;parameter&gt; &lt;value&gt; [layer]
  25384. Sets the value of one configuration parameter. The first argument is
  25385. the name of the parameter, the second argument is the new value. Some
  25386. parameters are subject to validation, and the command will fail with
  25387. an error message if the new value does not make sense. An optional
  25388. third argument may be used to specify in which layer to set the
  25389. configuration parameter. The default layer is &quot;user&quot;. The
  25390. configuration value will be set for the current channel, which
  25391. is controlled by the default_channel configuration variable.
  25392. </doc>
  25393. </config-set>
  25394. <config-help>
  25395. <summary>Show Information About Setting</summary>
  25396. <function>doConfigHelp</function>
  25397. <shortcut>ch</shortcut>
  25398. <options />
  25399. <doc>[parameter]
  25400. Displays help for a configuration parameter. Without arguments it
  25401. displays help for all configuration parameters.
  25402. </doc>
  25403. </config-help>
  25404. <config-create>
  25405. <summary>Create a Default configuration file</summary>
  25406. <function>doConfigCreate</function>
  25407. <shortcut>coc</shortcut>
  25408. <options>
  25409. <windows>
  25410. <shortopt>w</shortopt>
  25411. <doc>create a config file for a windows install</doc>
  25412. </windows>
  25413. </options>
  25414. <doc>&lt;root path&gt; &lt;filename&gt;
  25415. Create a default configuration file with all directory configuration
  25416. variables set to subdirectories of &lt;root path&gt;, and save it as &lt;filename&gt;.
  25417. This is useful especially for creating a configuration file for a remote
  25418. PEAR installation (using the --remoteconfig option of install, upgrade,
  25419. and uninstall).
  25420. </doc>
  25421. </config-create>
  25422. </commands>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Config.php����������������������������������������������������������������0000644�0001750�0001750�00000036153�13565304531�016311� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  25423. /**
  25424. * PEAR_Command_Config (config-show, config-get, config-set, config-help, config-create commands)
  25425. *
  25426. * PHP versions 4 and 5
  25427. *
  25428. * @category pear
  25429. * @package PEAR
  25430. * @author Stig Bakken <ssb@php.net>
  25431. * @author Greg Beaver <cellog@php.net>
  25432. * @copyright 1997-2009 The Authors
  25433. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  25434. * @link http://pear.php.net/package/PEAR
  25435. * @since File available since Release 0.1
  25436. */
  25437. /**
  25438. * base class
  25439. */
  25440. require_once 'PEAR/Command/Common.php';
  25441. /**
  25442. * PEAR commands for managing configuration data.
  25443. *
  25444. * @category pear
  25445. * @package PEAR
  25446. * @author Stig Bakken <ssb@php.net>
  25447. * @author Greg Beaver <cellog@php.net>
  25448. * @copyright 1997-2009 The Authors
  25449. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  25450. * @version Release: 1.10.10
  25451. * @link http://pear.php.net/package/PEAR
  25452. * @since Class available since Release 0.1
  25453. */
  25454. class PEAR_Command_Config extends PEAR_Command_Common
  25455. {
  25456. var $commands = array(
  25457. 'config-show' => array(
  25458. 'summary' => 'Show All Settings',
  25459. 'function' => 'doConfigShow',
  25460. 'shortcut' => 'csh',
  25461. 'options' => array(
  25462. 'channel' => array(
  25463. 'shortopt' => 'c',
  25464. 'doc' => 'show configuration variables for another channel',
  25465. 'arg' => 'CHAN',
  25466. ),
  25467. ),
  25468. 'doc' => '[layer]
  25469. Displays all configuration values. An optional argument
  25470. may be used to tell which configuration layer to display. Valid
  25471. configuration layers are "user", "system" and "default". To display
  25472. configurations for different channels, set the default_channel
  25473. configuration variable and run config-show again.
  25474. ',
  25475. ),
  25476. 'config-get' => array(
  25477. 'summary' => 'Show One Setting',
  25478. 'function' => 'doConfigGet',
  25479. 'shortcut' => 'cg',
  25480. 'options' => array(
  25481. 'channel' => array(
  25482. 'shortopt' => 'c',
  25483. 'doc' => 'show configuration variables for another channel',
  25484. 'arg' => 'CHAN',
  25485. ),
  25486. ),
  25487. 'doc' => '<parameter> [layer]
  25488. Displays the value of one configuration parameter. The
  25489. first argument is the name of the parameter, an optional second argument
  25490. may be used to tell which configuration layer to look in. Valid configuration
  25491. layers are "user", "system" and "default". If no layer is specified, a value
  25492. will be picked from the first layer that defines the parameter, in the order
  25493. just specified. The configuration value will be retrieved for the channel
  25494. specified by the default_channel configuration variable.
  25495. ',
  25496. ),
  25497. 'config-set' => array(
  25498. 'summary' => 'Change Setting',
  25499. 'function' => 'doConfigSet',
  25500. 'shortcut' => 'cs',
  25501. 'options' => array(
  25502. 'channel' => array(
  25503. 'shortopt' => 'c',
  25504. 'doc' => 'show configuration variables for another channel',
  25505. 'arg' => 'CHAN',
  25506. ),
  25507. ),
  25508. 'doc' => '<parameter> <value> [layer]
  25509. Sets the value of one configuration parameter. The first argument is
  25510. the name of the parameter, the second argument is the new value. Some
  25511. parameters are subject to validation, and the command will fail with
  25512. an error message if the new value does not make sense. An optional
  25513. third argument may be used to specify in which layer to set the
  25514. configuration parameter. The default layer is "user". The
  25515. configuration value will be set for the current channel, which
  25516. is controlled by the default_channel configuration variable.
  25517. ',
  25518. ),
  25519. 'config-help' => array(
  25520. 'summary' => 'Show Information About Setting',
  25521. 'function' => 'doConfigHelp',
  25522. 'shortcut' => 'ch',
  25523. 'options' => array(),
  25524. 'doc' => '[parameter]
  25525. Displays help for a configuration parameter. Without arguments it
  25526. displays help for all configuration parameters.
  25527. ',
  25528. ),
  25529. 'config-create' => array(
  25530. 'summary' => 'Create a Default configuration file',
  25531. 'function' => 'doConfigCreate',
  25532. 'shortcut' => 'coc',
  25533. 'options' => array(
  25534. 'windows' => array(
  25535. 'shortopt' => 'w',
  25536. 'doc' => 'create a config file for a windows install',
  25537. ),
  25538. ),
  25539. 'doc' => '<root path> <filename>
  25540. Create a default configuration file with all directory configuration
  25541. variables set to subdirectories of <root path>, and save it as <filename>.
  25542. This is useful especially for creating a configuration file for a remote
  25543. PEAR installation (using the --remoteconfig option of install, upgrade,
  25544. and uninstall).
  25545. ',
  25546. ),
  25547. );
  25548. /**
  25549. * PEAR_Command_Config constructor.
  25550. *
  25551. * @access public
  25552. */
  25553. function __construct(&$ui, &$config)
  25554. {
  25555. parent::__construct($ui, $config);
  25556. }
  25557. function doConfigShow($command, $options, $params)
  25558. {
  25559. $layer = null;
  25560. if (is_array($params)) {
  25561. $layer = isset($params[0]) ? $params[0] : null;
  25562. }
  25563. // $params[0] -> the layer
  25564. if ($error = $this->_checkLayer($layer)) {
  25565. return $this->raiseError("config-show:$error");
  25566. }
  25567. $keys = $this->config->getKeys();
  25568. sort($keys);
  25569. $channel = isset($options['channel']) ? $options['channel'] :
  25570. $this->config->get('default_channel');
  25571. $reg = &$this->config->getRegistry();
  25572. if (!$reg->channelExists($channel)) {
  25573. return $this->raiseError('Channel "' . $channel . '" does not exist');
  25574. }
  25575. $channel = $reg->channelName($channel);
  25576. $data = array('caption' => 'Configuration (channel ' . $channel . '):');
  25577. foreach ($keys as $key) {
  25578. $type = $this->config->getType($key);
  25579. $value = $this->config->get($key, $layer, $channel);
  25580. if ($type == 'password' && $value) {
  25581. $value = '********';
  25582. }
  25583. if ($value === false) {
  25584. $value = 'false';
  25585. } elseif ($value === true) {
  25586. $value = 'true';
  25587. }
  25588. $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value);
  25589. }
  25590. foreach ($this->config->getLayers() as $layer) {
  25591. $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer));
  25592. }
  25593. $this->ui->outputData($data, $command);
  25594. return true;
  25595. }
  25596. function doConfigGet($command, $options, $params)
  25597. {
  25598. $args_cnt = is_array($params) ? count($params) : 0;
  25599. switch ($args_cnt) {
  25600. case 1:
  25601. $config_key = $params[0];
  25602. $layer = null;
  25603. break;
  25604. case 2:
  25605. $config_key = $params[0];
  25606. $layer = $params[1];
  25607. if ($error = $this->_checkLayer($layer)) {
  25608. return $this->raiseError("config-get:$error");
  25609. }
  25610. break;
  25611. case 0:
  25612. default:
  25613. return $this->raiseError("config-get expects 1 or 2 parameters");
  25614. }
  25615. $reg = &$this->config->getRegistry();
  25616. $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
  25617. if (!$reg->channelExists($channel)) {
  25618. return $this->raiseError('Channel "' . $channel . '" does not exist');
  25619. }
  25620. $channel = $reg->channelName($channel);
  25621. $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command);
  25622. return true;
  25623. }
  25624. function doConfigSet($command, $options, $params)
  25625. {
  25626. // $param[0] -> a parameter to set
  25627. // $param[1] -> the value for the parameter
  25628. // $param[2] -> the layer
  25629. $failmsg = '';
  25630. if (count($params) < 2 || count($params) > 3) {
  25631. $failmsg .= "config-set expects 2 or 3 parameters";
  25632. return PEAR::raiseError($failmsg);
  25633. }
  25634. if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) {
  25635. $failmsg .= $error;
  25636. return PEAR::raiseError("config-set:$failmsg");
  25637. }
  25638. $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
  25639. $reg = &$this->config->getRegistry();
  25640. if (!$reg->channelExists($channel)) {
  25641. return $this->raiseError('Channel "' . $channel . '" does not exist');
  25642. }
  25643. $channel = $reg->channelName($channel);
  25644. if ($params[0] == 'default_channel' && !$reg->channelExists($params[1])) {
  25645. return $this->raiseError('Channel "' . $params[1] . '" does not exist');
  25646. }
  25647. if ($params[0] == 'preferred_mirror'
  25648. && (
  25649. !$reg->mirrorExists($channel, $params[1]) &&
  25650. (!$reg->channelExists($params[1]) || $channel != $params[1])
  25651. )
  25652. ) {
  25653. $msg = 'Channel Mirror "' . $params[1] . '" does not exist';
  25654. $msg .= ' in your registry for channel "' . $channel . '".';
  25655. $msg .= "\n" . 'Attempt to run "pear channel-update ' . $channel .'"';
  25656. $msg .= ' if you believe this mirror should exist as you may';
  25657. $msg .= ' have outdated channel information.';
  25658. return $this->raiseError($msg);
  25659. }
  25660. if (count($params) == 2) {
  25661. array_push($params, 'user');
  25662. $layer = 'user';
  25663. } else {
  25664. $layer = $params[2];
  25665. }
  25666. array_push($params, $channel);
  25667. if (!call_user_func_array(array(&$this->config, 'set'), $params)) {
  25668. array_pop($params);
  25669. $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel";
  25670. } else {
  25671. $this->config->store($layer);
  25672. }
  25673. if ($failmsg) {
  25674. return $this->raiseError($failmsg);
  25675. }
  25676. $this->ui->outputData('config-set succeeded', $command);
  25677. return true;
  25678. }
  25679. function doConfigHelp($command, $options, $params)
  25680. {
  25681. if (empty($params)) {
  25682. $params = $this->config->getKeys();
  25683. }
  25684. $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : '');
  25685. $data['headline'] = array('Name', 'Type', 'Description');
  25686. $data['border'] = true;
  25687. foreach ($params as $name) {
  25688. $type = $this->config->getType($name);
  25689. $docs = $this->config->getDocs($name);
  25690. if ($type == 'set') {
  25691. $docs = rtrim($docs) . "\nValid set: " .
  25692. implode(' ', $this->config->getSetValues($name));
  25693. }
  25694. $data['data'][] = array($name, $type, $docs);
  25695. }
  25696. $this->ui->outputData($data, $command);
  25697. }
  25698. function doConfigCreate($command, $options, $params)
  25699. {
  25700. if (count($params) != 2) {
  25701. return PEAR::raiseError('config-create: must have 2 parameters, root path and ' .
  25702. 'filename to save as');
  25703. }
  25704. $root = $params[0];
  25705. // Clean up the DIRECTORY_SEPARATOR mess
  25706. $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  25707. $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"),
  25708. array('/', '/', '/'),
  25709. $root);
  25710. if ($root[0] != '/') {
  25711. if (!isset($options['windows'])) {
  25712. return PEAR::raiseError('Root directory must be an absolute path beginning ' .
  25713. 'with "/", was: "' . $root . '"');
  25714. }
  25715. if (!preg_match('/^[A-Za-z]:/', $root)) {
  25716. return PEAR::raiseError('Root directory must be an absolute path beginning ' .
  25717. 'with "\\" or "C:\\", was: "' . $root . '"');
  25718. }
  25719. }
  25720. $windows = isset($options['windows']);
  25721. if ($windows) {
  25722. $root = str_replace('/', '\\', $root);
  25723. }
  25724. if (!file_exists($params[1]) && !@touch($params[1])) {
  25725. return PEAR::raiseError('Could not create "' . $params[1] . '"');
  25726. }
  25727. $params[1] = realpath($params[1]);
  25728. $config = new PEAR_Config($params[1], '#no#system#config#', false, false);
  25729. if ($root[strlen($root) - 1] == '/') {
  25730. $root = substr($root, 0, strlen($root) - 1);
  25731. }
  25732. $config->noRegistry();
  25733. $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user');
  25734. $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data");
  25735. $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www");
  25736. $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg");
  25737. $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext");
  25738. $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs");
  25739. $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests");
  25740. $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache");
  25741. $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download");
  25742. $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp");
  25743. $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear");
  25744. $config->set('man_dir', $windows ? "$root\\pear\\man" : "$root/pear/man");
  25745. $config->writeConfigFile();
  25746. $this->_showConfig($config);
  25747. $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"',
  25748. $command);
  25749. }
  25750. function _showConfig(&$config)
  25751. {
  25752. $params = array('user');
  25753. $keys = $config->getKeys();
  25754. sort($keys);
  25755. $channel = 'pear.php.net';
  25756. $data = array('caption' => 'Configuration (channel ' . $channel . '):');
  25757. foreach ($keys as $key) {
  25758. $type = $config->getType($key);
  25759. $value = $config->get($key, 'user', $channel);
  25760. if ($type == 'password' && $value) {
  25761. $value = '********';
  25762. }
  25763. if ($value === false) {
  25764. $value = 'false';
  25765. } elseif ($value === true) {
  25766. $value = 'true';
  25767. }
  25768. $data['data'][$config->getGroup($key)][] =
  25769. array($config->getPrompt($key) , $key, $value);
  25770. }
  25771. foreach ($config->getLayers() as $layer) {
  25772. $data['data']['Config Files'][] =
  25773. array(ucfirst($layer) . ' Configuration File', 'Filename' ,
  25774. $config->getConfFile($layer));
  25775. }
  25776. $this->ui->outputData($data, 'config-show');
  25777. return true;
  25778. }
  25779. /**
  25780. * Checks if a layer is defined or not
  25781. *
  25782. * @param string $layer The layer to search for
  25783. * @return mixed False on no error or the error message
  25784. */
  25785. function _checkLayer($layer = null)
  25786. {
  25787. if (!empty($layer) && $layer != 'default') {
  25788. $layers = $this->config->getLayers();
  25789. if (!in_array($layer, $layers)) {
  25790. return " only the layers: \"" . implode('" or "', $layers) . "\" are supported";
  25791. }
  25792. }
  25793. return false;
  25794. }
  25795. }
  25796. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Install.xml���������������������������������������������������������������0000644�0001750�0001750�00000020763�13565304531�016523� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  25797. <install>
  25798. <summary>Install Package</summary>
  25799. <function>doInstall</function>
  25800. <shortcut>i</shortcut>
  25801. <options>
  25802. <force>
  25803. <shortopt>f</shortopt>
  25804. <doc>will overwrite newer installed packages</doc>
  25805. </force>
  25806. <loose>
  25807. <shortopt>l</shortopt>
  25808. <doc>do not check for recommended dependency version</doc>
  25809. </loose>
  25810. <nodeps>
  25811. <shortopt>n</shortopt>
  25812. <doc>ignore dependencies, install anyway</doc>
  25813. </nodeps>
  25814. <register-only>
  25815. <shortopt>r</shortopt>
  25816. <doc>do not install files, only register the package as installed</doc>
  25817. </register-only>
  25818. <soft>
  25819. <shortopt>s</shortopt>
  25820. <doc>soft install, fail silently, or upgrade if already installed</doc>
  25821. </soft>
  25822. <nobuild>
  25823. <shortopt>B</shortopt>
  25824. <doc>don&#039;t build C extensions</doc>
  25825. </nobuild>
  25826. <configureoptions>
  25827. <shortopt>D</shortopt>
  25828. <arg>OPTION1=VALUE[ OPTION2=VALUE]</arg>
  25829. </configureoptions>
  25830. <nocompress>
  25831. <shortopt>Z</shortopt>
  25832. <doc>request uncompressed files when downloading</doc>
  25833. </nocompress>
  25834. <installroot>
  25835. <shortopt>R</shortopt>
  25836. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT), use packagingroot for RPM</doc>
  25837. <arg>DIR</arg>
  25838. </installroot>
  25839. <packagingroot>
  25840. <shortopt>P</shortopt>
  25841. <doc>root directory used when packaging files, like RPM packaging</doc>
  25842. <arg>DIR</arg>
  25843. </packagingroot>
  25844. <ignore-errors>
  25845. <shortopt></shortopt>
  25846. <doc>force install even if there were errors</doc>
  25847. </ignore-errors>
  25848. <alldeps>
  25849. <shortopt>a</shortopt>
  25850. <doc>install all required and optional dependencies</doc>
  25851. </alldeps>
  25852. <onlyreqdeps>
  25853. <shortopt>o</shortopt>
  25854. <doc>install all required dependencies</doc>
  25855. </onlyreqdeps>
  25856. <offline>
  25857. <shortopt>O</shortopt>
  25858. <doc>do not attempt to download any urls or contact channels</doc>
  25859. </offline>
  25860. <pretend>
  25861. <shortopt>p</shortopt>
  25862. <doc>Only list the packages that would be downloaded</doc>
  25863. </pretend>
  25864. </options>
  25865. <doc>[channel/]&lt;package&gt; ...
  25866. Installs one or more PEAR packages. You can specify a package to
  25867. install in four ways:
  25868. &quot;Package-1.0.tgz&quot; : installs from a local file
  25869. &quot;http://example.com/Package-1.0.tgz&quot; : installs from
  25870. anywhere on the net.
  25871. &quot;package.xml&quot; : installs the package described in
  25872. package.xml. Useful for testing, or for wrapping a PEAR package in
  25873. another package manager such as RPM.
  25874. &quot;Package[-version/state][.tar]&quot; : queries your default channel&#039;s server
  25875. ({config master_server}) and downloads the newest package with
  25876. the preferred quality/state ({config preferred_state}).
  25877. To retrieve Package version 1.1, use &quot;Package-1.1,&quot; to retrieve
  25878. Package state beta, use &quot;Package-beta.&quot; To retrieve an uncompressed
  25879. file, append .tar (make sure there is no file by the same name first)
  25880. To download a package from another channel, prefix with the channel name like
  25881. &quot;channel/Package&quot;
  25882. More than one package may be specified at once. It is ok to mix these
  25883. four ways of specifying packages.
  25884. </doc>
  25885. </install>
  25886. <upgrade>
  25887. <summary>Upgrade Package</summary>
  25888. <function>doInstall</function>
  25889. <shortcut>up</shortcut>
  25890. <options>
  25891. <channel>
  25892. <shortopt>c</shortopt>
  25893. <doc>upgrade packages from a specific channel</doc>
  25894. <arg>CHAN</arg>
  25895. </channel>
  25896. <force>
  25897. <shortopt>f</shortopt>
  25898. <doc>overwrite newer installed packages</doc>
  25899. </force>
  25900. <loose>
  25901. <shortopt>l</shortopt>
  25902. <doc>do not check for recommended dependency version</doc>
  25903. </loose>
  25904. <nodeps>
  25905. <shortopt>n</shortopt>
  25906. <doc>ignore dependencies, upgrade anyway</doc>
  25907. </nodeps>
  25908. <register-only>
  25909. <shortopt>r</shortopt>
  25910. <doc>do not install files, only register the package as upgraded</doc>
  25911. </register-only>
  25912. <nobuild>
  25913. <shortopt>B</shortopt>
  25914. <doc>don&#039;t build C extensions</doc>
  25915. </nobuild>
  25916. <nocompress>
  25917. <shortopt>Z</shortopt>
  25918. <doc>request uncompressed files when downloading</doc>
  25919. </nocompress>
  25920. <installroot>
  25921. <shortopt>R</shortopt>
  25922. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT)</doc>
  25923. <arg>DIR</arg>
  25924. </installroot>
  25925. <ignore-errors>
  25926. <shortopt></shortopt>
  25927. <doc>force install even if there were errors</doc>
  25928. </ignore-errors>
  25929. <alldeps>
  25930. <shortopt>a</shortopt>
  25931. <doc>install all required and optional dependencies</doc>
  25932. </alldeps>
  25933. <onlyreqdeps>
  25934. <shortopt>o</shortopt>
  25935. <doc>install all required dependencies</doc>
  25936. </onlyreqdeps>
  25937. <offline>
  25938. <shortopt>O</shortopt>
  25939. <doc>do not attempt to download any urls or contact channels</doc>
  25940. </offline>
  25941. <pretend>
  25942. <shortopt>p</shortopt>
  25943. <doc>Only list the packages that would be downloaded</doc>
  25944. </pretend>
  25945. </options>
  25946. <doc>&lt;package&gt; ...
  25947. Upgrades one or more PEAR packages. See documentation for the
  25948. &quot;install&quot; command for ways to specify a package.
  25949. When upgrading, your package will be updated if the provided new
  25950. package has a higher version number (use the -f option if you need to
  25951. upgrade anyway).
  25952. More than one package may be specified at once.
  25953. </doc>
  25954. </upgrade>
  25955. <upgrade-all>
  25956. <summary>Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]</summary>
  25957. <function>doUpgradeAll</function>
  25958. <shortcut>ua</shortcut>
  25959. <options>
  25960. <channel>
  25961. <shortopt>c</shortopt>
  25962. <doc>upgrade packages from a specific channel</doc>
  25963. <arg>CHAN</arg>
  25964. </channel>
  25965. <nodeps>
  25966. <shortopt>n</shortopt>
  25967. <doc>ignore dependencies, upgrade anyway</doc>
  25968. </nodeps>
  25969. <register-only>
  25970. <shortopt>r</shortopt>
  25971. <doc>do not install files, only register the package as upgraded</doc>
  25972. </register-only>
  25973. <nobuild>
  25974. <shortopt>B</shortopt>
  25975. <doc>don&#039;t build C extensions</doc>
  25976. </nobuild>
  25977. <nocompress>
  25978. <shortopt>Z</shortopt>
  25979. <doc>request uncompressed files when downloading</doc>
  25980. </nocompress>
  25981. <installroot>
  25982. <shortopt>R</shortopt>
  25983. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT), use packagingroot for RPM</doc>
  25984. <arg>DIR</arg>
  25985. </installroot>
  25986. <ignore-errors>
  25987. <shortopt></shortopt>
  25988. <doc>force install even if there were errors</doc>
  25989. </ignore-errors>
  25990. <loose>
  25991. <shortopt></shortopt>
  25992. <doc>do not check for recommended dependency version</doc>
  25993. </loose>
  25994. </options>
  25995. <doc>
  25996. WARNING: This function is deprecated in favor of using the upgrade command with no params
  25997. Upgrades all packages that have a newer release available. Upgrades are
  25998. done only if there is a release available of the state specified in
  25999. &quot;preferred_state&quot; (currently {config preferred_state}), or a state considered
  26000. more stable.
  26001. </doc>
  26002. </upgrade-all>
  26003. <uninstall>
  26004. <summary>Un-install Package</summary>
  26005. <function>doUninstall</function>
  26006. <shortcut>un</shortcut>
  26007. <options>
  26008. <nodeps>
  26009. <shortopt>n</shortopt>
  26010. <doc>ignore dependencies, uninstall anyway</doc>
  26011. </nodeps>
  26012. <register-only>
  26013. <shortopt>r</shortopt>
  26014. <doc>do not remove files, only register the packages as not installed</doc>
  26015. </register-only>
  26016. <installroot>
  26017. <shortopt>R</shortopt>
  26018. <doc>root directory used when installing files (ala PHP&#039;s INSTALL_ROOT)</doc>
  26019. <arg>DIR</arg>
  26020. </installroot>
  26021. <ignore-errors>
  26022. <shortopt></shortopt>
  26023. <doc>force install even if there were errors</doc>
  26024. </ignore-errors>
  26025. <offline>
  26026. <shortopt>O</shortopt>
  26027. <doc>do not attempt to uninstall remotely</doc>
  26028. </offline>
  26029. </options>
  26030. <doc>[channel/]&lt;package&gt; ...
  26031. Uninstalls one or more PEAR packages. More than one package may be
  26032. specified at once. Prefix with channel name to uninstall from a
  26033. channel not in your default channel ({config default_channel})
  26034. </doc>
  26035. </uninstall>
  26036. <bundle>
  26037. <summary>Unpacks a Pecl Package</summary>
  26038. <function>doBundle</function>
  26039. <shortcut>bun</shortcut>
  26040. <options>
  26041. <destination>
  26042. <shortopt>d</shortopt>
  26043. <doc>Optional destination directory for unpacking (defaults to current path or &quot;ext&quot; if exists)</doc>
  26044. <arg>DIR</arg>
  26045. </destination>
  26046. <force>
  26047. <shortopt>f</shortopt>
  26048. <doc>Force the unpacking even if there were errors in the package</doc>
  26049. </force>
  26050. </options>
  26051. <doc>&lt;package&gt;
  26052. Unpacks a Pecl Package into the selected location. It will download the
  26053. package if needed.
  26054. </doc>
  26055. </bundle>
  26056. <run-scripts>
  26057. <summary>Run Post-Install Scripts bundled with a package</summary>
  26058. <function>doRunScripts</function>
  26059. <shortcut>rs</shortcut>
  26060. <options />
  26061. <doc>&lt;package&gt;
  26062. Run post-installation scripts in package &lt;package&gt;, if any exist.
  26063. </doc>
  26064. </run-scripts>
  26065. </commands>�������������PEAR-1.10.10/PEAR/Command/Install.php���������������������������������������������������������������0000644�0001750�0001750�00000143473�13565304531�016516� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  26066. /**
  26067. * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
  26068. *
  26069. * PHP versions 4 and 5
  26070. *
  26071. * @category pear
  26072. * @package PEAR
  26073. * @author Stig Bakken <ssb@php.net>
  26074. * @author Greg Beaver <cellog@php.net>
  26075. * @copyright 1997-2009 The Authors
  26076. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  26077. * @link http://pear.php.net/package/PEAR
  26078. * @since File available since Release 0.1
  26079. */
  26080. /**
  26081. * base class
  26082. */
  26083. require_once 'PEAR/Command/Common.php';
  26084. /**
  26085. * PEAR commands for installation or deinstallation/upgrading of
  26086. * packages.
  26087. *
  26088. * @category pear
  26089. * @package PEAR
  26090. * @author Stig Bakken <ssb@php.net>
  26091. * @author Greg Beaver <cellog@php.net>
  26092. * @copyright 1997-2009 The Authors
  26093. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  26094. * @version Release: 1.10.10
  26095. * @link http://pear.php.net/package/PEAR
  26096. * @since Class available since Release 0.1
  26097. */
  26098. class PEAR_Command_Install extends PEAR_Command_Common
  26099. {
  26100. // {{{ properties
  26101. var $commands = array(
  26102. 'install' => array(
  26103. 'summary' => 'Install Package',
  26104. 'function' => 'doInstall',
  26105. 'shortcut' => 'i',
  26106. 'options' => array(
  26107. 'force' => array(
  26108. 'shortopt' => 'f',
  26109. 'doc' => 'will overwrite newer installed packages',
  26110. ),
  26111. 'loose' => array(
  26112. 'shortopt' => 'l',
  26113. 'doc' => 'do not check for recommended dependency version',
  26114. ),
  26115. 'nodeps' => array(
  26116. 'shortopt' => 'n',
  26117. 'doc' => 'ignore dependencies, install anyway',
  26118. ),
  26119. 'register-only' => array(
  26120. 'shortopt' => 'r',
  26121. 'doc' => 'do not install files, only register the package as installed',
  26122. ),
  26123. 'soft' => array(
  26124. 'shortopt' => 's',
  26125. 'doc' => 'soft install, fail silently, or upgrade if already installed',
  26126. ),
  26127. 'nobuild' => array(
  26128. 'shortopt' => 'B',
  26129. 'doc' => 'don\'t build C extensions',
  26130. ),
  26131. 'configureoptions' => array(
  26132. 'shortopt' => 'D',
  26133. 'arg' => 'OPTION1=VALUE[ OPTION2=VALUE]',
  26134. 'doc' => 'space-delimited list of configure options',
  26135. ),
  26136. 'nocompress' => array(
  26137. 'shortopt' => 'Z',
  26138. 'doc' => 'request uncompressed files when downloading',
  26139. ),
  26140. 'installroot' => array(
  26141. 'shortopt' => 'R',
  26142. 'arg' => 'DIR',
  26143. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  26144. ),
  26145. 'packagingroot' => array(
  26146. 'shortopt' => 'P',
  26147. 'arg' => 'DIR',
  26148. 'doc' => 'root directory used when packaging files, like RPM packaging',
  26149. ),
  26150. 'ignore-errors' => array(
  26151. 'doc' => 'force install even if there were errors',
  26152. ),
  26153. 'alldeps' => array(
  26154. 'shortopt' => 'a',
  26155. 'doc' => 'install all required and optional dependencies',
  26156. ),
  26157. 'onlyreqdeps' => array(
  26158. 'shortopt' => 'o',
  26159. 'doc' => 'install all required dependencies',
  26160. ),
  26161. 'offline' => array(
  26162. 'shortopt' => 'O',
  26163. 'doc' => 'do not attempt to download any urls or contact channels',
  26164. ),
  26165. 'pretend' => array(
  26166. 'shortopt' => 'p',
  26167. 'doc' => 'Only list the packages that would be downloaded',
  26168. ),
  26169. ),
  26170. 'doc' => '[channel/]<package> ...
  26171. Installs one or more PEAR packages. You can specify a package to
  26172. install in four ways:
  26173. "Package-1.0.tgz" : installs from a local file
  26174. "http://example.com/Package-1.0.tgz" : installs from
  26175. anywhere on the net.
  26176. "package.xml" : installs the package described in
  26177. package.xml. Useful for testing, or for wrapping a PEAR package in
  26178. another package manager such as RPM.
  26179. "Package[-version/state][.tar]" : queries your default channel\'s server
  26180. ({config master_server}) and downloads the newest package with
  26181. the preferred quality/state ({config preferred_state}).
  26182. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  26183. Package state beta, use "Package-beta." To retrieve an uncompressed
  26184. file, append .tar (make sure there is no file by the same name first)
  26185. To download a package from another channel, prefix with the channel name like
  26186. "channel/Package"
  26187. More than one package may be specified at once. It is ok to mix these
  26188. four ways of specifying packages.
  26189. '),
  26190. 'upgrade' => array(
  26191. 'summary' => 'Upgrade Package',
  26192. 'function' => 'doInstall',
  26193. 'shortcut' => 'up',
  26194. 'options' => array(
  26195. 'channel' => array(
  26196. 'shortopt' => 'c',
  26197. 'doc' => 'upgrade packages from a specific channel',
  26198. 'arg' => 'CHAN',
  26199. ),
  26200. 'force' => array(
  26201. 'shortopt' => 'f',
  26202. 'doc' => 'overwrite newer installed packages',
  26203. ),
  26204. 'loose' => array(
  26205. 'shortopt' => 'l',
  26206. 'doc' => 'do not check for recommended dependency version',
  26207. ),
  26208. 'nodeps' => array(
  26209. 'shortopt' => 'n',
  26210. 'doc' => 'ignore dependencies, upgrade anyway',
  26211. ),
  26212. 'register-only' => array(
  26213. 'shortopt' => 'r',
  26214. 'doc' => 'do not install files, only register the package as upgraded',
  26215. ),
  26216. 'nobuild' => array(
  26217. 'shortopt' => 'B',
  26218. 'doc' => 'don\'t build C extensions',
  26219. ),
  26220. 'nocompress' => array(
  26221. 'shortopt' => 'Z',
  26222. 'doc' => 'request uncompressed files when downloading',
  26223. ),
  26224. 'installroot' => array(
  26225. 'shortopt' => 'R',
  26226. 'arg' => 'DIR',
  26227. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  26228. ),
  26229. 'ignore-errors' => array(
  26230. 'doc' => 'force install even if there were errors',
  26231. ),
  26232. 'alldeps' => array(
  26233. 'shortopt' => 'a',
  26234. 'doc' => 'install all required and optional dependencies',
  26235. ),
  26236. 'onlyreqdeps' => array(
  26237. 'shortopt' => 'o',
  26238. 'doc' => 'install all required dependencies',
  26239. ),
  26240. 'offline' => array(
  26241. 'shortopt' => 'O',
  26242. 'doc' => 'do not attempt to download any urls or contact channels',
  26243. ),
  26244. 'pretend' => array(
  26245. 'shortopt' => 'p',
  26246. 'doc' => 'Only list the packages that would be downloaded',
  26247. ),
  26248. ),
  26249. 'doc' => '<package> ...
  26250. Upgrades one or more PEAR packages. See documentation for the
  26251. "install" command for ways to specify a package.
  26252. When upgrading, your package will be updated if the provided new
  26253. package has a higher version number (use the -f option if you need to
  26254. upgrade anyway).
  26255. More than one package may be specified at once.
  26256. '),
  26257. 'upgrade-all' => array(
  26258. 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]',
  26259. 'function' => 'doUpgradeAll',
  26260. 'shortcut' => 'ua',
  26261. 'options' => array(
  26262. 'channel' => array(
  26263. 'shortopt' => 'c',
  26264. 'doc' => 'upgrade packages from a specific channel',
  26265. 'arg' => 'CHAN',
  26266. ),
  26267. 'nodeps' => array(
  26268. 'shortopt' => 'n',
  26269. 'doc' => 'ignore dependencies, upgrade anyway',
  26270. ),
  26271. 'register-only' => array(
  26272. 'shortopt' => 'r',
  26273. 'doc' => 'do not install files, only register the package as upgraded',
  26274. ),
  26275. 'nobuild' => array(
  26276. 'shortopt' => 'B',
  26277. 'doc' => 'don\'t build C extensions',
  26278. ),
  26279. 'nocompress' => array(
  26280. 'shortopt' => 'Z',
  26281. 'doc' => 'request uncompressed files when downloading',
  26282. ),
  26283. 'installroot' => array(
  26284. 'shortopt' => 'R',
  26285. 'arg' => 'DIR',
  26286. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  26287. ),
  26288. 'ignore-errors' => array(
  26289. 'doc' => 'force install even if there were errors',
  26290. ),
  26291. 'loose' => array(
  26292. 'doc' => 'do not check for recommended dependency version',
  26293. ),
  26294. ),
  26295. 'doc' => '
  26296. WARNING: This function is deprecated in favor of using the upgrade command with no params
  26297. Upgrades all packages that have a newer release available. Upgrades are
  26298. done only if there is a release available of the state specified in
  26299. "preferred_state" (currently {config preferred_state}), or a state considered
  26300. more stable.
  26301. '),
  26302. 'uninstall' => array(
  26303. 'summary' => 'Un-install Package',
  26304. 'function' => 'doUninstall',
  26305. 'shortcut' => 'un',
  26306. 'options' => array(
  26307. 'nodeps' => array(
  26308. 'shortopt' => 'n',
  26309. 'doc' => 'ignore dependencies, uninstall anyway',
  26310. ),
  26311. 'register-only' => array(
  26312. 'shortopt' => 'r',
  26313. 'doc' => 'do not remove files, only register the packages as not installed',
  26314. ),
  26315. 'installroot' => array(
  26316. 'shortopt' => 'R',
  26317. 'arg' => 'DIR',
  26318. 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  26319. ),
  26320. 'ignore-errors' => array(
  26321. 'doc' => 'force install even if there were errors',
  26322. ),
  26323. 'offline' => array(
  26324. 'shortopt' => 'O',
  26325. 'doc' => 'do not attempt to uninstall remotely',
  26326. ),
  26327. ),
  26328. 'doc' => '[channel/]<package> ...
  26329. Uninstalls one or more PEAR packages. More than one package may be
  26330. specified at once. Prefix with channel name to uninstall from a
  26331. channel not in your default channel ({config default_channel})
  26332. '),
  26333. 'bundle' => array(
  26334. 'summary' => 'Unpacks a Pecl Package',
  26335. 'function' => 'doBundle',
  26336. 'shortcut' => 'bun',
  26337. 'options' => array(
  26338. 'destination' => array(
  26339. 'shortopt' => 'd',
  26340. 'arg' => 'DIR',
  26341. 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  26342. ),
  26343. 'force' => array(
  26344. 'shortopt' => 'f',
  26345. 'doc' => 'Force the unpacking even if there were errors in the package',
  26346. ),
  26347. ),
  26348. 'doc' => '<package>
  26349. Unpacks a Pecl Package into the selected location. It will download the
  26350. package if needed.
  26351. '),
  26352. 'run-scripts' => array(
  26353. 'summary' => 'Run Post-Install Scripts bundled with a package',
  26354. 'function' => 'doRunScripts',
  26355. 'shortcut' => 'rs',
  26356. 'options' => array(
  26357. ),
  26358. 'doc' => '<package>
  26359. Run post-installation scripts in package <package>, if any exist.
  26360. '),
  26361. );
  26362. // }}}
  26363. // {{{ constructor
  26364. /**
  26365. * PEAR_Command_Install constructor.
  26366. *
  26367. * @access public
  26368. */
  26369. function __construct(&$ui, &$config)
  26370. {
  26371. parent::__construct($ui, $config);
  26372. }
  26373. // }}}
  26374. /**
  26375. * For unit testing purposes
  26376. */
  26377. function &getDownloader(&$ui, $options, &$config)
  26378. {
  26379. if (!class_exists('PEAR_Downloader')) {
  26380. require_once 'PEAR/Downloader.php';
  26381. }
  26382. $a = new PEAR_Downloader($ui, $options, $config);
  26383. return $a;
  26384. }
  26385. /**
  26386. * For unit testing purposes
  26387. */
  26388. function &getInstaller(&$ui)
  26389. {
  26390. if (!class_exists('PEAR_Installer')) {
  26391. require_once 'PEAR/Installer.php';
  26392. }
  26393. $a = new PEAR_Installer($ui);
  26394. return $a;
  26395. }
  26396. function enableExtension($binaries, $type)
  26397. {
  26398. if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  26399. return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  26400. }
  26401. $ini = $this->_parseIni($phpini);
  26402. if (PEAR::isError($ini)) {
  26403. return $ini;
  26404. }
  26405. $line = 0;
  26406. if ($type == 'extsrc' || $type == 'extbin') {
  26407. $search = 'extensions';
  26408. $enable = 'extension';
  26409. } else {
  26410. $search = 'zend_extensions';
  26411. ob_start();
  26412. phpinfo(INFO_GENERAL);
  26413. $info = ob_get_contents();
  26414. ob_end_clean();
  26415. $debug = function_exists('leak') ? '_debug' : '';
  26416. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  26417. $enable = 'zend_extension' . $debug . $ts;
  26418. }
  26419. foreach ($ini[$search] as $line => $extension) {
  26420. if (in_array($extension, $binaries, true) || in_array(
  26421. $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  26422. // already enabled - assume if one is, all are
  26423. return true;
  26424. }
  26425. }
  26426. if ($line) {
  26427. $newini = array_slice($ini['all'], 0, $line);
  26428. } else {
  26429. $newini = array();
  26430. }
  26431. foreach ($binaries as $binary) {
  26432. if ($ini['extension_dir']) {
  26433. $binary = basename($binary);
  26434. }
  26435. $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
  26436. }
  26437. $newini = array_merge($newini, array_slice($ini['all'], $line));
  26438. $fp = @fopen($phpini, 'wb');
  26439. if (!$fp) {
  26440. return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  26441. }
  26442. foreach ($newini as $line) {
  26443. fwrite($fp, $line);
  26444. }
  26445. fclose($fp);
  26446. return true;
  26447. }
  26448. function disableExtension($binaries, $type)
  26449. {
  26450. if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  26451. return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  26452. }
  26453. $ini = $this->_parseIni($phpini);
  26454. if (PEAR::isError($ini)) {
  26455. return $ini;
  26456. }
  26457. $line = 0;
  26458. if ($type == 'extsrc' || $type == 'extbin') {
  26459. $search = 'extensions';
  26460. $enable = 'extension';
  26461. } else {
  26462. $search = 'zend_extensions';
  26463. ob_start();
  26464. phpinfo(INFO_GENERAL);
  26465. $info = ob_get_contents();
  26466. ob_end_clean();
  26467. $debug = function_exists('leak') ? '_debug' : '';
  26468. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  26469. $enable = 'zend_extension' . $debug . $ts;
  26470. }
  26471. $found = false;
  26472. foreach ($ini[$search] as $line => $extension) {
  26473. if (in_array($extension, $binaries, true) || in_array(
  26474. $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  26475. $found = true;
  26476. break;
  26477. }
  26478. }
  26479. if (!$found) {
  26480. // not enabled
  26481. return true;
  26482. }
  26483. $fp = @fopen($phpini, 'wb');
  26484. if (!$fp) {
  26485. return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  26486. }
  26487. if ($line) {
  26488. $newini = array_slice($ini['all'], 0, $line);
  26489. // delete the enable line
  26490. $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
  26491. } else {
  26492. $newini = array_slice($ini['all'], 1);
  26493. }
  26494. foreach ($newini as $line) {
  26495. fwrite($fp, $line);
  26496. }
  26497. fclose($fp);
  26498. return true;
  26499. }
  26500. function _parseIni($filename)
  26501. {
  26502. if (!file_exists($filename)) {
  26503. return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
  26504. }
  26505. if (filesize($filename) > 300000) {
  26506. return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
  26507. }
  26508. ob_start();
  26509. phpinfo(INFO_GENERAL);
  26510. $info = ob_get_contents();
  26511. ob_end_clean();
  26512. $debug = function_exists('leak') ? '_debug' : '';
  26513. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  26514. $zend_extension_line = 'zend_extension' . $debug . $ts;
  26515. $all = @file($filename);
  26516. if ($all === false) {
  26517. return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
  26518. }
  26519. $zend_extensions = $extensions = array();
  26520. // assume this is right, but pull from the php.ini if it is found
  26521. $extension_dir = ini_get('extension_dir');
  26522. foreach ($all as $linenum => $line) {
  26523. $line = trim($line);
  26524. if (!$line) {
  26525. continue;
  26526. }
  26527. if ($line[0] == ';') {
  26528. continue;
  26529. }
  26530. if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
  26531. $line = trim(substr($line, 13));
  26532. if ($line[0] == '=') {
  26533. $x = trim(substr($line, 1));
  26534. $x = explode(';', $x);
  26535. $extension_dir = str_replace('"', '', array_shift($x));
  26536. continue;
  26537. }
  26538. }
  26539. if (strtolower(substr($line, 0, 9)) == 'extension') {
  26540. $line = trim(substr($line, 9));
  26541. if ($line[0] == '=') {
  26542. $x = trim(substr($line, 1));
  26543. $x = explode(';', $x);
  26544. $extensions[$linenum] = str_replace('"', '', array_shift($x));
  26545. continue;
  26546. }
  26547. }
  26548. if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
  26549. $zend_extension_line) {
  26550. $line = trim(substr($line, strlen($zend_extension_line)));
  26551. if ($line[0] == '=') {
  26552. $x = trim(substr($line, 1));
  26553. $x = explode(';', $x);
  26554. $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
  26555. continue;
  26556. }
  26557. }
  26558. }
  26559. return array(
  26560. 'extensions' => $extensions,
  26561. 'zend_extensions' => $zend_extensions,
  26562. 'extension_dir' => $extension_dir,
  26563. 'all' => $all,
  26564. );
  26565. }
  26566. // {{{ doInstall()
  26567. function doInstall($command, $options, $params)
  26568. {
  26569. if (!class_exists('PEAR_PackageFile')) {
  26570. require_once 'PEAR/PackageFile.php';
  26571. }
  26572. if (isset($options['installroot']) && isset($options['packagingroot'])) {
  26573. return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
  26574. }
  26575. $reg = &$this->config->getRegistry();
  26576. $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
  26577. if (!$reg->channelExists($channel)) {
  26578. return $this->raiseError('Channel "' . $channel . '" does not exist');
  26579. }
  26580. if (empty($this->installer)) {
  26581. $this->installer = &$this->getInstaller($this->ui);
  26582. }
  26583. if ($command == 'upgrade' || $command == 'upgrade-all') {
  26584. // If people run the upgrade command but pass nothing, emulate a upgrade-all
  26585. if ($command == 'upgrade' && empty($params)) {
  26586. return $this->doUpgradeAll($command, $options, $params);
  26587. }
  26588. $options['upgrade'] = true;
  26589. } else {
  26590. $packages = $params;
  26591. }
  26592. $instreg = &$reg; // instreg used to check if package is installed
  26593. if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
  26594. $packrootphp_dir = $this->installer->_prependPath(
  26595. $this->config->get('php_dir', null, 'pear.php.net'),
  26596. $options['packagingroot']);
  26597. $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
  26598. if ($metadata_dir) {
  26599. $metadata_dir = $this->installer->_prependPath(
  26600. $metadata_dir,
  26601. $options['packagingroot']);
  26602. }
  26603. $instreg = new PEAR_Registry($packrootphp_dir, false, false, $metadata_dir); // other instreg!
  26604. if ($this->config->get('verbose') > 2) {
  26605. $this->ui->outputData('using package root: ' . $options['packagingroot']);
  26606. }
  26607. }
  26608. $abstractpackages = $otherpackages = array();
  26609. // parse params
  26610. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26611. foreach ($params as $param) {
  26612. if (strpos($param, 'http://') === 0) {
  26613. $otherpackages[] = $param;
  26614. continue;
  26615. }
  26616. if (strpos($param, 'channel://') === false && @file_exists($param)) {
  26617. if (isset($options['force'])) {
  26618. $otherpackages[] = $param;
  26619. continue;
  26620. }
  26621. $pkg = new PEAR_PackageFile($this->config);
  26622. $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
  26623. if (PEAR::isError($pf)) {
  26624. $otherpackages[] = $param;
  26625. continue;
  26626. }
  26627. $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel());
  26628. $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel());
  26629. $version_compare = version_compare($pf->getVersion(), $pversion, '<=');
  26630. if ($exists && $version_compare) {
  26631. if ($this->config->get('verbose')) {
  26632. $this->ui->outputData('Ignoring installed package ' .
  26633. $reg->parsedPackageNameToString(
  26634. array('package' => $pf->getPackage(),
  26635. 'channel' => $pf->getChannel()), true));
  26636. }
  26637. continue;
  26638. }
  26639. $otherpackages[] = $param;
  26640. continue;
  26641. }
  26642. $e = $reg->parsePackageName($param, $channel);
  26643. if (PEAR::isError($e)) {
  26644. $otherpackages[] = $param;
  26645. } else {
  26646. $abstractpackages[] = $e;
  26647. }
  26648. }
  26649. PEAR::staticPopErrorHandling();
  26650. // if there are any local package .tgz or remote static url, we can't
  26651. // filter. The filter only works for abstract packages
  26652. if (count($abstractpackages) && !isset($options['force'])) {
  26653. // when not being forced, only do necessary upgrades/installs
  26654. if (isset($options['upgrade'])) {
  26655. $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command);
  26656. } else {
  26657. $count = count($abstractpackages);
  26658. foreach ($abstractpackages as $i => $package) {
  26659. if (isset($package['group'])) {
  26660. // do not filter out install groups
  26661. continue;
  26662. }
  26663. if ($instreg->packageExists($package['package'], $package['channel'])) {
  26664. if ($count > 1) {
  26665. if ($this->config->get('verbose')) {
  26666. $this->ui->outputData('Ignoring installed package ' .
  26667. $reg->parsedPackageNameToString($package, true));
  26668. }
  26669. unset($abstractpackages[$i]);
  26670. } elseif ($count === 1) {
  26671. // Lets try to upgrade it since it's already installed
  26672. $options['upgrade'] = true;
  26673. }
  26674. }
  26675. }
  26676. }
  26677. $abstractpackages =
  26678. array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  26679. } elseif (count($abstractpackages)) {
  26680. $abstractpackages =
  26681. array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
  26682. }
  26683. $packages = array_merge($abstractpackages, $otherpackages);
  26684. if (!count($packages)) {
  26685. $c = '';
  26686. if (isset($options['channel'])){
  26687. $c .= ' in channel "' . $options['channel'] . '"';
  26688. }
  26689. $this->ui->outputData('Nothing to ' . $command . $c);
  26690. return true;
  26691. }
  26692. $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
  26693. $errors = $downloaded = $binaries = array();
  26694. $downloaded = &$this->downloader->download($packages);
  26695. if (PEAR::isError($downloaded)) {
  26696. return $this->raiseError($downloaded);
  26697. }
  26698. $errors = $this->downloader->getErrorMsgs();
  26699. if (count($errors)) {
  26700. $err = array();
  26701. $err['data'] = array();
  26702. foreach ($errors as $error) {
  26703. if ($error !== null) {
  26704. $err['data'][] = array($error);
  26705. }
  26706. }
  26707. if (!empty($err['data'])) {
  26708. $err['headline'] = 'Install Errors';
  26709. $this->ui->outputData($err);
  26710. }
  26711. if (!count($downloaded)) {
  26712. return $this->raiseError("$command failed");
  26713. }
  26714. }
  26715. $data = array(
  26716. 'headline' => 'Packages that would be Installed'
  26717. );
  26718. if (isset($options['pretend'])) {
  26719. foreach ($downloaded as $package) {
  26720. $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
  26721. }
  26722. $this->ui->outputData($data, 'pretend');
  26723. return true;
  26724. }
  26725. $this->installer->setOptions($options);
  26726. $this->installer->sortPackagesForInstall($downloaded);
  26727. if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
  26728. $this->raiseError($err->getMessage());
  26729. return true;
  26730. }
  26731. $binaries = $extrainfo = array();
  26732. foreach ($downloaded as $param) {
  26733. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26734. $info = $this->installer->install($param, $options);
  26735. PEAR::staticPopErrorHandling();
  26736. if (PEAR::isError($info)) {
  26737. $oldinfo = $info;
  26738. $pkg = &$param->getPackageFile();
  26739. if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
  26740. if (!($info = $pkg->installBinary($this->installer))) {
  26741. return $this->raiseError('ERROR: ' .$oldinfo->getMessage());
  26742. }
  26743. // we just installed a different package than requested,
  26744. // let's change the param and info so that the rest of this works
  26745. $param = $info[0];
  26746. $info = $info[1];
  26747. }
  26748. }
  26749. if (!is_array($info)) {
  26750. return $this->raiseError("$command failed");
  26751. }
  26752. if ($param->getPackageType() == 'extsrc' ||
  26753. $param->getPackageType() == 'extbin' ||
  26754. $param->getPackageType() == 'zendextsrc' ||
  26755. $param->getPackageType() == 'zendextbin'
  26756. ) {
  26757. $pkg = &$param->getPackageFile();
  26758. if ($instbin = $pkg->getInstalledBinary()) {
  26759. $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
  26760. } else {
  26761. $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
  26762. }
  26763. foreach ($instpkg->getFilelist() as $name => $atts) {
  26764. $pinfo = pathinfo($atts['installed_as']);
  26765. if (!isset($pinfo['extension']) ||
  26766. in_array($pinfo['extension'], array('c', 'h'))
  26767. ) {
  26768. continue; // make sure we don't match php_blah.h
  26769. }
  26770. if ((strpos($pinfo['basename'], 'php_') === 0 &&
  26771. $pinfo['extension'] == 'dll') ||
  26772. // most unices
  26773. $pinfo['extension'] == 'so' ||
  26774. // hp-ux
  26775. $pinfo['extension'] == 'sl') {
  26776. $binaries[] = array($atts['installed_as'], $pinfo);
  26777. break;
  26778. }
  26779. }
  26780. if (count($binaries)) {
  26781. foreach ($binaries as $pinfo) {
  26782. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26783. $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
  26784. PEAR::staticPopErrorHandling();
  26785. if (PEAR::isError($ret)) {
  26786. $extrainfo[] = $ret->getMessage();
  26787. if ($param->getPackageType() == 'extsrc' ||
  26788. $param->getPackageType() == 'extbin') {
  26789. $exttype = 'extension';
  26790. $extpath = $pinfo[1]['basename'];
  26791. } else {
  26792. $exttype = 'zend_extension';
  26793. $extpath = $atts['installed_as'];
  26794. }
  26795. $extrainfo[] = 'You should add "' . $exttype . '=' .
  26796. $extpath . '" to php.ini';
  26797. } else {
  26798. $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
  26799. ' enabled in php.ini';
  26800. }
  26801. }
  26802. }
  26803. }
  26804. if ($this->config->get('verbose') > 0) {
  26805. $chan = $param->getChannel();
  26806. $label = $reg->parsedPackageNameToString(
  26807. array(
  26808. 'channel' => $chan,
  26809. 'package' => $param->getPackage(),
  26810. 'version' => $param->getVersion(),
  26811. ));
  26812. $out = array('data' => "$command ok: $label");
  26813. if (isset($info['release_warnings'])) {
  26814. $out['release_warnings'] = $info['release_warnings'];
  26815. }
  26816. $this->ui->outputData($out, $command);
  26817. if (!isset($options['register-only']) && !isset($options['offline'])) {
  26818. if ($this->config->isDefinedLayer('ftp')) {
  26819. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26820. $info = $this->installer->ftpInstall($param);
  26821. PEAR::staticPopErrorHandling();
  26822. if (PEAR::isError($info)) {
  26823. $this->ui->outputData($info->getMessage());
  26824. $this->ui->outputData("remote install failed: $label");
  26825. } else {
  26826. $this->ui->outputData("remote install ok: $label");
  26827. }
  26828. }
  26829. }
  26830. }
  26831. $deps = $param->getDeps();
  26832. if ($deps) {
  26833. if (isset($deps['group'])) {
  26834. $groups = $deps['group'];
  26835. if (!isset($groups[0])) {
  26836. $groups = array($groups);
  26837. }
  26838. foreach ($groups as $group) {
  26839. if ($group['attribs']['name'] == 'default') {
  26840. // default group is always installed, unless the user
  26841. // explicitly chooses to install another group
  26842. continue;
  26843. }
  26844. $extrainfo[] = $param->getPackage() . ': Optional feature ' .
  26845. $group['attribs']['name'] . ' available (' .
  26846. $group['attribs']['hint'] . ')';
  26847. }
  26848. $extrainfo[] = $param->getPackage() .
  26849. ': To install optional features use "pear install ' .
  26850. $reg->parsedPackageNameToString(
  26851. array('package' => $param->getPackage(),
  26852. 'channel' => $param->getChannel()), true) .
  26853. '#featurename"';
  26854. }
  26855. }
  26856. $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
  26857. // $pkg may be NULL if install is a 'fake' install via --packagingroot
  26858. if (is_object($pkg)) {
  26859. $pkg->setConfig($this->config);
  26860. if ($list = $pkg->listPostinstallScripts()) {
  26861. $pn = $reg->parsedPackageNameToString(array('channel' =>
  26862. $param->getChannel(), 'package' => $param->getPackage()), true);
  26863. $extrainfo[] = $pn . ' has post-install scripts:';
  26864. foreach ($list as $file) {
  26865. $extrainfo[] = $file;
  26866. }
  26867. $extrainfo[] = $param->getPackage() .
  26868. ': Use "pear run-scripts ' . $pn . '" to finish setup.';
  26869. $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
  26870. }
  26871. }
  26872. }
  26873. if (count($extrainfo)) {
  26874. foreach ($extrainfo as $info) {
  26875. $this->ui->outputData($info);
  26876. }
  26877. }
  26878. return true;
  26879. }
  26880. // }}}
  26881. // {{{ doUpgradeAll()
  26882. function doUpgradeAll($command, $options, $params)
  26883. {
  26884. $reg = &$this->config->getRegistry();
  26885. $upgrade = array();
  26886. if (isset($options['channel'])) {
  26887. $channels = array($options['channel']);
  26888. } else {
  26889. $channels = $reg->listChannels();
  26890. }
  26891. foreach ($channels as $channel) {
  26892. if ($channel == '__uri') {
  26893. continue;
  26894. }
  26895. // parse name with channel
  26896. foreach ($reg->listPackages($channel) as $name) {
  26897. $upgrade[] = $reg->parsedPackageNameToString(array(
  26898. 'channel' => $channel,
  26899. 'package' => $name
  26900. ));
  26901. }
  26902. }
  26903. $err = $this->doInstall($command, $options, $upgrade);
  26904. if (PEAR::isError($err)) {
  26905. $this->ui->outputData($err->getMessage(), $command);
  26906. }
  26907. }
  26908. // }}}
  26909. // {{{ doUninstall()
  26910. function doUninstall($command, $options, $params)
  26911. {
  26912. if (count($params) < 1) {
  26913. return $this->raiseError("Please supply the package(s) you want to uninstall");
  26914. }
  26915. if (empty($this->installer)) {
  26916. $this->installer = &$this->getInstaller($this->ui);
  26917. }
  26918. if (isset($options['remoteconfig'])) {
  26919. $e = $this->config->readFTPConfigFile($options['remoteconfig']);
  26920. if (!PEAR::isError($e)) {
  26921. $this->installer->setConfig($this->config);
  26922. }
  26923. }
  26924. $reg = &$this->config->getRegistry();
  26925. $newparams = array();
  26926. $binaries = array();
  26927. $badparams = array();
  26928. foreach ($params as $pkg) {
  26929. $channel = $this->config->get('default_channel');
  26930. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26931. $parsed = $reg->parsePackageName($pkg, $channel);
  26932. PEAR::staticPopErrorHandling();
  26933. if (!$parsed || PEAR::isError($parsed)) {
  26934. $badparams[] = $pkg;
  26935. continue;
  26936. }
  26937. $package = $parsed['package'];
  26938. $channel = $parsed['channel'];
  26939. $info = &$reg->getPackage($package, $channel);
  26940. if ($info === null &&
  26941. ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
  26942. // make sure this isn't a package that has flipped from pear to pecl but
  26943. // used a package.xml 1.0
  26944. $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
  26945. $info = &$reg->getPackage($package, $testc);
  26946. if ($info !== null) {
  26947. $channel = $testc;
  26948. }
  26949. }
  26950. if ($info === null) {
  26951. $badparams[] = $pkg;
  26952. } else {
  26953. $newparams[] = &$info;
  26954. // check for binary packages (this is an alias for those packages if so)
  26955. if ($installedbinary = $info->getInstalledBinary()) {
  26956. $this->ui->log('adding binary package ' .
  26957. $reg->parsedPackageNameToString(array('channel' => $channel,
  26958. 'package' => $installedbinary), true));
  26959. $newparams[] = &$reg->getPackage($installedbinary, $channel);
  26960. }
  26961. // add the contents of a dependency group to the list of installed packages
  26962. if (isset($parsed['group'])) {
  26963. $group = $info->getDependencyGroup($parsed['group']);
  26964. if ($group) {
  26965. $installed = $reg->getInstalledGroup($group);
  26966. if ($installed) {
  26967. foreach ($installed as $i => $p) {
  26968. $newparams[] = &$installed[$i];
  26969. }
  26970. }
  26971. }
  26972. }
  26973. }
  26974. }
  26975. $err = $this->installer->sortPackagesForUninstall($newparams);
  26976. if (PEAR::isError($err)) {
  26977. $this->ui->outputData($err->getMessage(), $command);
  26978. return true;
  26979. }
  26980. $params = $newparams;
  26981. // twist this to use it to check on whether dependent packages are also being uninstalled
  26982. // for circular dependencies like subpackages
  26983. $this->installer->setUninstallPackages($newparams);
  26984. $params = array_merge($params, $badparams);
  26985. $binaries = array();
  26986. foreach ($params as $pkg) {
  26987. $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  26988. if ($err = $this->installer->uninstall($pkg, $options)) {
  26989. $this->installer->popErrorHandling();
  26990. if (PEAR::isError($err)) {
  26991. $this->ui->outputData($err->getMessage(), $command);
  26992. continue;
  26993. }
  26994. if ($pkg->getPackageType() == 'extsrc' ||
  26995. $pkg->getPackageType() == 'extbin' ||
  26996. $pkg->getPackageType() == 'zendextsrc' ||
  26997. $pkg->getPackageType() == 'zendextbin') {
  26998. if ($instbin = $pkg->getInstalledBinary()) {
  26999. continue; // this will be uninstalled later
  27000. }
  27001. foreach ($pkg->getFilelist() as $name => $atts) {
  27002. $pinfo = pathinfo($atts['installed_as']);
  27003. if (!isset($pinfo['extension']) ||
  27004. in_array($pinfo['extension'], array('c', 'h'))) {
  27005. continue; // make sure we don't match php_blah.h
  27006. }
  27007. if ((strpos($pinfo['basename'], 'php_') === 0 &&
  27008. $pinfo['extension'] == 'dll') ||
  27009. // most unices
  27010. $pinfo['extension'] == 'so' ||
  27011. // hp-ux
  27012. $pinfo['extension'] == 'sl') {
  27013. $binaries[] = array($atts['installed_as'], $pinfo);
  27014. break;
  27015. }
  27016. }
  27017. if (count($binaries)) {
  27018. foreach ($binaries as $pinfo) {
  27019. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27020. $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
  27021. PEAR::staticPopErrorHandling();
  27022. if (PEAR::isError($ret)) {
  27023. $extrainfo[] = $ret->getMessage();
  27024. if ($pkg->getPackageType() == 'extsrc' ||
  27025. $pkg->getPackageType() == 'extbin') {
  27026. $exttype = 'extension';
  27027. } else {
  27028. ob_start();
  27029. phpinfo(INFO_GENERAL);
  27030. $info = ob_get_contents();
  27031. ob_end_clean();
  27032. $debug = function_exists('leak') ? '_debug' : '';
  27033. $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  27034. $exttype = 'zend_extension' . $debug . $ts;
  27035. }
  27036. $this->ui->outputData('Unable to remove "' . $exttype . '=' .
  27037. $pinfo[1]['basename'] . '" from php.ini', $command);
  27038. } else {
  27039. $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
  27040. ' disabled in php.ini', $command);
  27041. }
  27042. }
  27043. }
  27044. }
  27045. $savepkg = $pkg;
  27046. if ($this->config->get('verbose') > 0) {
  27047. if (is_object($pkg)) {
  27048. $pkg = $reg->parsedPackageNameToString($pkg);
  27049. }
  27050. $this->ui->outputData("uninstall ok: $pkg", $command);
  27051. }
  27052. if (!isset($options['offline']) && is_object($savepkg) &&
  27053. defined('PEAR_REMOTEINSTALL_OK')) {
  27054. if ($this->config->isDefinedLayer('ftp')) {
  27055. $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  27056. $info = $this->installer->ftpUninstall($savepkg);
  27057. $this->installer->popErrorHandling();
  27058. if (PEAR::isError($info)) {
  27059. $this->ui->outputData($info->getMessage());
  27060. $this->ui->outputData("remote uninstall failed: $pkg");
  27061. } else {
  27062. $this->ui->outputData("remote uninstall ok: $pkg");
  27063. }
  27064. }
  27065. }
  27066. } else {
  27067. $this->installer->popErrorHandling();
  27068. if (!is_object($pkg)) {
  27069. return $this->raiseError("uninstall failed: $pkg");
  27070. }
  27071. $pkg = $reg->parsedPackageNameToString($pkg);
  27072. }
  27073. }
  27074. return true;
  27075. }
  27076. // }}}
  27077. // }}}
  27078. // {{{ doBundle()
  27079. /*
  27080. (cox) It just downloads and untars the package, does not do
  27081. any check that the PEAR_Installer::_installFile() does.
  27082. */
  27083. function doBundle($command, $options, $params)
  27084. {
  27085. $opts = array(
  27086. 'force' => true,
  27087. 'nodeps' => true,
  27088. 'soft' => true,
  27089. 'downloadonly' => true
  27090. );
  27091. $downloader = &$this->getDownloader($this->ui, $opts, $this->config);
  27092. $reg = &$this->config->getRegistry();
  27093. if (count($params) < 1) {
  27094. return $this->raiseError("Please supply the package you want to bundle");
  27095. }
  27096. if (isset($options['destination'])) {
  27097. if (!is_dir($options['destination'])) {
  27098. System::mkdir('-p ' . $options['destination']);
  27099. }
  27100. $dest = realpath($options['destination']);
  27101. } else {
  27102. $pwd = getcwd();
  27103. $dir = $pwd . DIRECTORY_SEPARATOR . 'ext';
  27104. $dest = is_dir($dir) ? $dir : $pwd;
  27105. }
  27106. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27107. $err = $downloader->setDownloadDir($dest);
  27108. PEAR::staticPopErrorHandling();
  27109. if (PEAR::isError($err)) {
  27110. return PEAR::raiseError('download directory "' . $dest .
  27111. '" is not writeable.');
  27112. }
  27113. $result = &$downloader->download(array($params[0]));
  27114. if (PEAR::isError($result)) {
  27115. return $result;
  27116. }
  27117. if (!isset($result[0])) {
  27118. return $this->raiseError('unable to unpack ' . $params[0]);
  27119. }
  27120. $pkgfile = &$result[0]->getPackageFile();
  27121. $pkgname = $pkgfile->getName();
  27122. $pkgversion = $pkgfile->getVersion();
  27123. // Unpacking -------------------------------------------------
  27124. $dest .= DIRECTORY_SEPARATOR . $pkgname;
  27125. $orig = $pkgname . '-' . $pkgversion;
  27126. $tar = new Archive_Tar($pkgfile->getArchiveFile());
  27127. if (!$tar->extractModify($dest, $orig)) {
  27128. return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
  27129. }
  27130. $this->ui->outputData("Package ready at '$dest'");
  27131. // }}}
  27132. }
  27133. // }}}
  27134. function doRunScripts($command, $options, $params)
  27135. {
  27136. if (!isset($params[0])) {
  27137. return $this->raiseError('run-scripts expects 1 parameter: a package name');
  27138. }
  27139. $reg = &$this->config->getRegistry();
  27140. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27141. $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  27142. PEAR::staticPopErrorHandling();
  27143. if (PEAR::isError($parsed)) {
  27144. return $this->raiseError($parsed);
  27145. }
  27146. $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
  27147. if (!is_object($package)) {
  27148. return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
  27149. }
  27150. $package->setConfig($this->config);
  27151. $package->runPostinstallScripts();
  27152. $this->ui->outputData('Install scripts complete', $command);
  27153. return true;
  27154. }
  27155. /**
  27156. * Given a list of packages, filter out those ones that are already up to date
  27157. *
  27158. * @param $packages: packages, in parsed array format !
  27159. * @return list of packages that can be upgraded
  27160. */
  27161. function _filterUptodatePackages($packages, $command)
  27162. {
  27163. $reg = &$this->config->getRegistry();
  27164. $latestReleases = array();
  27165. $ret = array();
  27166. foreach ($packages as $package) {
  27167. if (isset($package['group'])) {
  27168. $ret[] = $package;
  27169. continue;
  27170. }
  27171. $channel = $package['channel'];
  27172. $name = $package['package'];
  27173. if (!$reg->packageExists($name, $channel)) {
  27174. $ret[] = $package;
  27175. continue;
  27176. }
  27177. if (!isset($latestReleases[$channel])) {
  27178. // fill in cache for this channel
  27179. $chan = $reg->getChannel($channel);
  27180. if (PEAR::isError($chan)) {
  27181. return $this->raiseError($chan);
  27182. }
  27183. $base2 = false;
  27184. $preferred_mirror = $this->config->get('preferred_mirror', null, $channel);
  27185. if ($chan->supportsREST($preferred_mirror) &&
  27186. (
  27187. //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) ||
  27188. ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
  27189. )
  27190. ) {
  27191. $dorest = true;
  27192. }
  27193. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27194. if (!isset($package['state'])) {
  27195. $state = $this->config->get('preferred_state', null, $channel);
  27196. } else {
  27197. $state = $package['state'];
  27198. }
  27199. if ($dorest) {
  27200. if ($base2) {
  27201. $rest = &$this->config->getREST('1.4', array());
  27202. $base = $base2;
  27203. } else {
  27204. $rest = &$this->config->getREST('1.0', array());
  27205. }
  27206. $installed = array_flip($reg->listPackages($channel));
  27207. $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
  27208. }
  27209. PEAR::staticPopErrorHandling();
  27210. if (PEAR::isError($latest)) {
  27211. $this->ui->outputData('Error getting channel info from ' . $channel .
  27212. ': ' . $latest->getMessage());
  27213. continue;
  27214. }
  27215. $latestReleases[$channel] = array_change_key_case($latest);
  27216. }
  27217. // check package for latest release
  27218. $name_lower = strtolower($name);
  27219. if (isset($latestReleases[$channel][$name_lower])) {
  27220. // if not set, up to date
  27221. $inst_version = $reg->packageInfo($name, 'version', $channel);
  27222. $channel_version = $latestReleases[$channel][$name_lower]['version'];
  27223. if (version_compare($channel_version, $inst_version, 'le')) {
  27224. // installed version is up-to-date
  27225. continue;
  27226. }
  27227. // maintain BC
  27228. if ($command == 'upgrade-all') {
  27229. $this->ui->outputData(array('data' => 'Will upgrade ' .
  27230. $reg->parsedPackageNameToString($package)), $command);
  27231. }
  27232. $ret[] = $package;
  27233. }
  27234. }
  27235. return $ret;
  27236. }
  27237. }
  27238. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Mirror.xml����������������������������������������������������������������0000644�0001750�0001750�00000001151�13565304531�016355� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  27239. <download-all>
  27240. <summary>Downloads each available package from the default channel</summary>
  27241. <function>doDownloadAll</function>
  27242. <shortcut>da</shortcut>
  27243. <options>
  27244. <channel>
  27245. <shortopt>c</shortopt>
  27246. <doc>specify a channel other than the default channel</doc>
  27247. <arg>CHAN</arg>
  27248. </channel>
  27249. </options>
  27250. <doc>
  27251. Requests a list of available packages from the default channel ({config default_channel})
  27252. and downloads them to current working directory. Note: only
  27253. packages within preferred_state ({config preferred_state}) will be downloaded</doc>
  27254. </download-all>
  27255. </commands>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Mirror.php����������������������������������������������������������������0000644�0001750�0001750�00000010636�13565304531�016354� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  27256. /**
  27257. * PEAR_Command_Mirror (download-all command)
  27258. *
  27259. * PHP versions 4 and 5
  27260. *
  27261. * @category pear
  27262. * @package PEAR
  27263. * @author Alexander Merz <alexmerz@php.net>
  27264. * @copyright 1997-2009 The Authors
  27265. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  27266. * @link http://pear.php.net/package/PEAR
  27267. * @since File available since Release 1.2.0
  27268. */
  27269. /**
  27270. * base class
  27271. */
  27272. require_once 'PEAR/Command/Common.php';
  27273. /**
  27274. * PEAR commands for providing file mirrors
  27275. *
  27276. * @category pear
  27277. * @package PEAR
  27278. * @author Alexander Merz <alexmerz@php.net>
  27279. * @copyright 1997-2009 The Authors
  27280. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  27281. * @version Release: 1.10.10
  27282. * @link http://pear.php.net/package/PEAR
  27283. * @since Class available since Release 1.2.0
  27284. */
  27285. class PEAR_Command_Mirror extends PEAR_Command_Common
  27286. {
  27287. var $commands = array(
  27288. 'download-all' => array(
  27289. 'summary' => 'Downloads each available package from the default channel',
  27290. 'function' => 'doDownloadAll',
  27291. 'shortcut' => 'da',
  27292. 'options' => array(
  27293. 'channel' =>
  27294. array(
  27295. 'shortopt' => 'c',
  27296. 'doc' => 'specify a channel other than the default channel',
  27297. 'arg' => 'CHAN',
  27298. ),
  27299. ),
  27300. 'doc' => '
  27301. Requests a list of available packages from the default channel ({config default_channel})
  27302. and downloads them to current working directory. Note: only
  27303. packages within preferred_state ({config preferred_state}) will be downloaded'
  27304. ),
  27305. );
  27306. /**
  27307. * PEAR_Command_Mirror constructor.
  27308. *
  27309. * @access public
  27310. * @param object PEAR_Frontend a reference to an frontend
  27311. * @param object PEAR_Config a reference to the configuration data
  27312. */
  27313. function __construct(&$ui, &$config)
  27314. {
  27315. parent::__construct($ui, $config);
  27316. }
  27317. /**
  27318. * For unit-testing
  27319. */
  27320. function &factory($a)
  27321. {
  27322. $a = &PEAR_Command::factory($a, $this->config);
  27323. return $a;
  27324. }
  27325. /**
  27326. * retrieves a list of avaible Packages from master server
  27327. * and downloads them
  27328. *
  27329. * @access public
  27330. * @param string $command the command
  27331. * @param array $options the command options before the command
  27332. * @param array $params the stuff after the command name
  27333. * @return bool true if successful
  27334. * @throw PEAR_Error
  27335. */
  27336. function doDownloadAll($command, $options, $params)
  27337. {
  27338. $savechannel = $this->config->get('default_channel');
  27339. $reg = &$this->config->getRegistry();
  27340. $channel = isset($options['channel']) ? $options['channel'] :
  27341. $this->config->get('default_channel');
  27342. if (!$reg->channelExists($channel)) {
  27343. $this->config->set('default_channel', $savechannel);
  27344. return $this->raiseError('Channel "' . $channel . '" does not exist');
  27345. }
  27346. $this->config->set('default_channel', $channel);
  27347. $this->ui->outputData('Using Channel ' . $this->config->get('default_channel'));
  27348. $chan = $reg->getChannel($channel);
  27349. if (PEAR::isError($chan)) {
  27350. return $this->raiseError($chan);
  27351. }
  27352. if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  27353. $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  27354. $rest = &$this->config->getREST('1.0', array());
  27355. $remoteInfo = array_flip($rest->listPackages($base, $channel));
  27356. }
  27357. if (PEAR::isError($remoteInfo)) {
  27358. return $remoteInfo;
  27359. }
  27360. $cmd = &$this->factory("download");
  27361. if (PEAR::isError($cmd)) {
  27362. return $cmd;
  27363. }
  27364. $this->ui->outputData('Using Preferred State of ' .
  27365. $this->config->get('preferred_state'));
  27366. $this->ui->outputData('Gathering release information, please wait...');
  27367. /**
  27368. * Error handling not necessary, because already done by
  27369. * the download command
  27370. */
  27371. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27372. $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo));
  27373. PEAR::staticPopErrorHandling();
  27374. $this->config->set('default_channel', $savechannel);
  27375. if (PEAR::isError($err)) {
  27376. $this->ui->outputData($err->getMessage());
  27377. }
  27378. return true;
  27379. }
  27380. }
  27381. ��������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Package.xml���������������������������������������������������������������0000644�0001750�0001750�00000016066�13565304531�016451� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  27382. <package>
  27383. <summary>Build Package</summary>
  27384. <function>doPackage</function>
  27385. <shortcut>p</shortcut>
  27386. <options>
  27387. <nocompress>
  27388. <shortopt>Z</shortopt>
  27389. <doc>Do not gzip the package file</doc>
  27390. </nocompress>
  27391. <showname>
  27392. <shortopt>n</shortopt>
  27393. <doc>Print the name of the packaged file.</doc>
  27394. </showname>
  27395. </options>
  27396. <doc>[descfile] [descfile2]
  27397. Creates a PEAR package from its description file (usually called
  27398. package.xml). If a second packagefile is passed in, then
  27399. the packager will check to make sure that one is a package.xml
  27400. version 1.0, and the other is a package.xml version 2.0. The
  27401. package.xml version 1.0 will be saved as &quot;package.xml&quot; in the archive,
  27402. and the other as &quot;package2.xml&quot; in the archive&quot;
  27403. </doc>
  27404. </package>
  27405. <package-validate>
  27406. <summary>Validate Package Consistency</summary>
  27407. <function>doPackageValidate</function>
  27408. <shortcut>pv</shortcut>
  27409. <options />
  27410. <doc>
  27411. </doc>
  27412. </package-validate>
  27413. <cvsdiff>
  27414. <summary>Run a &quot;cvs diff&quot; for all files in a package</summary>
  27415. <function>doCvsDiff</function>
  27416. <shortcut>cd</shortcut>
  27417. <options>
  27418. <quiet>
  27419. <shortopt>q</shortopt>
  27420. <doc>Be quiet</doc>
  27421. </quiet>
  27422. <reallyquiet>
  27423. <shortopt>Q</shortopt>
  27424. <doc>Be really quiet</doc>
  27425. </reallyquiet>
  27426. <date>
  27427. <shortopt>D</shortopt>
  27428. <doc>Diff against revision of DATE</doc>
  27429. <arg>DATE</arg>
  27430. </date>
  27431. <release>
  27432. <shortopt>R</shortopt>
  27433. <doc>Diff against tag for package release REL</doc>
  27434. <arg>REL</arg>
  27435. </release>
  27436. <revision>
  27437. <shortopt>r</shortopt>
  27438. <doc>Diff against revision REV</doc>
  27439. <arg>REV</arg>
  27440. </revision>
  27441. <context>
  27442. <shortopt>c</shortopt>
  27443. <doc>Generate context diff</doc>
  27444. </context>
  27445. <unified>
  27446. <shortopt>u</shortopt>
  27447. <doc>Generate unified diff</doc>
  27448. </unified>
  27449. <ignore-case>
  27450. <shortopt>i</shortopt>
  27451. <doc>Ignore case, consider upper- and lower-case letters equivalent</doc>
  27452. </ignore-case>
  27453. <ignore-whitespace>
  27454. <shortopt>b</shortopt>
  27455. <doc>Ignore changes in amount of white space</doc>
  27456. </ignore-whitespace>
  27457. <ignore-blank-lines>
  27458. <shortopt>B</shortopt>
  27459. <doc>Ignore changes that insert or delete blank lines</doc>
  27460. </ignore-blank-lines>
  27461. <brief>
  27462. <shortopt></shortopt>
  27463. <doc>Report only whether the files differ, no details</doc>
  27464. </brief>
  27465. <dry-run>
  27466. <shortopt>n</shortopt>
  27467. <doc>Don&#039;t do anything, just pretend</doc>
  27468. </dry-run>
  27469. </options>
  27470. <doc>&lt;package.xml&gt;
  27471. Compares all the files in a package. Without any options, this
  27472. command will compare the current code with the last checked-in code.
  27473. Using the -r or -R option you may compare the current code with that
  27474. of a specific release.
  27475. </doc>
  27476. </cvsdiff>
  27477. <svntag>
  27478. <summary>Set SVN Release Tag</summary>
  27479. <function>doSvnTag</function>
  27480. <shortcut>sv</shortcut>
  27481. <options>
  27482. <quiet>
  27483. <shortopt>q</shortopt>
  27484. <doc>Be quiet</doc>
  27485. </quiet>
  27486. <slide>
  27487. <shortopt>F</shortopt>
  27488. <doc>Move (slide) tag if it exists</doc>
  27489. </slide>
  27490. <delete>
  27491. <shortopt>d</shortopt>
  27492. <doc>Remove tag</doc>
  27493. </delete>
  27494. <dry-run>
  27495. <shortopt>n</shortopt>
  27496. <doc>Don&#039;t do anything, just pretend</doc>
  27497. </dry-run>
  27498. </options>
  27499. <doc>&lt;package.xml&gt; [files...]
  27500. Sets a SVN tag on all files in a package. Use this command after you have
  27501. packaged a distribution tarball with the &quot;package&quot; command to tag what
  27502. revisions of what files were in that release. If need to fix something
  27503. after running svntag once, but before the tarball is released to the public,
  27504. use the &quot;slide&quot; option to move the release tag.
  27505. to include files (such as a second package.xml, or tests not included in the
  27506. release), pass them as additional parameters.
  27507. </doc>
  27508. </svntag>
  27509. <cvstag>
  27510. <summary>Set CVS Release Tag</summary>
  27511. <function>doCvsTag</function>
  27512. <shortcut>ct</shortcut>
  27513. <options>
  27514. <quiet>
  27515. <shortopt>q</shortopt>
  27516. <doc>Be quiet</doc>
  27517. </quiet>
  27518. <reallyquiet>
  27519. <shortopt>Q</shortopt>
  27520. <doc>Be really quiet</doc>
  27521. </reallyquiet>
  27522. <slide>
  27523. <shortopt>F</shortopt>
  27524. <doc>Move (slide) tag if it exists</doc>
  27525. </slide>
  27526. <delete>
  27527. <shortopt>d</shortopt>
  27528. <doc>Remove tag</doc>
  27529. </delete>
  27530. <dry-run>
  27531. <shortopt>n</shortopt>
  27532. <doc>Don&#039;t do anything, just pretend</doc>
  27533. </dry-run>
  27534. </options>
  27535. <doc>&lt;package.xml&gt; [files...]
  27536. Sets a CVS tag on all files in a package. Use this command after you have
  27537. packaged a distribution tarball with the &quot;package&quot; command to tag what
  27538. revisions of what files were in that release. If need to fix something
  27539. after running cvstag once, but before the tarball is released to the public,
  27540. use the &quot;slide&quot; option to move the release tag.
  27541. to include files (such as a second package.xml, or tests not included in the
  27542. release), pass them as additional parameters.
  27543. </doc>
  27544. </cvstag>
  27545. <package-dependencies>
  27546. <summary>Show package dependencies</summary>
  27547. <function>doPackageDependencies</function>
  27548. <shortcut>pd</shortcut>
  27549. <options />
  27550. <doc>&lt;package-file&gt; or &lt;package.xml&gt; or &lt;install-package-name&gt;
  27551. List all dependencies the package has.
  27552. Can take a tgz / tar file, package.xml or a package name of an installed package.</doc>
  27553. </package-dependencies>
  27554. <sign>
  27555. <summary>Sign a package distribution file</summary>
  27556. <function>doSign</function>
  27557. <shortcut>si</shortcut>
  27558. <options>
  27559. <verbose>
  27560. <shortopt>v</shortopt>
  27561. <doc>Display GnuPG output</doc>
  27562. </verbose>
  27563. </options>
  27564. <doc>&lt;package-file&gt;
  27565. Signs a package distribution (.tar or .tgz) file with GnuPG.</doc>
  27566. </sign>
  27567. <makerpm>
  27568. <summary>Builds an RPM spec file from a PEAR package</summary>
  27569. <function>doMakeRPM</function>
  27570. <shortcut>rpm</shortcut>
  27571. <options>
  27572. <spec-template>
  27573. <shortopt>t</shortopt>
  27574. <doc>Use FILE as RPM spec file template</doc>
  27575. <arg>FILE</arg>
  27576. </spec-template>
  27577. <rpm-pkgname>
  27578. <shortopt>p</shortopt>
  27579. <doc>Use FORMAT as format string for RPM package name, %s is replaced
  27580. by the PEAR package name, defaults to &quot;PEAR::%s&quot;.</doc>
  27581. <arg>FORMAT</arg>
  27582. </rpm-pkgname>
  27583. </options>
  27584. <doc>&lt;package-file&gt;
  27585. Creates an RPM .spec file for wrapping a PEAR package inside an RPM
  27586. package. Intended to be used from the SPECS directory, with the PEAR
  27587. package tarball in the SOURCES directory:
  27588. $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
  27589. Wrote RPM spec file PEAR::Net_Geo-1.0.spec
  27590. $ rpm -bb PEAR::Net_Socket-1.0.spec
  27591. ...
  27592. Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
  27593. </doc>
  27594. </makerpm>
  27595. <convert>
  27596. <summary>Convert a package.xml 1.0 to package.xml 2.0 format</summary>
  27597. <function>doConvert</function>
  27598. <shortcut>c2</shortcut>
  27599. <options>
  27600. <flat>
  27601. <shortopt>f</shortopt>
  27602. <doc>do not beautify the filelist.</doc>
  27603. </flat>
  27604. </options>
  27605. <doc>[descfile] [descfile2]
  27606. Converts a package.xml in 1.0 format into a package.xml
  27607. in 2.0 format. The new file will be named package2.xml by default,
  27608. and package.xml will be used as the old file by default.
  27609. This is not the most intelligent conversion, and should only be
  27610. used for automated conversion or learning the format.
  27611. </doc>
  27612. </convert>
  27613. </commands>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Package.php���������������������������������������������������������������0000644�0001750�0001750�00000116334�13565304531�016437� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  27614. /**
  27615. * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
  27616. * sign, makerpm, convert commands)
  27617. *
  27618. * PHP versions 4 and 5
  27619. *
  27620. * @category pear
  27621. * @package PEAR
  27622. * @author Stig Bakken <ssb@php.net>
  27623. * @author Martin Jansen <mj@php.net>
  27624. * @author Greg Beaver <cellog@php.net>
  27625. * @copyright 1997-2009 The Authors
  27626. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  27627. * @link http://pear.php.net/package/PEAR
  27628. * @since File available since Release 0.1
  27629. */
  27630. /**
  27631. * base class
  27632. */
  27633. require_once 'PEAR/Command/Common.php';
  27634. /**
  27635. * PEAR commands for login/logout
  27636. *
  27637. * @category pear
  27638. * @package PEAR
  27639. * @author Stig Bakken <ssb@php.net>
  27640. * @author Martin Jansen <mj@php.net>
  27641. * @author Greg Beaver <cellog@php.net>
  27642. * @copyright 1997-2009 The Authors
  27643. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  27644. * @version Release: @package_version@
  27645. * @link http://pear.php.net/package/PEAR
  27646. * @since Class available since Release 0.1
  27647. */
  27648. class PEAR_Command_Package extends PEAR_Command_Common
  27649. {
  27650. var $commands = array(
  27651. 'package' => array(
  27652. 'summary' => 'Build Package',
  27653. 'function' => 'doPackage',
  27654. 'shortcut' => 'p',
  27655. 'options' => array(
  27656. 'nocompress' => array(
  27657. 'shortopt' => 'Z',
  27658. 'doc' => 'Do not gzip the package file'
  27659. ),
  27660. 'showname' => array(
  27661. 'shortopt' => 'n',
  27662. 'doc' => 'Print the name of the packaged file.',
  27663. ),
  27664. ),
  27665. 'doc' => '[descfile] [descfile2]
  27666. Creates a PEAR package from its description file (usually called
  27667. package.xml). If a second packagefile is passed in, then
  27668. the packager will check to make sure that one is a package.xml
  27669. version 1.0, and the other is a package.xml version 2.0. The
  27670. package.xml version 1.0 will be saved as "package.xml" in the archive,
  27671. and the other as "package2.xml" in the archive"
  27672. '
  27673. ),
  27674. 'package-validate' => array(
  27675. 'summary' => 'Validate Package Consistency',
  27676. 'function' => 'doPackageValidate',
  27677. 'shortcut' => 'pv',
  27678. 'options' => array(),
  27679. 'doc' => '
  27680. ',
  27681. ),
  27682. 'cvsdiff' => array(
  27683. 'summary' => 'Run a "cvs diff" for all files in a package',
  27684. 'function' => 'doCvsDiff',
  27685. 'shortcut' => 'cd',
  27686. 'options' => array(
  27687. 'quiet' => array(
  27688. 'shortopt' => 'q',
  27689. 'doc' => 'Be quiet',
  27690. ),
  27691. 'reallyquiet' => array(
  27692. 'shortopt' => 'Q',
  27693. 'doc' => 'Be really quiet',
  27694. ),
  27695. 'date' => array(
  27696. 'shortopt' => 'D',
  27697. 'doc' => 'Diff against revision of DATE',
  27698. 'arg' => 'DATE',
  27699. ),
  27700. 'release' => array(
  27701. 'shortopt' => 'R',
  27702. 'doc' => 'Diff against tag for package release REL',
  27703. 'arg' => 'REL',
  27704. ),
  27705. 'revision' => array(
  27706. 'shortopt' => 'r',
  27707. 'doc' => 'Diff against revision REV',
  27708. 'arg' => 'REV',
  27709. ),
  27710. 'context' => array(
  27711. 'shortopt' => 'c',
  27712. 'doc' => 'Generate context diff',
  27713. ),
  27714. 'unified' => array(
  27715. 'shortopt' => 'u',
  27716. 'doc' => 'Generate unified diff',
  27717. ),
  27718. 'ignore-case' => array(
  27719. 'shortopt' => 'i',
  27720. 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
  27721. ),
  27722. 'ignore-whitespace' => array(
  27723. 'shortopt' => 'b',
  27724. 'doc' => 'Ignore changes in amount of white space',
  27725. ),
  27726. 'ignore-blank-lines' => array(
  27727. 'shortopt' => 'B',
  27728. 'doc' => 'Ignore changes that insert or delete blank lines',
  27729. ),
  27730. 'brief' => array(
  27731. 'doc' => 'Report only whether the files differ, no details',
  27732. ),
  27733. 'dry-run' => array(
  27734. 'shortopt' => 'n',
  27735. 'doc' => 'Don\'t do anything, just pretend',
  27736. ),
  27737. ),
  27738. 'doc' => '<package.xml>
  27739. Compares all the files in a package. Without any options, this
  27740. command will compare the current code with the last checked-in code.
  27741. Using the -r or -R option you may compare the current code with that
  27742. of a specific release.
  27743. ',
  27744. ),
  27745. 'svntag' => array(
  27746. 'summary' => 'Set SVN Release Tag',
  27747. 'function' => 'doSvnTag',
  27748. 'shortcut' => 'sv',
  27749. 'options' => array(
  27750. 'quiet' => array(
  27751. 'shortopt' => 'q',
  27752. 'doc' => 'Be quiet',
  27753. ),
  27754. 'slide' => array(
  27755. 'shortopt' => 'F',
  27756. 'doc' => 'Move (slide) tag if it exists',
  27757. ),
  27758. 'delete' => array(
  27759. 'shortopt' => 'd',
  27760. 'doc' => 'Remove tag',
  27761. ),
  27762. 'dry-run' => array(
  27763. 'shortopt' => 'n',
  27764. 'doc' => 'Don\'t do anything, just pretend',
  27765. ),
  27766. ),
  27767. 'doc' => '<package.xml> [files...]
  27768. Sets a SVN tag on all files in a package. Use this command after you have
  27769. packaged a distribution tarball with the "package" command to tag what
  27770. revisions of what files were in that release. If need to fix something
  27771. after running svntag once, but before the tarball is released to the public,
  27772. use the "slide" option to move the release tag.
  27773. to include files (such as a second package.xml, or tests not included in the
  27774. release), pass them as additional parameters.
  27775. ',
  27776. ),
  27777. 'cvstag' => array(
  27778. 'summary' => 'Set CVS Release Tag',
  27779. 'function' => 'doCvsTag',
  27780. 'shortcut' => 'ct',
  27781. 'options' => array(
  27782. 'quiet' => array(
  27783. 'shortopt' => 'q',
  27784. 'doc' => 'Be quiet',
  27785. ),
  27786. 'reallyquiet' => array(
  27787. 'shortopt' => 'Q',
  27788. 'doc' => 'Be really quiet',
  27789. ),
  27790. 'slide' => array(
  27791. 'shortopt' => 'F',
  27792. 'doc' => 'Move (slide) tag if it exists',
  27793. ),
  27794. 'delete' => array(
  27795. 'shortopt' => 'd',
  27796. 'doc' => 'Remove tag',
  27797. ),
  27798. 'dry-run' => array(
  27799. 'shortopt' => 'n',
  27800. 'doc' => 'Don\'t do anything, just pretend',
  27801. ),
  27802. ),
  27803. 'doc' => '<package.xml> [files...]
  27804. Sets a CVS tag on all files in a package. Use this command after you have
  27805. packaged a distribution tarball with the "package" command to tag what
  27806. revisions of what files were in that release. If need to fix something
  27807. after running cvstag once, but before the tarball is released to the public,
  27808. use the "slide" option to move the release tag.
  27809. to include files (such as a second package.xml, or tests not included in the
  27810. release), pass them as additional parameters.
  27811. ',
  27812. ),
  27813. 'package-dependencies' => array(
  27814. 'summary' => 'Show package dependencies',
  27815. 'function' => 'doPackageDependencies',
  27816. 'shortcut' => 'pd',
  27817. 'options' => array(),
  27818. 'doc' => '<package-file> or <package.xml> or <install-package-name>
  27819. List all dependencies the package has.
  27820. Can take a tgz / tar file, package.xml or a package name of an installed package.'
  27821. ),
  27822. 'sign' => array(
  27823. 'summary' => 'Sign a package distribution file',
  27824. 'function' => 'doSign',
  27825. 'shortcut' => 'si',
  27826. 'options' => array(
  27827. 'verbose' => array(
  27828. 'shortopt' => 'v',
  27829. 'doc' => 'Display GnuPG output',
  27830. ),
  27831. ),
  27832. 'doc' => '<package-file>
  27833. Signs a package distribution (.tar or .tgz) file with GnuPG.',
  27834. ),
  27835. 'makerpm' => array(
  27836. 'summary' => 'Builds an RPM spec file from a PEAR package',
  27837. 'function' => 'doMakeRPM',
  27838. 'shortcut' => 'rpm',
  27839. 'options' => array(
  27840. 'spec-template' => array(
  27841. 'shortopt' => 't',
  27842. 'arg' => 'FILE',
  27843. 'doc' => 'Use FILE as RPM spec file template'
  27844. ),
  27845. 'rpm-pkgname' => array(
  27846. 'shortopt' => 'p',
  27847. 'arg' => 'FORMAT',
  27848. 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
  27849. by the PEAR package name, defaults to "PEAR::%s".',
  27850. ),
  27851. ),
  27852. 'doc' => '<package-file>
  27853. Creates an RPM .spec file for wrapping a PEAR package inside an RPM
  27854. package. Intended to be used from the SPECS directory, with the PEAR
  27855. package tarball in the SOURCES directory:
  27856. $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
  27857. Wrote RPM spec file PEAR::Net_Geo-1.0.spec
  27858. $ rpm -bb PEAR::Net_Socket-1.0.spec
  27859. ...
  27860. Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
  27861. ',
  27862. ),
  27863. 'convert' => array(
  27864. 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
  27865. 'function' => 'doConvert',
  27866. 'shortcut' => 'c2',
  27867. 'options' => array(
  27868. 'flat' => array(
  27869. 'shortopt' => 'f',
  27870. 'doc' => 'do not beautify the filelist.',
  27871. ),
  27872. ),
  27873. 'doc' => '[descfile] [descfile2]
  27874. Converts a package.xml in 1.0 format into a package.xml
  27875. in 2.0 format. The new file will be named package2.xml by default,
  27876. and package.xml will be used as the old file by default.
  27877. This is not the most intelligent conversion, and should only be
  27878. used for automated conversion or learning the format.
  27879. '
  27880. ),
  27881. );
  27882. var $output;
  27883. /**
  27884. * PEAR_Command_Package constructor.
  27885. *
  27886. * @access public
  27887. */
  27888. function __construct(&$ui, &$config)
  27889. {
  27890. parent::__construct($ui, $config);
  27891. }
  27892. function _displayValidationResults($err, $warn, $strict = false)
  27893. {
  27894. foreach ($err as $e) {
  27895. $this->output .= "Error: $e\n";
  27896. }
  27897. foreach ($warn as $w) {
  27898. $this->output .= "Warning: $w\n";
  27899. }
  27900. $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
  27901. sizeof($err), sizeof($warn));
  27902. if ($strict && count($err) > 0) {
  27903. $this->output .= "Fix these errors and try again.";
  27904. return false;
  27905. }
  27906. return true;
  27907. }
  27908. function &getPackager()
  27909. {
  27910. if (!class_exists('PEAR_Packager')) {
  27911. require_once 'PEAR/Packager.php';
  27912. }
  27913. $a = new PEAR_Packager;
  27914. return $a;
  27915. }
  27916. function &getPackageFile($config, $debug = false)
  27917. {
  27918. if (!class_exists('PEAR_Common')) {
  27919. require_once 'PEAR/Common.php';
  27920. }
  27921. if (!class_exists('PEAR_PackageFile')) {
  27922. require_once 'PEAR/PackageFile.php';
  27923. }
  27924. $a = new PEAR_PackageFile($config, $debug);
  27925. $common = new PEAR_Common;
  27926. $common->ui = $this->ui;
  27927. $a->setLogger($common);
  27928. return $a;
  27929. }
  27930. function doPackage($command, $options, $params)
  27931. {
  27932. $this->output = '';
  27933. $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
  27934. $pkg2 = isset($params[1]) ? $params[1] : null;
  27935. if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) {
  27936. $pkg2 = 'package2.xml';
  27937. }
  27938. $packager = &$this->getPackager();
  27939. $compress = empty($options['nocompress']) ? true : false;
  27940. $result = $packager->package($pkginfofile, $compress, $pkg2);
  27941. if (PEAR::isError($result)) {
  27942. return $this->raiseError($result);
  27943. }
  27944. // Don't want output, only the package file name just created
  27945. if (isset($options['showname'])) {
  27946. $this->output = $result;
  27947. }
  27948. if ($this->output) {
  27949. $this->ui->outputData($this->output, $command);
  27950. }
  27951. return true;
  27952. }
  27953. function doPackageValidate($command, $options, $params)
  27954. {
  27955. $this->output = '';
  27956. if (count($params) < 1) {
  27957. $params[0] = 'package.xml';
  27958. }
  27959. $obj = &$this->getPackageFile($this->config, $this->_debug);
  27960. $obj->rawReturn();
  27961. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27962. $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
  27963. if (PEAR::isError($info)) {
  27964. $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
  27965. } else {
  27966. $archive = $info->getArchiveFile();
  27967. $tar = new Archive_Tar($archive);
  27968. $tar->extract(dirname($info->getPackageFile()));
  27969. $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
  27970. $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
  27971. basename($info->getPackageFile()));
  27972. }
  27973. PEAR::staticPopErrorHandling();
  27974. if (PEAR::isError($info)) {
  27975. return $this->raiseError($info);
  27976. }
  27977. $valid = false;
  27978. if ($info->getPackagexmlVersion() == '2.0') {
  27979. if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
  27980. $info->flattenFileList();
  27981. $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
  27982. }
  27983. } else {
  27984. $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
  27985. }
  27986. $err = $warn = array();
  27987. if ($errors = $info->getValidationWarnings()) {
  27988. foreach ($errors as $error) {
  27989. if ($error['level'] == 'warning') {
  27990. $warn[] = $error['message'];
  27991. } else {
  27992. $err[] = $error['message'];
  27993. }
  27994. }
  27995. }
  27996. $this->_displayValidationResults($err, $warn);
  27997. $this->ui->outputData($this->output, $command);
  27998. return true;
  27999. }
  28000. function doSvnTag($command, $options, $params)
  28001. {
  28002. $this->output = '';
  28003. $_cmd = $command;
  28004. if (count($params) < 1) {
  28005. $help = $this->getHelp($command);
  28006. return $this->raiseError("$command: missing parameter: $help[0]");
  28007. }
  28008. $packageFile = realpath($params[0]);
  28009. $dir = dirname($packageFile);
  28010. $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
  28011. $obj = &$this->getPackageFile($this->config, $this->_debug);
  28012. $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
  28013. if (PEAR::isError($info)) {
  28014. return $this->raiseError($info);
  28015. }
  28016. $err = $warn = array();
  28017. if (!$info->validate()) {
  28018. foreach ($info->getValidationWarnings() as $error) {
  28019. if ($error['level'] == 'warning') {
  28020. $warn[] = $error['message'];
  28021. } else {
  28022. $err[] = $error['message'];
  28023. }
  28024. }
  28025. }
  28026. if (!$this->_displayValidationResults($err, $warn, true)) {
  28027. $this->ui->outputData($this->output, $command);
  28028. return $this->raiseError('SVN tag failed');
  28029. }
  28030. $version = $info->getVersion();
  28031. $package = $info->getName();
  28032. $svntag = "$package-$version";
  28033. if (isset($options['delete'])) {
  28034. return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
  28035. }
  28036. $path = $this->_svnFindPath($packageFile);
  28037. // Check if there are any modified files
  28038. $fp = popen('svn st --xml ' . dirname($packageFile), "r");
  28039. $out = '';
  28040. while ($line = fgets($fp, 1024)) {
  28041. $out .= rtrim($line)."\n";
  28042. }
  28043. pclose($fp);
  28044. if (!isset($options['quiet']) && strpos($out, 'item="modified"')) {
  28045. $params = array(array(
  28046. 'name' => 'modified',
  28047. 'type' => 'yesno',
  28048. 'default' => 'no',
  28049. 'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not committed, do you still want to tag ' . $version . '?',
  28050. ));
  28051. $answers = $this->ui->confirmDialog($params);
  28052. if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) {
  28053. return true;
  28054. }
  28055. }
  28056. if (isset($options['slide'])) {
  28057. $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
  28058. }
  28059. // Check if tag already exists
  28060. $releaseTag = $path['local']['base'] . 'tags' . DIRECTORY_SEPARATOR . $svntag;
  28061. $existsCommand = 'svn ls ' . $path['base'] . 'tags/';
  28062. $fp = popen($existsCommand, "r");
  28063. $out = '';
  28064. while ($line = fgets($fp, 1024)) {
  28065. $out .= rtrim($line)."\n";
  28066. }
  28067. pclose($fp);
  28068. if (in_array($svntag . DIRECTORY_SEPARATOR, explode("\n", $out))) {
  28069. $this->ui->outputData($this->output, $command);
  28070. return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.');
  28071. } elseif (file_exists($path['local']['base'] . 'tags') === false) {
  28072. return $this->raiseError('Can not locate the tags directory at ' . $path['local']['base'] . 'tags');
  28073. } elseif (is_writeable($path['local']['base'] . 'tags') === false) {
  28074. return $this->raiseError('Can not write to the tag directory at ' . $path['local']['base'] . 'tags');
  28075. } else {
  28076. $makeCommand = 'svn mkdir ' . $releaseTag;
  28077. $this->output .= "+ $makeCommand\n";
  28078. if (empty($options['dry-run'])) {
  28079. // We need to create the tag dir.
  28080. $fp = popen($makeCommand, "r");
  28081. $out = '';
  28082. while ($line = fgets($fp, 1024)) {
  28083. $out .= rtrim($line)."\n";
  28084. }
  28085. pclose($fp);
  28086. $this->output .= "$out\n";
  28087. }
  28088. }
  28089. $command = 'svn';
  28090. if (isset($options['quiet'])) {
  28091. $command .= ' -q';
  28092. }
  28093. $command .= ' copy --parents ';
  28094. $dir = dirname($packageFile);
  28095. $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
  28096. $files = array_keys($info->getFilelist());
  28097. if (!in_array(basename($packageFile), $files)) {
  28098. $files[] = basename($packageFile);
  28099. }
  28100. array_shift($params);
  28101. if (count($params)) {
  28102. // add in additional files to be tagged (package files and such)
  28103. $files = array_merge($files, $params);
  28104. }
  28105. $commands = array();
  28106. foreach ($files as $file) {
  28107. if (!file_exists($file)) {
  28108. $file = $dir . DIRECTORY_SEPARATOR . $file;
  28109. }
  28110. $commands[] = $command . ' ' . escapeshellarg($file) . ' ' .
  28111. escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file);
  28112. }
  28113. $this->output .= implode("\n", $commands) . "\n";
  28114. if (empty($options['dry-run'])) {
  28115. foreach ($commands as $command) {
  28116. $fp = popen($command, "r");
  28117. while ($line = fgets($fp, 1024)) {
  28118. $this->output .= rtrim($line)."\n";
  28119. }
  28120. pclose($fp);
  28121. }
  28122. }
  28123. $command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n";
  28124. $this->output .= "+ $command\n";
  28125. if (empty($options['dry-run'])) {
  28126. $fp = popen($command, "r");
  28127. while ($line = fgets($fp, 1024)) {
  28128. $this->output .= rtrim($line)."\n";
  28129. }
  28130. pclose($fp);
  28131. }
  28132. $this->ui->outputData($this->output, $_cmd);
  28133. return true;
  28134. }
  28135. function _svnFindPath($file)
  28136. {
  28137. $xml = '';
  28138. $command = "svn info --xml $file";
  28139. $fp = popen($command, "r");
  28140. while ($line = fgets($fp, 1024)) {
  28141. $xml .= rtrim($line)."\n";
  28142. }
  28143. pclose($fp);
  28144. $url_tag = strpos($xml, '<url>');
  28145. $url = substr($xml, $url_tag + 5, strpos($xml, '</url>', $url_tag + 5) - ($url_tag + 5));
  28146. $path = array();
  28147. $path['from'] = substr($url, 0, strrpos($url, '/'));
  28148. $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1);
  28149. // Figure out the local paths - see http://pear.php.net/bugs/17463
  28150. $pos = strpos($file, DIRECTORY_SEPARATOR . 'trunk' . DIRECTORY_SEPARATOR);
  28151. if ($pos === false) {
  28152. $pos = strpos($file, DIRECTORY_SEPARATOR . 'branches' . DIRECTORY_SEPARATOR);
  28153. }
  28154. $path['local']['base'] = substr($file, 0, $pos + 1);
  28155. return $path;
  28156. }
  28157. function _svnRemoveTag($version, $package, $tag, $packageFile, $options)
  28158. {
  28159. $command = 'svn';
  28160. if (isset($options['quiet'])) {
  28161. $command .= ' -q';
  28162. }
  28163. $command .= ' remove';
  28164. $command .= ' -m "Removing tag for the ' . $version . ' release."';
  28165. $path = $this->_svnFindPath($packageFile);
  28166. $command .= ' ' . $path['base'] . 'tags/' . $tag;
  28167. if ($this->config->get('verbose') > 1) {
  28168. $this->output .= "+ $command\n";
  28169. }
  28170. $this->output .= "+ $command\n";
  28171. if (empty($options['dry-run'])) {
  28172. $fp = popen($command, "r");
  28173. while ($line = fgets($fp, 1024)) {
  28174. $this->output .= rtrim($line)."\n";
  28175. }
  28176. pclose($fp);
  28177. }
  28178. $this->ui->outputData($this->output, $command);
  28179. return true;
  28180. }
  28181. function doCvsTag($command, $options, $params)
  28182. {
  28183. $this->output = '';
  28184. $_cmd = $command;
  28185. if (count($params) < 1) {
  28186. $help = $this->getHelp($command);
  28187. return $this->raiseError("$command: missing parameter: $help[0]");
  28188. }
  28189. $packageFile = realpath($params[0]);
  28190. $obj = &$this->getPackageFile($this->config, $this->_debug);
  28191. $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
  28192. if (PEAR::isError($info)) {
  28193. return $this->raiseError($info);
  28194. }
  28195. $err = $warn = array();
  28196. if (!$info->validate()) {
  28197. foreach ($info->getValidationWarnings() as $error) {
  28198. if ($error['level'] == 'warning') {
  28199. $warn[] = $error['message'];
  28200. } else {
  28201. $err[] = $error['message'];
  28202. }
  28203. }
  28204. }
  28205. if (!$this->_displayValidationResults($err, $warn, true)) {
  28206. $this->ui->outputData($this->output, $command);
  28207. return $this->raiseError('CVS tag failed');
  28208. }
  28209. $version = $info->getVersion();
  28210. $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
  28211. $cvstag = "RELEASE_$cvsversion";
  28212. $files = array_keys($info->getFilelist());
  28213. $command = 'cvs';
  28214. if (isset($options['quiet'])) {
  28215. $command .= ' -q';
  28216. }
  28217. if (isset($options['reallyquiet'])) {
  28218. $command .= ' -Q';
  28219. }
  28220. $command .= ' tag';
  28221. if (isset($options['slide'])) {
  28222. $command .= ' -F';
  28223. }
  28224. if (isset($options['delete'])) {
  28225. $command .= ' -d';
  28226. }
  28227. $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
  28228. array_shift($params);
  28229. if (count($params)) {
  28230. // add in additional files to be tagged
  28231. $files = array_merge($files, $params);
  28232. }
  28233. $dir = dirname($packageFile);
  28234. $dir = substr($dir, strrpos($dir, '/') + 1);
  28235. foreach ($files as $file) {
  28236. if (!file_exists($file)) {
  28237. $file = $dir . DIRECTORY_SEPARATOR . $file;
  28238. }
  28239. $command .= ' ' . escapeshellarg($file);
  28240. }
  28241. if ($this->config->get('verbose') > 1) {
  28242. $this->output .= "+ $command\n";
  28243. }
  28244. $this->output .= "+ $command\n";
  28245. if (empty($options['dry-run'])) {
  28246. $fp = popen($command, "r");
  28247. while ($line = fgets($fp, 1024)) {
  28248. $this->output .= rtrim($line)."\n";
  28249. }
  28250. pclose($fp);
  28251. }
  28252. $this->ui->outputData($this->output, $_cmd);
  28253. return true;
  28254. }
  28255. function doCvsDiff($command, $options, $params)
  28256. {
  28257. $this->output = '';
  28258. if (sizeof($params) < 1) {
  28259. $help = $this->getHelp($command);
  28260. return $this->raiseError("$command: missing parameter: $help[0]");
  28261. }
  28262. $file = realpath($params[0]);
  28263. $obj = &$this->getPackageFile($this->config, $this->_debug);
  28264. $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL);
  28265. if (PEAR::isError($info)) {
  28266. return $this->raiseError($info);
  28267. }
  28268. $err = $warn = array();
  28269. if (!$info->validate()) {
  28270. foreach ($info->getValidationWarnings() as $error) {
  28271. if ($error['level'] == 'warning') {
  28272. $warn[] = $error['message'];
  28273. } else {
  28274. $err[] = $error['message'];
  28275. }
  28276. }
  28277. }
  28278. if (!$this->_displayValidationResults($err, $warn, true)) {
  28279. $this->ui->outputData($this->output, $command);
  28280. return $this->raiseError('CVS diff failed');
  28281. }
  28282. $info1 = $info->getFilelist();
  28283. $files = $info1;
  28284. $cmd = "cvs";
  28285. if (isset($options['quiet'])) {
  28286. $cmd .= ' -q';
  28287. unset($options['quiet']);
  28288. }
  28289. if (isset($options['reallyquiet'])) {
  28290. $cmd .= ' -Q';
  28291. unset($options['reallyquiet']);
  28292. }
  28293. if (isset($options['release'])) {
  28294. $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
  28295. $cvstag = "RELEASE_$cvsversion";
  28296. $options['revision'] = $cvstag;
  28297. unset($options['release']);
  28298. }
  28299. $execute = true;
  28300. if (isset($options['dry-run'])) {
  28301. $execute = false;
  28302. unset($options['dry-run']);
  28303. }
  28304. $cmd .= ' diff';
  28305. // the rest of the options are passed right on to "cvs diff"
  28306. foreach ($options as $option => $optarg) {
  28307. $arg = $short = false;
  28308. if (isset($this->commands[$command]['options'][$option])) {
  28309. $arg = $this->commands[$command]['options'][$option]['arg'];
  28310. $short = $this->commands[$command]['options'][$option]['shortopt'];
  28311. }
  28312. $cmd .= $short ? " -$short" : " --$option";
  28313. if ($arg && $optarg) {
  28314. $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
  28315. }
  28316. }
  28317. foreach ($files as $file) {
  28318. $cmd .= ' ' . escapeshellarg($file['name']);
  28319. }
  28320. if ($this->config->get('verbose') > 1) {
  28321. $this->output .= "+ $cmd\n";
  28322. }
  28323. if ($execute) {
  28324. $fp = popen($cmd, "r");
  28325. while ($line = fgets($fp, 1024)) {
  28326. $this->output .= rtrim($line)."\n";
  28327. }
  28328. pclose($fp);
  28329. }
  28330. $this->ui->outputData($this->output, $command);
  28331. return true;
  28332. }
  28333. function doPackageDependencies($command, $options, $params)
  28334. {
  28335. // $params[0] -> the PEAR package to list its information
  28336. if (count($params) !== 1) {
  28337. return $this->raiseError("bad parameter(s), try \"help $command\"");
  28338. }
  28339. $obj = &$this->getPackageFile($this->config, $this->_debug);
  28340. if (is_file($params[0]) || strpos($params[0], '.xml') > 0) {
  28341. $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  28342. } else {
  28343. $reg = $this->config->getRegistry();
  28344. $info = $obj->fromArray($reg->packageInfo($params[0]));
  28345. }
  28346. if (PEAR::isError($info)) {
  28347. return $this->raiseError($info);
  28348. }
  28349. $deps = $info->getDeps();
  28350. if (is_array($deps)) {
  28351. if ($info->getPackagexmlVersion() == '1.0') {
  28352. $data = array(
  28353. 'caption' => 'Dependencies for pear/' . $info->getPackage(),
  28354. 'border' => true,
  28355. 'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
  28356. );
  28357. foreach ($deps as $d) {
  28358. if (isset($d['optional'])) {
  28359. if ($d['optional'] == 'yes') {
  28360. $req = 'No';
  28361. } else {
  28362. $req = 'Yes';
  28363. }
  28364. } else {
  28365. $req = 'Yes';
  28366. }
  28367. if (isset($this->_deps_rel_trans[$d['rel']])) {
  28368. $rel = $this->_deps_rel_trans[$d['rel']];
  28369. } else {
  28370. $rel = $d['rel'];
  28371. }
  28372. if (isset($this->_deps_type_trans[$d['type']])) {
  28373. $type = ucfirst($this->_deps_type_trans[$d['type']]);
  28374. } else {
  28375. $type = $d['type'];
  28376. }
  28377. if (isset($d['name'])) {
  28378. $name = $d['name'];
  28379. } else {
  28380. $name = '';
  28381. }
  28382. if (isset($d['version'])) {
  28383. $version = $d['version'];
  28384. } else {
  28385. $version = '';
  28386. }
  28387. $data['data'][] = array($req, $type, $name, $rel, $version);
  28388. }
  28389. } else { // package.xml 2.0 dependencies display
  28390. require_once 'PEAR/Dependency2.php';
  28391. $deps = $info->getDependencies();
  28392. $reg = &$this->config->getRegistry();
  28393. if (is_array($deps)) {
  28394. $data = array(
  28395. 'caption' => 'Dependencies for ' . $info->getPackage(),
  28396. 'border' => true,
  28397. 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
  28398. );
  28399. foreach ($deps as $type => $subd) {
  28400. $req = ($type == 'required') ? 'Yes' : 'No';
  28401. if ($type == 'group' && isset($subd['attribs']['name'])) {
  28402. $group = $subd['attribs']['name'];
  28403. } else {
  28404. $group = '';
  28405. }
  28406. if (!isset($subd[0])) {
  28407. $subd = array($subd);
  28408. }
  28409. foreach ($subd as $groupa) {
  28410. foreach ($groupa as $deptype => $depinfo) {
  28411. if ($deptype == 'attribs') {
  28412. continue;
  28413. }
  28414. if ($deptype == 'pearinstaller') {
  28415. $deptype = 'pear Installer';
  28416. }
  28417. if (!isset($depinfo[0])) {
  28418. $depinfo = array($depinfo);
  28419. }
  28420. foreach ($depinfo as $inf) {
  28421. $name = '';
  28422. if (isset($inf['channel'])) {
  28423. $alias = $reg->channelAlias($inf['channel']);
  28424. if (!$alias) {
  28425. $alias = '(channel?) ' .$inf['channel'];
  28426. }
  28427. $name = $alias . '/';
  28428. }
  28429. if (isset($inf['name'])) {
  28430. $name .= $inf['name'];
  28431. } elseif (isset($inf['pattern'])) {
  28432. $name .= $inf['pattern'];
  28433. } else {
  28434. $name .= '';
  28435. }
  28436. if (isset($inf['uri'])) {
  28437. $name .= ' [' . $inf['uri'] . ']';
  28438. }
  28439. if (isset($inf['conflicts'])) {
  28440. $ver = 'conflicts';
  28441. } else {
  28442. $ver = PEAR_Dependency2::_getExtraString($inf);
  28443. }
  28444. $data['data'][] = array($req, ucfirst($deptype), $name,
  28445. $ver, $group);
  28446. }
  28447. }
  28448. }
  28449. }
  28450. }
  28451. }
  28452. $this->ui->outputData($data, $command);
  28453. return true;
  28454. }
  28455. // Fallback
  28456. $this->ui->outputData("This package does not have any dependencies.", $command);
  28457. }
  28458. function doSign($command, $options, $params)
  28459. {
  28460. // should move most of this code into PEAR_Packager
  28461. // so it'll be easy to implement "pear package --sign"
  28462. if (count($params) !== 1) {
  28463. return $this->raiseError("bad parameter(s), try \"help $command\"");
  28464. }
  28465. require_once 'System.php';
  28466. require_once 'Archive/Tar.php';
  28467. if (!file_exists($params[0])) {
  28468. return $this->raiseError("file does not exist: $params[0]");
  28469. }
  28470. $obj = $this->getPackageFile($this->config, $this->_debug);
  28471. $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
  28472. if (PEAR::isError($info)) {
  28473. return $this->raiseError($info);
  28474. }
  28475. $tar = new Archive_Tar($params[0]);
  28476. $tmpdir = $this->config->get('temp_dir');
  28477. $tmpdir = System::mktemp(' -t "' . $tmpdir . '" -d pearsign');
  28478. if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
  28479. return $this->raiseError("failed to extract tar file");
  28480. }
  28481. if (file_exists("$tmpdir/package.sig")) {
  28482. return $this->raiseError("package already signed");
  28483. }
  28484. $packagexml = 'package.xml';
  28485. if (file_exists("$tmpdir/package2.xml")) {
  28486. $packagexml = 'package2.xml';
  28487. }
  28488. if (file_exists("$tmpdir/package.sig")) {
  28489. unlink("$tmpdir/package.sig");
  28490. }
  28491. if (!file_exists("$tmpdir/$packagexml")) {
  28492. return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
  28493. }
  28494. $input = $this->ui->userDialog($command,
  28495. array('GnuPG Passphrase'),
  28496. array('password'));
  28497. if (!isset($input[0])) {
  28498. //use empty passphrase
  28499. $input[0] = '';
  28500. }
  28501. $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
  28502. $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
  28503. if (!$gpg) {
  28504. return $this->raiseError("gpg command failed");
  28505. }
  28506. fwrite($gpg, "$input[0]\n");
  28507. if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
  28508. return $this->raiseError("gpg sign failed");
  28509. }
  28510. if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
  28511. return $this->raiseError('failed adding signature to file');
  28512. }
  28513. $this->ui->outputData("Package signed.", $command);
  28514. return true;
  28515. }
  28516. /**
  28517. * For unit testing purposes
  28518. */
  28519. function &getInstaller(&$ui)
  28520. {
  28521. if (!class_exists('PEAR_Installer')) {
  28522. require_once 'PEAR/Installer.php';
  28523. }
  28524. $a = new PEAR_Installer($ui);
  28525. return $a;
  28526. }
  28527. /**
  28528. * For unit testing purposes
  28529. */
  28530. function &getCommandPackaging(&$ui, &$config)
  28531. {
  28532. if (!class_exists('PEAR_Command_Packaging')) {
  28533. if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
  28534. fclose($fp);
  28535. include_once 'PEAR/Command/Packaging.php';
  28536. }
  28537. }
  28538. if (class_exists('PEAR_Command_Packaging')) {
  28539. $a = new PEAR_Command_Packaging($ui, $config);
  28540. } else {
  28541. $a = null;
  28542. }
  28543. return $a;
  28544. }
  28545. function doMakeRPM($command, $options, $params)
  28546. {
  28547. // Check to see if PEAR_Command_Packaging is installed, and
  28548. // transparently switch to use the "make-rpm-spec" command from it
  28549. // instead, if it does. Otherwise, continue to use the old version
  28550. // of "makerpm" supplied with this package (PEAR).
  28551. $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
  28552. if ($packaging_cmd !== null) {
  28553. $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
  28554. 'newer "make-rpm-spec" command instead');
  28555. return $packaging_cmd->run('make-rpm-spec', $options, $params);
  28556. }
  28557. $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
  28558. 'improved version is available via "pear make-rpm-spec", which '.
  28559. 'is available by installing PEAR_Command_Packaging');
  28560. return true;
  28561. }
  28562. function doConvert($command, $options, $params)
  28563. {
  28564. $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
  28565. $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
  28566. DIRECTORY_SEPARATOR . 'package2.xml';
  28567. $pkg = &$this->getPackageFile($this->config, $this->_debug);
  28568. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  28569. $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
  28570. PEAR::staticPopErrorHandling();
  28571. if (PEAR::isError($pf)) {
  28572. if (is_array($pf->getUserInfo())) {
  28573. foreach ($pf->getUserInfo() as $warning) {
  28574. $this->ui->outputData($warning['message']);
  28575. }
  28576. }
  28577. return $this->raiseError($pf);
  28578. }
  28579. if (is_a($pf, 'PEAR_PackageFile_v2')) {
  28580. $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
  28581. return true;
  28582. }
  28583. $gen = &$pf->getDefaultGenerator();
  28584. $newpf = &$gen->toV2();
  28585. $newpf->setPackagefile($newpackagexml);
  28586. $gen = &$newpf->getDefaultGenerator();
  28587. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  28588. $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
  28589. $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml));
  28590. PEAR::staticPopErrorHandling();
  28591. if (PEAR::isError($saved)) {
  28592. if (is_array($saved->getUserInfo())) {
  28593. foreach ($saved->getUserInfo() as $warning) {
  28594. $this->ui->outputData($warning['message']);
  28595. }
  28596. }
  28597. $this->ui->outputData($saved->getMessage());
  28598. return true;
  28599. }
  28600. $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
  28601. return true;
  28602. }
  28603. }
  28604. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Pickle.xml����������������������������������������������������������������0000644�0001750�0001750�00000002233�13565304531�016314� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  28605. <pickle>
  28606. <summary>Build PECL Package</summary>
  28607. <function>doPackage</function>
  28608. <shortcut>pi</shortcut>
  28609. <options>
  28610. <nocompress>
  28611. <shortopt>Z</shortopt>
  28612. <doc>Do not gzip the package file</doc>
  28613. </nocompress>
  28614. <showname>
  28615. <shortopt>n</shortopt>
  28616. <doc>Print the name of the packaged file.</doc>
  28617. </showname>
  28618. </options>
  28619. <doc>[descfile]
  28620. Creates a PECL package from its package2.xml file.
  28621. An automatic conversion will be made to a package.xml 1.0 and written out to
  28622. disk in the current directory as &quot;package.xml&quot;. Note that
  28623. only simple package.xml 2.0 will be converted. package.xml 2.0 with:
  28624. - dependency types other than required/optional PECL package/ext/php/pearinstaller
  28625. - more than one extsrcrelease or zendextsrcrelease
  28626. - zendextbinrelease, extbinrelease, phprelease, or bundle release type
  28627. - dependency groups
  28628. - ignore tags in release filelist
  28629. - tasks other than replace
  28630. - custom roles
  28631. will cause pickle to fail, and output an error message. If your package2.xml
  28632. uses any of these features, you are best off using PEAR_PackageFileManager to
  28633. generate both package.xml.
  28634. </doc>
  28635. </pickle>
  28636. </commands>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Pickle.php����������������������������������������������������������������0000644�0001750�0001750�00000037027�13565304531�016314� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  28637. /**
  28638. * PEAR_Command_Pickle (pickle command)
  28639. *
  28640. * PHP versions 4 and 5
  28641. *
  28642. * @category pear
  28643. * @package PEAR
  28644. * @author Greg Beaver <cellog@php.net>
  28645. * @copyright 2005-2009 The Authors
  28646. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  28647. * @link http://pear.php.net/package/PEAR
  28648. * @since File available since Release 1.4.1
  28649. */
  28650. /**
  28651. * base class
  28652. */
  28653. require_once 'PEAR/Command/Common.php';
  28654. /**
  28655. * PEAR commands for login/logout
  28656. *
  28657. * @category pear
  28658. * @package PEAR
  28659. * @author Greg Beaver <cellog@php.net>
  28660. * @copyright 2005-2009 The Authors
  28661. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  28662. * @version Release: 1.10.10
  28663. * @link http://pear.php.net/package/PEAR
  28664. * @since Class available since Release 1.4.1
  28665. */
  28666. class PEAR_Command_Pickle extends PEAR_Command_Common
  28667. {
  28668. var $commands = array(
  28669. 'pickle' => array(
  28670. 'summary' => 'Build PECL Package',
  28671. 'function' => 'doPackage',
  28672. 'shortcut' => 'pi',
  28673. 'options' => array(
  28674. 'nocompress' => array(
  28675. 'shortopt' => 'Z',
  28676. 'doc' => 'Do not gzip the package file'
  28677. ),
  28678. 'showname' => array(
  28679. 'shortopt' => 'n',
  28680. 'doc' => 'Print the name of the packaged file.',
  28681. ),
  28682. ),
  28683. 'doc' => '[descfile]
  28684. Creates a PECL package from its package2.xml file.
  28685. An automatic conversion will be made to a package.xml 1.0 and written out to
  28686. disk in the current directory as "package.xml". Note that
  28687. only simple package.xml 2.0 will be converted. package.xml 2.0 with:
  28688. - dependency types other than required/optional PECL package/ext/php/pearinstaller
  28689. - more than one extsrcrelease or zendextsrcrelease
  28690. - zendextbinrelease, extbinrelease, phprelease, or bundle release type
  28691. - dependency groups
  28692. - ignore tags in release filelist
  28693. - tasks other than replace
  28694. - custom roles
  28695. will cause pickle to fail, and output an error message. If your package2.xml
  28696. uses any of these features, you are best off using PEAR_PackageFileManager to
  28697. generate both package.xml.
  28698. '
  28699. ),
  28700. );
  28701. /**
  28702. * PEAR_Command_Package constructor.
  28703. *
  28704. * @access public
  28705. */
  28706. function __construct(&$ui, &$config)
  28707. {
  28708. parent::__construct($ui, $config);
  28709. }
  28710. /**
  28711. * For unit-testing ease
  28712. *
  28713. * @return PEAR_Packager
  28714. */
  28715. function &getPackager()
  28716. {
  28717. if (!class_exists('PEAR_Packager')) {
  28718. require_once 'PEAR/Packager.php';
  28719. }
  28720. $a = new PEAR_Packager;
  28721. return $a;
  28722. }
  28723. /**
  28724. * For unit-testing ease
  28725. *
  28726. * @param PEAR_Config $config
  28727. * @param bool $debug
  28728. * @param string|null $tmpdir
  28729. * @return PEAR_PackageFile
  28730. */
  28731. function &getPackageFile($config, $debug = false)
  28732. {
  28733. if (!class_exists('PEAR_Common')) {
  28734. require_once 'PEAR/Common.php';
  28735. }
  28736. if (!class_exists('PEAR_PackageFile')) {
  28737. require_once 'PEAR/PackageFile.php';
  28738. }
  28739. $a = new PEAR_PackageFile($config, $debug);
  28740. $common = new PEAR_Common;
  28741. $common->ui = $this->ui;
  28742. $a->setLogger($common);
  28743. return $a;
  28744. }
  28745. function doPackage($command, $options, $params)
  28746. {
  28747. $this->output = '';
  28748. $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml';
  28749. $packager = &$this->getPackager();
  28750. if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) {
  28751. return $err;
  28752. }
  28753. $compress = empty($options['nocompress']) ? true : false;
  28754. $result = $packager->package($pkginfofile, $compress, 'package.xml');
  28755. if (PEAR::isError($result)) {
  28756. return $this->raiseError($result);
  28757. }
  28758. // Don't want output, only the package file name just created
  28759. if (isset($options['showname'])) {
  28760. $this->ui->outputData($result, $command);
  28761. }
  28762. return true;
  28763. }
  28764. function _convertPackage($packagexml)
  28765. {
  28766. $pkg = &$this->getPackageFile($this->config);
  28767. $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
  28768. if (!is_a($pf2, 'PEAR_PackageFile_v2')) {
  28769. return $this->raiseError('Cannot process "' .
  28770. $packagexml . '", is not a package.xml 2.0');
  28771. }
  28772. require_once 'PEAR/PackageFile/v1.php';
  28773. $pf = new PEAR_PackageFile_v1;
  28774. $pf->setConfig($this->config);
  28775. if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') {
  28776. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28777. '", is not an extension source package. Using a PEAR_PackageFileManager-based ' .
  28778. 'script is an option');
  28779. }
  28780. if (is_array($pf2->getUsesRole())) {
  28781. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28782. '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' .
  28783. 'the convert command is an option');
  28784. }
  28785. if (is_array($pf2->getUsesTask())) {
  28786. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28787. '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' .
  28788. 'the convert command is an option');
  28789. }
  28790. $deps = $pf2->getDependencies();
  28791. if (isset($deps['group'])) {
  28792. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28793. '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' .
  28794. 'or the convert command is an option');
  28795. }
  28796. if (isset($deps['required']['subpackage']) ||
  28797. isset($deps['optional']['subpackage'])) {
  28798. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28799. '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '.
  28800. 'script is an option');
  28801. }
  28802. if (isset($deps['required']['os'])) {
  28803. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28804. '", contains os dependencies. Using a PEAR_PackageFileManager-based '.
  28805. 'script is an option');
  28806. }
  28807. if (isset($deps['required']['arch'])) {
  28808. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28809. '", contains arch dependencies. Using a PEAR_PackageFileManager-based '.
  28810. 'script is an option');
  28811. }
  28812. $pf->setPackage($pf2->getPackage());
  28813. $pf->setSummary($pf2->getSummary());
  28814. $pf->setDescription($pf2->getDescription());
  28815. foreach ($pf2->getMaintainers() as $maintainer) {
  28816. $pf->addMaintainer($maintainer['role'], $maintainer['handle'],
  28817. $maintainer['name'], $maintainer['email']);
  28818. }
  28819. $pf->setVersion($pf2->getVersion());
  28820. $pf->setDate($pf2->getDate());
  28821. $pf->setLicense($pf2->getLicense());
  28822. $pf->setState($pf2->getState());
  28823. $pf->setNotes($pf2->getNotes());
  28824. $pf->addPhpDep($deps['required']['php']['min'], 'ge');
  28825. if (isset($deps['required']['php']['max'])) {
  28826. $pf->addPhpDep($deps['required']['php']['max'], 'le');
  28827. }
  28828. if (isset($deps['required']['package'])) {
  28829. if (!isset($deps['required']['package'][0])) {
  28830. $deps['required']['package'] = array($deps['required']['package']);
  28831. }
  28832. foreach ($deps['required']['package'] as $dep) {
  28833. if (!isset($dep['channel'])) {
  28834. return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  28835. ' contains uri-based dependency on a package. Using a ' .
  28836. 'PEAR_PackageFileManager-based script is an option');
  28837. }
  28838. if ($dep['channel'] != 'pear.php.net'
  28839. && $dep['channel'] != 'pecl.php.net'
  28840. && $dep['channel'] != 'doc.php.net') {
  28841. return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  28842. ' contains dependency on a non-standard channel package. Using a ' .
  28843. 'PEAR_PackageFileManager-based script is an option');
  28844. }
  28845. if (isset($dep['conflicts'])) {
  28846. return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  28847. ' contains conflicts dependency. Using a ' .
  28848. 'PEAR_PackageFileManager-based script is an option');
  28849. }
  28850. if (isset($dep['exclude'])) {
  28851. $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  28852. }
  28853. if (isset($dep['min'])) {
  28854. $pf->addPackageDep($dep['name'], $dep['min'], 'ge');
  28855. }
  28856. if (isset($dep['max'])) {
  28857. $pf->addPackageDep($dep['name'], $dep['max'], 'le');
  28858. }
  28859. }
  28860. }
  28861. if (isset($deps['required']['extension'])) {
  28862. if (!isset($deps['required']['extension'][0])) {
  28863. $deps['required']['extension'] = array($deps['required']['extension']);
  28864. }
  28865. foreach ($deps['required']['extension'] as $dep) {
  28866. if (isset($dep['conflicts'])) {
  28867. return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  28868. ' contains conflicts dependency. Using a ' .
  28869. 'PEAR_PackageFileManager-based script is an option');
  28870. }
  28871. if (isset($dep['exclude'])) {
  28872. $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  28873. }
  28874. if (isset($dep['min'])) {
  28875. $pf->addExtensionDep($dep['name'], $dep['min'], 'ge');
  28876. }
  28877. if (isset($dep['max'])) {
  28878. $pf->addExtensionDep($dep['name'], $dep['max'], 'le');
  28879. }
  28880. }
  28881. }
  28882. if (isset($deps['optional']['package'])) {
  28883. if (!isset($deps['optional']['package'][0])) {
  28884. $deps['optional']['package'] = array($deps['optional']['package']);
  28885. }
  28886. foreach ($deps['optional']['package'] as $dep) {
  28887. if (!isset($dep['channel'])) {
  28888. return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  28889. ' contains uri-based dependency on a package. Using a ' .
  28890. 'PEAR_PackageFileManager-based script is an option');
  28891. }
  28892. if ($dep['channel'] != 'pear.php.net'
  28893. && $dep['channel'] != 'pecl.php.net'
  28894. && $dep['channel'] != 'doc.php.net') {
  28895. return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  28896. ' contains dependency on a non-standard channel package. Using a ' .
  28897. 'PEAR_PackageFileManager-based script is an option');
  28898. }
  28899. if (isset($dep['exclude'])) {
  28900. $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  28901. }
  28902. if (isset($dep['min'])) {
  28903. $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes');
  28904. }
  28905. if (isset($dep['max'])) {
  28906. $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes');
  28907. }
  28908. }
  28909. }
  28910. if (isset($deps['optional']['extension'])) {
  28911. if (!isset($deps['optional']['extension'][0])) {
  28912. $deps['optional']['extension'] = array($deps['optional']['extension']);
  28913. }
  28914. foreach ($deps['optional']['extension'] as $dep) {
  28915. if (isset($dep['exclude'])) {
  28916. $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  28917. }
  28918. if (isset($dep['min'])) {
  28919. $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes');
  28920. }
  28921. if (isset($dep['max'])) {
  28922. $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes');
  28923. }
  28924. }
  28925. }
  28926. $contents = $pf2->getContents();
  28927. $release = $pf2->getReleases();
  28928. if (isset($releases[0])) {
  28929. return $this->raiseError('Cannot safely process "' . $packagexml . '" contains '
  28930. . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' .
  28931. 'or the convert command is an option');
  28932. }
  28933. if ($configoptions = $pf2->getConfigureOptions()) {
  28934. foreach ($configoptions as $option) {
  28935. $default = isset($option['default']) ? $option['default'] : false;
  28936. $pf->addConfigureOption($option['name'], $option['prompt'], $default);
  28937. }
  28938. }
  28939. if (isset($release['filelist']['ignore'])) {
  28940. return $this->raiseError('Cannot safely process "' . $packagexml . '" contains '
  28941. . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' .
  28942. ' command is an option');
  28943. }
  28944. if (isset($release['filelist']['install']) &&
  28945. !isset($release['filelist']['install'][0])) {
  28946. $release['filelist']['install'] = array($release['filelist']['install']);
  28947. }
  28948. if (isset($contents['dir']['attribs']['baseinstalldir'])) {
  28949. $baseinstalldir = $contents['dir']['attribs']['baseinstalldir'];
  28950. } else {
  28951. $baseinstalldir = false;
  28952. }
  28953. if (!isset($contents['dir']['file'][0])) {
  28954. $contents['dir']['file'] = array($contents['dir']['file']);
  28955. }
  28956. foreach ($contents['dir']['file'] as $file) {
  28957. if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) {
  28958. $file['attribs']['baseinstalldir'] = $baseinstalldir;
  28959. }
  28960. $processFile = $file;
  28961. unset($processFile['attribs']);
  28962. if (count($processFile)) {
  28963. foreach ($processFile as $name => $task) {
  28964. if ($name != $pf2->getTasksNs() . ':replace') {
  28965. return $this->raiseError('Cannot safely process "' . $packagexml .
  28966. '" contains tasks other than replace. Using a ' .
  28967. 'PEAR_PackageFileManager-based script is an option.');
  28968. }
  28969. $file['attribs']['replace'][] = $task;
  28970. }
  28971. }
  28972. if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) {
  28973. return $this->raiseError('Cannot safely convert "' . $packagexml .
  28974. '", contains custom roles. Using a PEAR_PackageFileManager-based script ' .
  28975. 'or the convert command is an option');
  28976. }
  28977. if (isset($release['filelist']['install'])) {
  28978. foreach ($release['filelist']['install'] as $installas) {
  28979. if ($installas['attribs']['name'] == $file['attribs']['name']) {
  28980. $file['attribs']['install-as'] = $installas['attribs']['as'];
  28981. }
  28982. }
  28983. }
  28984. $pf->addFile('/', $file['attribs']['name'], $file['attribs']);
  28985. }
  28986. if ($pf2->getChangeLog()) {
  28987. $this->ui->outputData('WARNING: changelog is not translated to package.xml ' .
  28988. '1.0, use PEAR_PackageFileManager-based script if you need changelog-' .
  28989. 'translation for package.xml 1.0');
  28990. }
  28991. $gen = &$pf->getDefaultGenerator();
  28992. $gen->toPackageFile('.');
  28993. }
  28994. }
  28995. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Registry.xml��������������������������������������������������������������0000644�0001750�0001750�00000003376�13565304531�016726� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  28996. <list>
  28997. <summary>List Installed Packages In The Default Channel</summary>
  28998. <function>doList</function>
  28999. <shortcut>l</shortcut>
  29000. <options>
  29001. <channel>
  29002. <shortopt>c</shortopt>
  29003. <doc>list installed packages from this channel</doc>
  29004. <arg>CHAN</arg>
  29005. </channel>
  29006. <allchannels>
  29007. <shortopt>a</shortopt>
  29008. <doc>list installed packages from all channels</doc>
  29009. </allchannels>
  29010. <channelinfo>
  29011. <shortopt>i</shortopt>
  29012. <doc>output fully channel-aware data, even on failure</doc>
  29013. </channelinfo>
  29014. </options>
  29015. <doc>&lt;package&gt;
  29016. If invoked without parameters, this command lists the PEAR packages
  29017. installed in your php_dir ({config php_dir}). With a parameter, it
  29018. lists the files in a package.
  29019. </doc>
  29020. </list>
  29021. <list-files>
  29022. <summary>List Files In Installed Package</summary>
  29023. <function>doFileList</function>
  29024. <shortcut>fl</shortcut>
  29025. <options />
  29026. <doc>&lt;package&gt;
  29027. List the files in an installed package.
  29028. </doc>
  29029. </list-files>
  29030. <shell-test>
  29031. <summary>Shell Script Test</summary>
  29032. <function>doShellTest</function>
  29033. <shortcut>st</shortcut>
  29034. <options />
  29035. <doc>&lt;package&gt; [[relation] version]
  29036. Tests if a package is installed in the system. Will exit(1) if it is not.
  29037. &lt;relation&gt; The version comparison operator. One of:
  29038. &lt;, lt, &lt;=, le, &gt;, gt, &gt;=, ge, ==, =, eq, !=, &lt;&gt;, ne
  29039. &lt;version&gt; The version to compare with
  29040. </doc>
  29041. </shell-test>
  29042. <info>
  29043. <summary>Display information about a package</summary>
  29044. <function>doInfo</function>
  29045. <shortcut>in</shortcut>
  29046. <options />
  29047. <doc>&lt;package&gt;
  29048. Displays information about a package. The package argument may be a
  29049. local package file, an URL to a package file, or the name of an
  29050. installed package.</doc>
  29051. </info>
  29052. </commands>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Registry.php��������������������������������������������������������������0000644�0001750�0001750�00000132315�13565304531�016711� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  29053. /**
  29054. * PEAR_Command_Registry (list, list-files, shell-test, info commands)
  29055. *
  29056. * PHP versions 4 and 5
  29057. *
  29058. * @category pear
  29059. * @package PEAR
  29060. * @author Stig Bakken <ssb@php.net>
  29061. * @author Greg Beaver <cellog@php.net>
  29062. * @copyright 1997-2009 The Authors
  29063. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  29064. * @link http://pear.php.net/package/PEAR
  29065. * @since File available since Release 0.1
  29066. */
  29067. /**
  29068. * base class
  29069. */
  29070. require_once 'PEAR/Command/Common.php';
  29071. /**
  29072. * PEAR commands for registry manipulation
  29073. *
  29074. * @category pear
  29075. * @package PEAR
  29076. * @author Stig Bakken <ssb@php.net>
  29077. * @author Greg Beaver <cellog@php.net>
  29078. * @copyright 1997-2009 The Authors
  29079. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  29080. * @version Release: 1.10.10
  29081. * @link http://pear.php.net/package/PEAR
  29082. * @since Class available since Release 0.1
  29083. */
  29084. class PEAR_Command_Registry extends PEAR_Command_Common
  29085. {
  29086. var $commands = array(
  29087. 'list' => array(
  29088. 'summary' => 'List Installed Packages In The Default Channel',
  29089. 'function' => 'doList',
  29090. 'shortcut' => 'l',
  29091. 'options' => array(
  29092. 'channel' => array(
  29093. 'shortopt' => 'c',
  29094. 'doc' => 'list installed packages from this channel',
  29095. 'arg' => 'CHAN',
  29096. ),
  29097. 'allchannels' => array(
  29098. 'shortopt' => 'a',
  29099. 'doc' => 'list installed packages from all channels',
  29100. ),
  29101. 'channelinfo' => array(
  29102. 'shortopt' => 'i',
  29103. 'doc' => 'output fully channel-aware data, even on failure',
  29104. ),
  29105. ),
  29106. 'doc' => '<package>
  29107. If invoked without parameters, this command lists the PEAR packages
  29108. installed in your php_dir ({config php_dir}). With a parameter, it
  29109. lists the files in a package.
  29110. ',
  29111. ),
  29112. 'list-files' => array(
  29113. 'summary' => 'List Files In Installed Package',
  29114. 'function' => 'doFileList',
  29115. 'shortcut' => 'fl',
  29116. 'options' => array(),
  29117. 'doc' => '<package>
  29118. List the files in an installed package.
  29119. '
  29120. ),
  29121. 'shell-test' => array(
  29122. 'summary' => 'Shell Script Test',
  29123. 'function' => 'doShellTest',
  29124. 'shortcut' => 'st',
  29125. 'options' => array(),
  29126. 'doc' => '<package> [[relation] version]
  29127. Tests if a package is installed in the system. Will exit(1) if it is not.
  29128. <relation> The version comparison operator. One of:
  29129. <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
  29130. <version> The version to compare with
  29131. '),
  29132. 'info' => array(
  29133. 'summary' => 'Display information about a package',
  29134. 'function' => 'doInfo',
  29135. 'shortcut' => 'in',
  29136. 'options' => array(),
  29137. 'doc' => '<package>
  29138. Displays information about a package. The package argument may be a
  29139. local package file, an URL to a package file, or the name of an
  29140. installed package.'
  29141. )
  29142. );
  29143. /**
  29144. * PEAR_Command_Registry constructor.
  29145. *
  29146. * @access public
  29147. */
  29148. function __construct(&$ui, &$config)
  29149. {
  29150. parent::__construct($ui, $config);
  29151. }
  29152. function _sortinfo($a, $b)
  29153. {
  29154. $apackage = isset($a['package']) ? $a['package'] : $a['name'];
  29155. $bpackage = isset($b['package']) ? $b['package'] : $b['name'];
  29156. return strcmp($apackage, $bpackage);
  29157. }
  29158. function doList($command, $options, $params)
  29159. {
  29160. $reg = &$this->config->getRegistry();
  29161. $channelinfo = isset($options['channelinfo']);
  29162. if (isset($options['allchannels']) && !$channelinfo) {
  29163. return $this->doListAll($command, array(), $params);
  29164. }
  29165. if (isset($options['allchannels']) && $channelinfo) {
  29166. // allchannels with $channelinfo
  29167. unset($options['allchannels']);
  29168. $channels = $reg->getChannels();
  29169. $errors = array();
  29170. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  29171. foreach ($channels as $channel) {
  29172. $options['channel'] = $channel->getName();
  29173. $ret = $this->doList($command, $options, $params);
  29174. if (PEAR::isError($ret)) {
  29175. $errors[] = $ret;
  29176. }
  29177. }
  29178. PEAR::staticPopErrorHandling();
  29179. if (count($errors)) {
  29180. // for now, only give first error
  29181. return PEAR::raiseError($errors[0]);
  29182. }
  29183. return true;
  29184. }
  29185. if (count($params) === 1) {
  29186. return $this->doFileList($command, $options, $params);
  29187. }
  29188. if (isset($options['channel'])) {
  29189. if (!$reg->channelExists($options['channel'])) {
  29190. return $this->raiseError('Channel "' . $options['channel'] .'" does not exist');
  29191. }
  29192. $channel = $reg->channelName($options['channel']);
  29193. } else {
  29194. $channel = $this->config->get('default_channel');
  29195. }
  29196. $installed = $reg->packageInfo(null, null, $channel);
  29197. usort($installed, array(&$this, '_sortinfo'));
  29198. $data = array(
  29199. 'caption' => 'Installed packages, channel ' .
  29200. $channel . ':',
  29201. 'border' => true,
  29202. 'headline' => array('Package', 'Version', 'State'),
  29203. 'channel' => $channel,
  29204. );
  29205. if ($channelinfo) {
  29206. $data['headline'] = array('Channel', 'Package', 'Version', 'State');
  29207. }
  29208. if (count($installed) && !isset($data['data'])) {
  29209. $data['data'] = array();
  29210. }
  29211. foreach ($installed as $package) {
  29212. $pobj = $reg->getPackage(isset($package['package']) ?
  29213. $package['package'] : $package['name'], $channel);
  29214. if ($channelinfo) {
  29215. $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(),
  29216. $pobj->getState() ? $pobj->getState() : null);
  29217. } else {
  29218. $packageinfo = array($pobj->getPackage(), $pobj->getVersion(),
  29219. $pobj->getState() ? $pobj->getState() : null);
  29220. }
  29221. $data['data'][] = $packageinfo;
  29222. }
  29223. if (count($installed) === 0) {
  29224. if (!$channelinfo) {
  29225. $data = '(no packages installed from channel ' . $channel . ')';
  29226. } else {
  29227. $data = array(
  29228. 'caption' => 'Installed packages, channel ' .
  29229. $channel . ':',
  29230. 'border' => true,
  29231. 'channel' => $channel,
  29232. 'data' => array(array('(no packages installed)')),
  29233. );
  29234. }
  29235. }
  29236. $this->ui->outputData($data, $command);
  29237. return true;
  29238. }
  29239. function doListAll($command, $options, $params)
  29240. {
  29241. // This duplicate code is deprecated over
  29242. // list --channelinfo, which gives identical
  29243. // output for list and list --allchannels.
  29244. $reg = &$this->config->getRegistry();
  29245. $installed = $reg->packageInfo(null, null, null);
  29246. foreach ($installed as $channel => $packages) {
  29247. usort($packages, array($this, '_sortinfo'));
  29248. $data = array(
  29249. 'caption' => 'Installed packages, channel ' . $channel . ':',
  29250. 'border' => true,
  29251. 'headline' => array('Package', 'Version', 'State'),
  29252. 'channel' => $channel
  29253. );
  29254. foreach ($packages as $package) {
  29255. $p = isset($package['package']) ? $package['package'] : $package['name'];
  29256. $pobj = $reg->getPackage($p, $channel);
  29257. $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
  29258. $pobj->getState() ? $pobj->getState() : null);
  29259. }
  29260. // Adds a blank line after each section
  29261. $data['data'][] = array();
  29262. if (count($packages) === 0) {
  29263. $data = array(
  29264. 'caption' => 'Installed packages, channel ' . $channel . ':',
  29265. 'border' => true,
  29266. 'data' => array(array('(no packages installed)'), array()),
  29267. 'channel' => $channel
  29268. );
  29269. }
  29270. $this->ui->outputData($data, $command);
  29271. }
  29272. return true;
  29273. }
  29274. function doFileList($command, $options, $params)
  29275. {
  29276. if (count($params) !== 1) {
  29277. return $this->raiseError('list-files expects 1 parameter');
  29278. }
  29279. $reg = &$this->config->getRegistry();
  29280. $fp = false;
  29281. if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))) {
  29282. if ($fp) {
  29283. fclose($fp);
  29284. }
  29285. if (!class_exists('PEAR_PackageFile')) {
  29286. require_once 'PEAR/PackageFile.php';
  29287. }
  29288. $pkg = new PEAR_PackageFile($this->config, $this->_debug);
  29289. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  29290. $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  29291. PEAR::staticPopErrorHandling();
  29292. $headings = array('Package File', 'Install Path');
  29293. $installed = false;
  29294. } else {
  29295. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  29296. $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  29297. PEAR::staticPopErrorHandling();
  29298. if (PEAR::isError($parsed)) {
  29299. return $this->raiseError($parsed);
  29300. }
  29301. $info = &$reg->getPackage($parsed['package'], $parsed['channel']);
  29302. $headings = array('Type', 'Install Path');
  29303. $installed = true;
  29304. }
  29305. if (PEAR::isError($info)) {
  29306. return $this->raiseError($info);
  29307. }
  29308. if ($info === null) {
  29309. return $this->raiseError("`$params[0]' not installed");
  29310. }
  29311. $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ?
  29312. $info->getFilelist() : $info->getContents();
  29313. if ($installed) {
  29314. $caption = 'Installed Files For ' . $params[0];
  29315. } else {
  29316. $caption = 'Contents of ' . basename($params[0]);
  29317. }
  29318. $data = array(
  29319. 'caption' => $caption,
  29320. 'border' => true,
  29321. 'headline' => $headings);
  29322. if ($info->getPackagexmlVersion() == '1.0' || $installed) {
  29323. foreach ($list as $file => $att) {
  29324. if ($installed) {
  29325. if (empty($att['installed_as'])) {
  29326. continue;
  29327. }
  29328. $data['data'][] = array($att['role'], $att['installed_as']);
  29329. } else {
  29330. if (isset($att['baseinstalldir']) && !in_array($att['role'],
  29331. array('test', 'data', 'doc'))) {
  29332. $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR .
  29333. $file;
  29334. } else {
  29335. $dest = $file;
  29336. }
  29337. switch ($att['role']) {
  29338. case 'test':
  29339. case 'data':
  29340. case 'doc':
  29341. $role = $att['role'];
  29342. if ($role == 'test') {
  29343. $role .= 's';
  29344. }
  29345. $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR .
  29346. $info->getPackage() . DIRECTORY_SEPARATOR . $dest;
  29347. break;
  29348. case 'php':
  29349. default:
  29350. $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR .
  29351. $dest;
  29352. }
  29353. $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  29354. $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
  29355. array(DIRECTORY_SEPARATOR,
  29356. DIRECTORY_SEPARATOR,
  29357. DIRECTORY_SEPARATOR),
  29358. $dest);
  29359. $file = preg_replace('!/+!', '/', $file);
  29360. $data['data'][] = array($file, $dest);
  29361. }
  29362. }
  29363. } else { // package.xml 2.0, not installed
  29364. if (!isset($list['dir']['file'][0])) {
  29365. $list['dir']['file'] = array($list['dir']['file']);
  29366. }
  29367. foreach ($list['dir']['file'] as $att) {
  29368. $att = $att['attribs'];
  29369. $file = $att['name'];
  29370. $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config);
  29371. $role->setup($this, $info, $att, $file);
  29372. if (!$role->isInstallable()) {
  29373. $dest = '(not installable)';
  29374. } else {
  29375. $dest = $role->processInstallation($info, $att, $file, '');
  29376. if (PEAR::isError($dest)) {
  29377. $dest = '(Unknown role "' . $att['role'] . ')';
  29378. } else {
  29379. list(,, $dest) = $dest;
  29380. }
  29381. }
  29382. $data['data'][] = array($file, $dest);
  29383. }
  29384. }
  29385. $this->ui->outputData($data, $command);
  29386. return true;
  29387. }
  29388. function doShellTest($command, $options, $params)
  29389. {
  29390. if (count($params) < 1) {
  29391. return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]');
  29392. }
  29393. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  29394. $reg = &$this->config->getRegistry();
  29395. $info = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  29396. if (PEAR::isError($info)) {
  29397. exit(1); // invalid package name
  29398. }
  29399. $package = $info['package'];
  29400. $channel = $info['channel'];
  29401. // "pear shell-test Foo"
  29402. if (!$reg->packageExists($package, $channel)) {
  29403. if ($channel == 'pecl.php.net') {
  29404. if ($reg->packageExists($package, 'pear.php.net')) {
  29405. $channel = 'pear.php.net'; // magically change channels for extensions
  29406. }
  29407. }
  29408. }
  29409. if (count($params) === 1) {
  29410. if (!$reg->packageExists($package, $channel)) {
  29411. exit(1);
  29412. }
  29413. // "pear shell-test Foo 1.0"
  29414. } elseif (count($params) === 2) {
  29415. $v = $reg->packageInfo($package, 'version', $channel);
  29416. if (!$v || !version_compare("$v", "{$params[1]}", "ge")) {
  29417. exit(1);
  29418. }
  29419. // "pear shell-test Foo ge 1.0"
  29420. } elseif (count($params) === 3) {
  29421. $v = $reg->packageInfo($package, 'version', $channel);
  29422. if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) {
  29423. exit(1);
  29424. }
  29425. } else {
  29426. PEAR::staticPopErrorHandling();
  29427. $this->raiseError("$command: expects 1 to 3 parameters");
  29428. exit(1);
  29429. }
  29430. }
  29431. function doInfo($command, $options, $params)
  29432. {
  29433. if (count($params) !== 1) {
  29434. return $this->raiseError('pear info expects 1 parameter');
  29435. }
  29436. $info = $fp = false;
  29437. $reg = &$this->config->getRegistry();
  29438. if (is_file($params[0]) && !is_dir($params[0]) &&
  29439. (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))
  29440. ) {
  29441. if ($fp) {
  29442. fclose($fp);
  29443. }
  29444. if (!class_exists('PEAR_PackageFile')) {
  29445. require_once 'PEAR/PackageFile.php';
  29446. }
  29447. $pkg = new PEAR_PackageFile($this->config, $this->_debug);
  29448. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  29449. $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  29450. PEAR::staticPopErrorHandling();
  29451. if (PEAR::isError($obj)) {
  29452. $uinfo = $obj->getUserInfo();
  29453. if (is_array($uinfo)) {
  29454. foreach ($uinfo as $message) {
  29455. if (is_array($message)) {
  29456. $message = $message['message'];
  29457. }
  29458. $this->ui->outputData($message);
  29459. }
  29460. }
  29461. return $this->raiseError($obj);
  29462. }
  29463. if ($obj->getPackagexmlVersion() != '1.0') {
  29464. return $this->_doInfo2($command, $options, $params, $obj, false);
  29465. }
  29466. $info = $obj->toArray();
  29467. } else {
  29468. $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  29469. if (PEAR::isError($parsed)) {
  29470. return $this->raiseError($parsed);
  29471. }
  29472. $package = $parsed['package'];
  29473. $channel = $parsed['channel'];
  29474. $info = $reg->packageInfo($package, null, $channel);
  29475. if (isset($info['old'])) {
  29476. $obj = $reg->getPackage($package, $channel);
  29477. return $this->_doInfo2($command, $options, $params, $obj, true);
  29478. }
  29479. }
  29480. if (PEAR::isError($info)) {
  29481. return $info;
  29482. }
  29483. if (empty($info)) {
  29484. $this->raiseError("No information found for `$params[0]'");
  29485. return;
  29486. }
  29487. unset($info['filelist']);
  29488. unset($info['dirtree']);
  29489. unset($info['changelog']);
  29490. if (isset($info['xsdversion'])) {
  29491. $info['package.xml version'] = $info['xsdversion'];
  29492. unset($info['xsdversion']);
  29493. }
  29494. if (isset($info['packagerversion'])) {
  29495. $info['packaged with PEAR version'] = $info['packagerversion'];
  29496. unset($info['packagerversion']);
  29497. }
  29498. $keys = array_keys($info);
  29499. $longtext = array('description', 'summary');
  29500. foreach ($keys as $key) {
  29501. if (is_array($info[$key])) {
  29502. switch ($key) {
  29503. case 'maintainers': {
  29504. $i = 0;
  29505. $mstr = '';
  29506. foreach ($info[$key] as $m) {
  29507. if ($i++ > 0) {
  29508. $mstr .= "\n";
  29509. }
  29510. $mstr .= $m['name'] . " <";
  29511. if (isset($m['email'])) {
  29512. $mstr .= $m['email'];
  29513. } else {
  29514. $mstr .= $m['handle'] . '@php.net';
  29515. }
  29516. $mstr .= "> ($m[role])";
  29517. }
  29518. $info[$key] = $mstr;
  29519. break;
  29520. }
  29521. case 'release_deps': {
  29522. $i = 0;
  29523. $dstr = '';
  29524. foreach ($info[$key] as $d) {
  29525. if (isset($this->_deps_rel_trans[$d['rel']])) {
  29526. $rel = $this->_deps_rel_trans[$d['rel']];
  29527. } else {
  29528. $rel = $d['rel'];
  29529. }
  29530. if (isset($this->_deps_type_trans[$d['type']])) {
  29531. $type = ucfirst($this->_deps_type_trans[$d['type']]);
  29532. } else {
  29533. $type = $d['type'];
  29534. }
  29535. if (isset($d['name'])) {
  29536. $name = $d['name'] . ' ';
  29537. } else {
  29538. $name = '';
  29539. }
  29540. if (isset($d['version'])) {
  29541. $version = $d['version'] . ' ';
  29542. } else {
  29543. $version = '';
  29544. }
  29545. if (isset($d['optional']) && $d['optional'] == 'yes') {
  29546. $optional = ' (optional)';
  29547. } else {
  29548. $optional = '';
  29549. }
  29550. $dstr .= "$type $name$rel $version$optional\n";
  29551. }
  29552. $info[$key] = $dstr;
  29553. break;
  29554. }
  29555. case 'provides' : {
  29556. $debug = $this->config->get('verbose');
  29557. if ($debug < 2) {
  29558. $pstr = 'Classes: ';
  29559. } else {
  29560. $pstr = '';
  29561. }
  29562. $i = 0;
  29563. foreach ($info[$key] as $p) {
  29564. if ($debug < 2 && $p['type'] != "class") {
  29565. continue;
  29566. }
  29567. // Only print classes when verbosity mode is < 2
  29568. if ($debug < 2) {
  29569. if ($i++ > 0) {
  29570. $pstr .= ", ";
  29571. }
  29572. $pstr .= $p['name'];
  29573. } else {
  29574. if ($i++ > 0) {
  29575. $pstr .= "\n";
  29576. }
  29577. $pstr .= ucfirst($p['type']) . " " . $p['name'];
  29578. if (isset($p['explicit']) && $p['explicit'] == 1) {
  29579. $pstr .= " (explicit)";
  29580. }
  29581. }
  29582. }
  29583. $info[$key] = $pstr;
  29584. break;
  29585. }
  29586. case 'configure_options' : {
  29587. foreach ($info[$key] as $i => $p) {
  29588. $info[$key][$i] = array_map(null, array_keys($p), array_values($p));
  29589. $info[$key][$i] = array_map(
  29590. function($a) { return join(" = ", $a); },
  29591. $info[$key][$i]);
  29592. $info[$key][$i] = implode(', ', $info[$key][$i]);
  29593. }
  29594. $info[$key] = implode("\n", $info[$key]);
  29595. break;
  29596. }
  29597. default: {
  29598. $info[$key] = implode(", ", $info[$key]);
  29599. break;
  29600. }
  29601. }
  29602. }
  29603. if ($key == '_lastmodified') {
  29604. $hdate = date('Y-m-d', $info[$key]);
  29605. unset($info[$key]);
  29606. $info['Last Modified'] = $hdate;
  29607. } elseif ($key == '_lastversion') {
  29608. $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -';
  29609. unset($info[$key]);
  29610. } else {
  29611. $info[$key] = trim($info[$key]);
  29612. if (in_array($key, $longtext)) {
  29613. $info[$key] = preg_replace('/ +/', ' ', $info[$key]);
  29614. }
  29615. }
  29616. }
  29617. $caption = 'About ' . $info['package'] . '-' . $info['version'];
  29618. $data = array(
  29619. 'caption' => $caption,
  29620. 'border' => true);
  29621. foreach ($info as $key => $value) {
  29622. $key = ucwords(trim(str_replace('_', ' ', $key)));
  29623. $data['data'][] = array($key, $value);
  29624. }
  29625. $data['raw'] = $info;
  29626. $this->ui->outputData($data, 'package-info');
  29627. }
  29628. /**
  29629. * @access private
  29630. */
  29631. function _doInfo2($command, $options, $params, &$obj, $installed)
  29632. {
  29633. $reg = &$this->config->getRegistry();
  29634. $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' .
  29635. $obj->getVersion();
  29636. $data = array(
  29637. 'caption' => $caption,
  29638. 'border' => true);
  29639. switch ($obj->getPackageType()) {
  29640. case 'php' :
  29641. $release = 'PEAR-style PHP-based Package';
  29642. break;
  29643. case 'extsrc' :
  29644. $release = 'PECL-style PHP extension (source code)';
  29645. break;
  29646. case 'zendextsrc' :
  29647. $release = 'PECL-style Zend extension (source code)';
  29648. break;
  29649. case 'extbin' :
  29650. $release = 'PECL-style PHP extension (binary)';
  29651. break;
  29652. case 'zendextbin' :
  29653. $release = 'PECL-style Zend extension (binary)';
  29654. break;
  29655. case 'bundle' :
  29656. $release = 'Package bundle (collection of packages)';
  29657. break;
  29658. }
  29659. $extends = $obj->getExtends();
  29660. $extends = $extends ?
  29661. $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage();
  29662. if ($src = $obj->getSourcePackage()) {
  29663. $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')';
  29664. }
  29665. $info = array(
  29666. 'Release Type' => $release,
  29667. 'Name' => $extends,
  29668. 'Channel' => $obj->getChannel(),
  29669. 'Summary' => preg_replace('/ +/', ' ', $obj->getSummary()),
  29670. 'Description' => preg_replace('/ +/', ' ', $obj->getDescription()),
  29671. );
  29672. $info['Maintainers'] = '';
  29673. foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
  29674. $leads = $obj->{"get{$role}s"}();
  29675. if (!$leads) {
  29676. continue;
  29677. }
  29678. if (isset($leads['active'])) {
  29679. $leads = array($leads);
  29680. }
  29681. foreach ($leads as $lead) {
  29682. if (!empty($info['Maintainers'])) {
  29683. $info['Maintainers'] .= "\n";
  29684. }
  29685. $active = $lead['active'] == 'no' ? ', inactive' : '';
  29686. $info['Maintainers'] .= $lead['name'] . ' <';
  29687. $info['Maintainers'] .= $lead['email'] . "> ($role$active)";
  29688. }
  29689. }
  29690. $info['Release Date'] = $obj->getDate();
  29691. if ($time = $obj->getTime()) {
  29692. $info['Release Date'] .= ' ' . $time;
  29693. }
  29694. $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')';
  29695. $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')';
  29696. $info['License'] = $obj->getLicense();
  29697. $uri = $obj->getLicenseLocation();
  29698. if ($uri) {
  29699. if (isset($uri['uri'])) {
  29700. $info['License'] .= ' (' . $uri['uri'] . ')';
  29701. } else {
  29702. $extra = $obj->getInstalledLocation($info['filesource']);
  29703. if ($extra) {
  29704. $info['License'] .= ' (' . $uri['filesource'] . ')';
  29705. }
  29706. }
  29707. }
  29708. $info['Release Notes'] = $obj->getNotes();
  29709. if ($compat = $obj->getCompatible()) {
  29710. if (!isset($compat[0])) {
  29711. $compat = array($compat);
  29712. }
  29713. $info['Compatible with'] = '';
  29714. foreach ($compat as $package) {
  29715. $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] .
  29716. "\nVersions >= " . $package['min'] . ', <= ' . $package['max'];
  29717. if (isset($package['exclude'])) {
  29718. if (is_array($package['exclude'])) {
  29719. $package['exclude'] = implode(', ', $package['exclude']);
  29720. }
  29721. if (!isset($info['Not Compatible with'])) {
  29722. $info['Not Compatible with'] = '';
  29723. } else {
  29724. $info['Not Compatible with'] .= "\n";
  29725. }
  29726. $info['Not Compatible with'] .= $package['channel'] . '/' .
  29727. $package['name'] . "\nVersions " . $package['exclude'];
  29728. }
  29729. }
  29730. }
  29731. $usesrole = $obj->getUsesrole();
  29732. if ($usesrole) {
  29733. if (!isset($usesrole[0])) {
  29734. $usesrole = array($usesrole);
  29735. }
  29736. foreach ($usesrole as $roledata) {
  29737. if (isset($info['Uses Custom Roles'])) {
  29738. $info['Uses Custom Roles'] .= "\n";
  29739. } else {
  29740. $info['Uses Custom Roles'] = '';
  29741. }
  29742. if (isset($roledata['package'])) {
  29743. $rolepackage = $reg->parsedPackageNameToString($roledata, true);
  29744. } else {
  29745. $rolepackage = $roledata['uri'];
  29746. }
  29747. $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')';
  29748. }
  29749. }
  29750. $usestask = $obj->getUsestask();
  29751. if ($usestask) {
  29752. if (!isset($usestask[0])) {
  29753. $usestask = array($usestask);
  29754. }
  29755. foreach ($usestask as $taskdata) {
  29756. if (isset($info['Uses Custom Tasks'])) {
  29757. $info['Uses Custom Tasks'] .= "\n";
  29758. } else {
  29759. $info['Uses Custom Tasks'] = '';
  29760. }
  29761. if (isset($taskdata['package'])) {
  29762. $taskpackage = $reg->parsedPackageNameToString($taskdata, true);
  29763. } else {
  29764. $taskpackage = $taskdata['uri'];
  29765. }
  29766. $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')';
  29767. }
  29768. }
  29769. $deps = $obj->getDependencies();
  29770. $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min'];
  29771. if (isset($deps['required']['php']['max'])) {
  29772. $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n";
  29773. } else {
  29774. $info['Required Dependencies'] .= "\n";
  29775. }
  29776. if (isset($deps['required']['php']['exclude'])) {
  29777. if (!isset($info['Not Compatible with'])) {
  29778. $info['Not Compatible with'] = '';
  29779. } else {
  29780. $info['Not Compatible with'] .= "\n";
  29781. }
  29782. if (is_array($deps['required']['php']['exclude'])) {
  29783. $deps['required']['php']['exclude'] =
  29784. implode(', ', $deps['required']['php']['exclude']);
  29785. }
  29786. $info['Not Compatible with'] .= "PHP versions\n " .
  29787. $deps['required']['php']['exclude'];
  29788. }
  29789. $info['Required Dependencies'] .= 'PEAR installer version';
  29790. if (isset($deps['required']['pearinstaller']['max'])) {
  29791. $info['Required Dependencies'] .= 's ' .
  29792. $deps['required']['pearinstaller']['min'] . '-' .
  29793. $deps['required']['pearinstaller']['max'];
  29794. } else {
  29795. $info['Required Dependencies'] .= ' ' .
  29796. $deps['required']['pearinstaller']['min'] . ' or newer';
  29797. }
  29798. if (isset($deps['required']['pearinstaller']['exclude'])) {
  29799. if (!isset($info['Not Compatible with'])) {
  29800. $info['Not Compatible with'] = '';
  29801. } else {
  29802. $info['Not Compatible with'] .= "\n";
  29803. }
  29804. if (is_array($deps['required']['pearinstaller']['exclude'])) {
  29805. $deps['required']['pearinstaller']['exclude'] =
  29806. implode(', ', $deps['required']['pearinstaller']['exclude']);
  29807. }
  29808. $info['Not Compatible with'] .= "PEAR installer\n Versions " .
  29809. $deps['required']['pearinstaller']['exclude'];
  29810. }
  29811. foreach (array('Package', 'Extension') as $type) {
  29812. $index = strtolower($type);
  29813. if (isset($deps['required'][$index])) {
  29814. if (isset($deps['required'][$index]['name'])) {
  29815. $deps['required'][$index] = array($deps['required'][$index]);
  29816. }
  29817. foreach ($deps['required'][$index] as $package) {
  29818. if (isset($package['conflicts'])) {
  29819. $infoindex = 'Not Compatible with';
  29820. if (!isset($info['Not Compatible with'])) {
  29821. $info['Not Compatible with'] = '';
  29822. } else {
  29823. $info['Not Compatible with'] .= "\n";
  29824. }
  29825. } else {
  29826. $infoindex = 'Required Dependencies';
  29827. $info[$infoindex] .= "\n";
  29828. }
  29829. if ($index == 'extension') {
  29830. $name = $package['name'];
  29831. } else {
  29832. if (isset($package['channel'])) {
  29833. $name = $package['channel'] . '/' . $package['name'];
  29834. } else {
  29835. $name = '__uri/' . $package['name'] . ' (static URI)';
  29836. }
  29837. }
  29838. $info[$infoindex] .= "$type $name";
  29839. if (isset($package['uri'])) {
  29840. $info[$infoindex] .= "\n Download URI: $package[uri]";
  29841. continue;
  29842. }
  29843. if (isset($package['max']) && isset($package['min'])) {
  29844. $info[$infoindex] .= " \n Versions " .
  29845. $package['min'] . '-' . $package['max'];
  29846. } elseif (isset($package['min'])) {
  29847. $info[$infoindex] .= " \n Version " .
  29848. $package['min'] . ' or newer';
  29849. } elseif (isset($package['max'])) {
  29850. $info[$infoindex] .= " \n Version " .
  29851. $package['max'] . ' or older';
  29852. }
  29853. if (isset($package['recommended'])) {
  29854. $info[$infoindex] .= "\n Recommended version: $package[recommended]";
  29855. }
  29856. if (isset($package['exclude'])) {
  29857. if (!isset($info['Not Compatible with'])) {
  29858. $info['Not Compatible with'] = '';
  29859. } else {
  29860. $info['Not Compatible with'] .= "\n";
  29861. }
  29862. if (is_array($package['exclude'])) {
  29863. $package['exclude'] = implode(', ', $package['exclude']);
  29864. }
  29865. $package['package'] = $package['name']; // for parsedPackageNameToString
  29866. if (isset($package['conflicts'])) {
  29867. $info['Not Compatible with'] .= '=> except ';
  29868. }
  29869. $info['Not Compatible with'] .= 'Package ' .
  29870. $reg->parsedPackageNameToString($package, true);
  29871. $info['Not Compatible with'] .= "\n Versions " . $package['exclude'];
  29872. }
  29873. }
  29874. }
  29875. }
  29876. if (isset($deps['required']['os'])) {
  29877. if (isset($deps['required']['os']['name'])) {
  29878. $dep['required']['os']['name'] = array($dep['required']['os']['name']);
  29879. }
  29880. foreach ($dep['required']['os'] as $os) {
  29881. if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
  29882. if (!isset($info['Not Compatible with'])) {
  29883. $info['Not Compatible with'] = '';
  29884. } else {
  29885. $info['Not Compatible with'] .= "\n";
  29886. }
  29887. $info['Not Compatible with'] .= "$os[name] Operating System";
  29888. } else {
  29889. $info['Required Dependencies'] .= "\n";
  29890. $info['Required Dependencies'] .= "$os[name] Operating System";
  29891. }
  29892. }
  29893. }
  29894. if (isset($deps['required']['arch'])) {
  29895. if (isset($deps['required']['arch']['pattern'])) {
  29896. $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']);
  29897. }
  29898. foreach ($dep['required']['arch'] as $os) {
  29899. if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
  29900. if (!isset($info['Not Compatible with'])) {
  29901. $info['Not Compatible with'] = '';
  29902. } else {
  29903. $info['Not Compatible with'] .= "\n";
  29904. }
  29905. $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'";
  29906. } else {
  29907. $info['Required Dependencies'] .= "\n";
  29908. $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'";
  29909. }
  29910. }
  29911. }
  29912. if (isset($deps['optional'])) {
  29913. foreach (array('Package', 'Extension') as $type) {
  29914. $index = strtolower($type);
  29915. if (isset($deps['optional'][$index])) {
  29916. if (isset($deps['optional'][$index]['name'])) {
  29917. $deps['optional'][$index] = array($deps['optional'][$index]);
  29918. }
  29919. foreach ($deps['optional'][$index] as $package) {
  29920. if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
  29921. $infoindex = 'Not Compatible with';
  29922. if (!isset($info['Not Compatible with'])) {
  29923. $info['Not Compatible with'] = '';
  29924. } else {
  29925. $info['Not Compatible with'] .= "\n";
  29926. }
  29927. } else {
  29928. $infoindex = 'Optional Dependencies';
  29929. if (!isset($info['Optional Dependencies'])) {
  29930. $info['Optional Dependencies'] = '';
  29931. } else {
  29932. $info['Optional Dependencies'] .= "\n";
  29933. }
  29934. }
  29935. if ($index == 'extension') {
  29936. $name = $package['name'];
  29937. } else {
  29938. if (isset($package['channel'])) {
  29939. $name = $package['channel'] . '/' . $package['name'];
  29940. } else {
  29941. $name = '__uri/' . $package['name'] . ' (static URI)';
  29942. }
  29943. }
  29944. $info[$infoindex] .= "$type $name";
  29945. if (isset($package['uri'])) {
  29946. $info[$infoindex] .= "\n Download URI: $package[uri]";
  29947. continue;
  29948. }
  29949. if ($infoindex == 'Not Compatible with') {
  29950. // conflicts is only used to say that all versions conflict
  29951. continue;
  29952. }
  29953. if (isset($package['max']) && isset($package['min'])) {
  29954. $info[$infoindex] .= " \n Versions " .
  29955. $package['min'] . '-' . $package['max'];
  29956. } elseif (isset($package['min'])) {
  29957. $info[$infoindex] .= " \n Version " .
  29958. $package['min'] . ' or newer';
  29959. } elseif (isset($package['max'])) {
  29960. $info[$infoindex] .= " \n Version " .
  29961. $package['min'] . ' or older';
  29962. }
  29963. if (isset($package['recommended'])) {
  29964. $info[$infoindex] .= "\n Recommended version: $package[recommended]";
  29965. }
  29966. if (isset($package['exclude'])) {
  29967. if (!isset($info['Not Compatible with'])) {
  29968. $info['Not Compatible with'] = '';
  29969. } else {
  29970. $info['Not Compatible with'] .= "\n";
  29971. }
  29972. if (is_array($package['exclude'])) {
  29973. $package['exclude'] = implode(', ', $package['exclude']);
  29974. }
  29975. $info['Not Compatible with'] .= "Package $package\n Versions " .
  29976. $package['exclude'];
  29977. }
  29978. }
  29979. }
  29980. }
  29981. }
  29982. if (isset($deps['group'])) {
  29983. if (!isset($deps['group'][0])) {
  29984. $deps['group'] = array($deps['group']);
  29985. }
  29986. foreach ($deps['group'] as $group) {
  29987. $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint'];
  29988. $groupindex = $group['attribs']['name'] . ' Contents';
  29989. $info[$groupindex] = '';
  29990. foreach (array('Package', 'Extension') as $type) {
  29991. $index = strtolower($type);
  29992. if (isset($group[$index])) {
  29993. if (isset($group[$index]['name'])) {
  29994. $group[$index] = array($group[$index]);
  29995. }
  29996. foreach ($group[$index] as $package) {
  29997. if (!empty($info[$groupindex])) {
  29998. $info[$groupindex] .= "\n";
  29999. }
  30000. if ($index == 'extension') {
  30001. $name = $package['name'];
  30002. } else {
  30003. if (isset($package['channel'])) {
  30004. $name = $package['channel'] . '/' . $package['name'];
  30005. } else {
  30006. $name = '__uri/' . $package['name'] . ' (static URI)';
  30007. }
  30008. }
  30009. if (isset($package['uri'])) {
  30010. if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
  30011. $info[$groupindex] .= "Not Compatible with $type $name";
  30012. } else {
  30013. $info[$groupindex] .= "$type $name";
  30014. }
  30015. $info[$groupindex] .= "\n Download URI: $package[uri]";
  30016. continue;
  30017. }
  30018. if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
  30019. $info[$groupindex] .= "Not Compatible with $type $name";
  30020. continue;
  30021. }
  30022. $info[$groupindex] .= "$type $name";
  30023. if (isset($package['max']) && isset($package['min'])) {
  30024. $info[$groupindex] .= " \n Versions " .
  30025. $package['min'] . '-' . $package['max'];
  30026. } elseif (isset($package['min'])) {
  30027. $info[$groupindex] .= " \n Version " .
  30028. $package['min'] . ' or newer';
  30029. } elseif (isset($package['max'])) {
  30030. $info[$groupindex] .= " \n Version " .
  30031. $package['min'] . ' or older';
  30032. }
  30033. if (isset($package['recommended'])) {
  30034. $info[$groupindex] .= "\n Recommended version: $package[recommended]";
  30035. }
  30036. if (isset($package['exclude'])) {
  30037. if (!isset($info['Not Compatible with'])) {
  30038. $info['Not Compatible with'] = '';
  30039. } else {
  30040. $info[$groupindex] .= "Not Compatible with\n";
  30041. }
  30042. if (is_array($package['exclude'])) {
  30043. $package['exclude'] = implode(', ', $package['exclude']);
  30044. }
  30045. $info[$groupindex] .= " Package $package\n Versions " .
  30046. $package['exclude'];
  30047. }
  30048. }
  30049. }
  30050. }
  30051. }
  30052. }
  30053. if ($obj->getPackageType() == 'bundle') {
  30054. $info['Bundled Packages'] = '';
  30055. foreach ($obj->getBundledPackages() as $package) {
  30056. if (!empty($info['Bundled Packages'])) {
  30057. $info['Bundled Packages'] .= "\n";
  30058. }
  30059. if (isset($package['uri'])) {
  30060. $info['Bundled Packages'] .= '__uri/' . $package['name'];
  30061. $info['Bundled Packages'] .= "\n (URI: $package[uri]";
  30062. } else {
  30063. $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name'];
  30064. }
  30065. }
  30066. }
  30067. $info['package.xml version'] = '2.0';
  30068. if ($installed) {
  30069. if ($obj->getLastModified()) {
  30070. $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified());
  30071. }
  30072. $v = $obj->getLastInstalledVersion();
  30073. $info['Previous Installed Version'] = $v ? $v : '- None -';
  30074. }
  30075. foreach ($info as $key => $value) {
  30076. $data['data'][] = array($key, $value);
  30077. }
  30078. $data['raw'] = $obj->getArray(); // no validation needed
  30079. $this->ui->outputData($data, 'package-info');
  30080. }
  30081. }
  30082. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Remote.xml����������������������������������������������������������������0000644�0001750�0001750�00000006357�13565304531�016353� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  30083. <remote-info>
  30084. <summary>Information About Remote Packages</summary>
  30085. <function>doRemoteInfo</function>
  30086. <shortcut>ri</shortcut>
  30087. <options />
  30088. <doc>&lt;package&gt;
  30089. Get details on a package from the server.</doc>
  30090. </remote-info>
  30091. <list-upgrades>
  30092. <summary>List Available Upgrades</summary>
  30093. <function>doListUpgrades</function>
  30094. <shortcut>lu</shortcut>
  30095. <options>
  30096. <channelinfo>
  30097. <shortopt>i</shortopt>
  30098. <doc>output fully channel-aware data, even on failure</doc>
  30099. </channelinfo>
  30100. </options>
  30101. <doc>[preferred_state]
  30102. List releases on the server of packages you have installed where
  30103. a newer version is available with the same release state (stable etc.)
  30104. or the state passed as the second parameter.</doc>
  30105. </list-upgrades>
  30106. <remote-list>
  30107. <summary>List Remote Packages</summary>
  30108. <function>doRemoteList</function>
  30109. <shortcut>rl</shortcut>
  30110. <options>
  30111. <channel>
  30112. <shortopt>c</shortopt>
  30113. <doc>specify a channel other than the default channel</doc>
  30114. <arg>CHAN</arg>
  30115. </channel>
  30116. </options>
  30117. <doc>
  30118. Lists the packages available on the configured server along with the
  30119. latest stable release of each package.</doc>
  30120. </remote-list>
  30121. <search>
  30122. <summary>Search remote package database</summary>
  30123. <function>doSearch</function>
  30124. <shortcut>sp</shortcut>
  30125. <options>
  30126. <channel>
  30127. <shortopt>c</shortopt>
  30128. <doc>specify a channel other than the default channel</doc>
  30129. <arg>CHAN</arg>
  30130. </channel>
  30131. <allchannels>
  30132. <shortopt>a</shortopt>
  30133. <doc>search packages from all known channels</doc>
  30134. </allchannels>
  30135. <channelinfo>
  30136. <shortopt>i</shortopt>
  30137. <doc>output fully channel-aware data, even on failure</doc>
  30138. </channelinfo>
  30139. </options>
  30140. <doc>[packagename] [packageinfo]
  30141. Lists all packages which match the search parameters. The first
  30142. parameter is a fragment of a packagename. The default channel
  30143. will be used unless explicitly overridden. The second parameter
  30144. will be used to match any portion of the summary/description</doc>
  30145. </search>
  30146. <list-all>
  30147. <summary>List All Packages</summary>
  30148. <function>doListAll</function>
  30149. <shortcut>la</shortcut>
  30150. <options>
  30151. <channel>
  30152. <shortopt>c</shortopt>
  30153. <doc>specify a channel other than the default channel</doc>
  30154. <arg>CHAN</arg>
  30155. </channel>
  30156. <channelinfo>
  30157. <shortopt>i</shortopt>
  30158. <doc>output fully channel-aware data, even on failure</doc>
  30159. </channelinfo>
  30160. </options>
  30161. <doc>
  30162. Lists the packages available on the configured server along with the
  30163. latest stable release of each package.</doc>
  30164. </list-all>
  30165. <download>
  30166. <summary>Download Package</summary>
  30167. <function>doDownload</function>
  30168. <shortcut>d</shortcut>
  30169. <options>
  30170. <nocompress>
  30171. <shortopt>Z</shortopt>
  30172. <doc>download an uncompressed (.tar) file</doc>
  30173. </nocompress>
  30174. </options>
  30175. <doc>&lt;package&gt;...
  30176. Download package tarballs. The files will be named as suggested by the
  30177. server, for example if you download the DB package and the latest stable
  30178. version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.</doc>
  30179. </download>
  30180. <clear-cache>
  30181. <summary>Clear Web Services Cache</summary>
  30182. <function>doClearCache</function>
  30183. <shortcut>cc</shortcut>
  30184. <options />
  30185. <doc>
  30186. Clear the XML-RPC/REST cache. See also the cache_ttl configuration
  30187. parameter.
  30188. </doc>
  30189. </clear-cache>
  30190. </commands>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Remote.php����������������������������������������������������������������0000644�0001750�0001750�00000072442�13565304531�016340� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  30191. /**
  30192. * PEAR_Command_Remote (remote-info, list-upgrades, remote-list, search, list-all, download,
  30193. * clear-cache commands)
  30194. *
  30195. * PHP versions 4 and 5
  30196. *
  30197. * @category pear
  30198. * @package PEAR
  30199. * @author Stig Bakken <ssb@php.net>
  30200. * @author Greg Beaver <cellog@php.net>
  30201. * @copyright 1997-2009 The Authors
  30202. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  30203. * @link http://pear.php.net/package/PEAR
  30204. * @since File available since Release 0.1
  30205. */
  30206. /**
  30207. * base class
  30208. */
  30209. require_once 'PEAR/Command/Common.php';
  30210. require_once 'PEAR/REST.php';
  30211. /**
  30212. * PEAR commands for remote server querying
  30213. *
  30214. * @category pear
  30215. * @package PEAR
  30216. * @author Stig Bakken <ssb@php.net>
  30217. * @author Greg Beaver <cellog@php.net>
  30218. * @copyright 1997-2009 The Authors
  30219. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  30220. * @version Release: 1.10.10
  30221. * @link http://pear.php.net/package/PEAR
  30222. * @since Class available since Release 0.1
  30223. */
  30224. class PEAR_Command_Remote extends PEAR_Command_Common
  30225. {
  30226. var $commands = array(
  30227. 'remote-info' => array(
  30228. 'summary' => 'Information About Remote Packages',
  30229. 'function' => 'doRemoteInfo',
  30230. 'shortcut' => 'ri',
  30231. 'options' => array(),
  30232. 'doc' => '<package>
  30233. Get details on a package from the server.',
  30234. ),
  30235. 'list-upgrades' => array(
  30236. 'summary' => 'List Available Upgrades',
  30237. 'function' => 'doListUpgrades',
  30238. 'shortcut' => 'lu',
  30239. 'options' => array(
  30240. 'channelinfo' => array(
  30241. 'shortopt' => 'i',
  30242. 'doc' => 'output fully channel-aware data, even on failure',
  30243. ),
  30244. ),
  30245. 'doc' => '[preferred_state]
  30246. List releases on the server of packages you have installed where
  30247. a newer version is available with the same release state (stable etc.)
  30248. or the state passed as the second parameter.'
  30249. ),
  30250. 'remote-list' => array(
  30251. 'summary' => 'List Remote Packages',
  30252. 'function' => 'doRemoteList',
  30253. 'shortcut' => 'rl',
  30254. 'options' => array(
  30255. 'channel' =>
  30256. array(
  30257. 'shortopt' => 'c',
  30258. 'doc' => 'specify a channel other than the default channel',
  30259. 'arg' => 'CHAN',
  30260. )
  30261. ),
  30262. 'doc' => '
  30263. Lists the packages available on the configured server along with the
  30264. latest stable release of each package.',
  30265. ),
  30266. 'search' => array(
  30267. 'summary' => 'Search remote package database',
  30268. 'function' => 'doSearch',
  30269. 'shortcut' => 'sp',
  30270. 'options' => array(
  30271. 'channel' =>
  30272. array(
  30273. 'shortopt' => 'c',
  30274. 'doc' => 'specify a channel other than the default channel',
  30275. 'arg' => 'CHAN',
  30276. ),
  30277. 'allchannels' => array(
  30278. 'shortopt' => 'a',
  30279. 'doc' => 'search packages from all known channels',
  30280. ),
  30281. 'channelinfo' => array(
  30282. 'shortopt' => 'i',
  30283. 'doc' => 'output fully channel-aware data, even on failure',
  30284. ),
  30285. ),
  30286. 'doc' => '[packagename] [packageinfo]
  30287. Lists all packages which match the search parameters. The first
  30288. parameter is a fragment of a packagename. The default channel
  30289. will be used unless explicitly overridden. The second parameter
  30290. will be used to match any portion of the summary/description',
  30291. ),
  30292. 'list-all' => array(
  30293. 'summary' => 'List All Packages',
  30294. 'function' => 'doListAll',
  30295. 'shortcut' => 'la',
  30296. 'options' => array(
  30297. 'channel' =>
  30298. array(
  30299. 'shortopt' => 'c',
  30300. 'doc' => 'specify a channel other than the default channel',
  30301. 'arg' => 'CHAN',
  30302. ),
  30303. 'channelinfo' => array(
  30304. 'shortopt' => 'i',
  30305. 'doc' => 'output fully channel-aware data, even on failure',
  30306. ),
  30307. ),
  30308. 'doc' => '
  30309. Lists the packages available on the configured server along with the
  30310. latest stable release of each package.',
  30311. ),
  30312. 'download' => array(
  30313. 'summary' => 'Download Package',
  30314. 'function' => 'doDownload',
  30315. 'shortcut' => 'd',
  30316. 'options' => array(
  30317. 'nocompress' => array(
  30318. 'shortopt' => 'Z',
  30319. 'doc' => 'download an uncompressed (.tar) file',
  30320. ),
  30321. ),
  30322. 'doc' => '<package>...
  30323. Download package tarballs. The files will be named as suggested by the
  30324. server, for example if you download the DB package and the latest stable
  30325. version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.',
  30326. ),
  30327. 'clear-cache' => array(
  30328. 'summary' => 'Clear Web Services Cache',
  30329. 'function' => 'doClearCache',
  30330. 'shortcut' => 'cc',
  30331. 'options' => array(),
  30332. 'doc' => '
  30333. Clear the REST cache. See also the cache_ttl configuration
  30334. parameter.
  30335. ',
  30336. ),
  30337. );
  30338. /**
  30339. * PEAR_Command_Remote constructor.
  30340. *
  30341. * @access public
  30342. */
  30343. function __construct(&$ui, &$config)
  30344. {
  30345. parent::__construct($ui, $config);
  30346. }
  30347. function _checkChannelForStatus($channel, $chan)
  30348. {
  30349. if (PEAR::isError($chan)) {
  30350. $this->raiseError($chan);
  30351. }
  30352. if (!is_a($chan, 'PEAR_ChannelFile')) {
  30353. return $this->raiseError('Internal corruption error: invalid channel "' .
  30354. $channel . '"');
  30355. }
  30356. $rest = new PEAR_REST($this->config);
  30357. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  30358. $mirror = $this->config->get('preferred_mirror', null,
  30359. $channel);
  30360. $a = $rest->downloadHttp('http://' . $channel .
  30361. '/channel.xml', $chan->lastModified());
  30362. PEAR::staticPopErrorHandling();
  30363. if (!PEAR::isError($a) && $a) {
  30364. $this->ui->outputData('WARNING: channel "' . $channel . '" has ' .
  30365. 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $channel .
  30366. '" to update');
  30367. }
  30368. }
  30369. function doRemoteInfo($command, $options, $params)
  30370. {
  30371. if (sizeof($params) != 1) {
  30372. return $this->raiseError("$command expects one param: the remote package name");
  30373. }
  30374. $savechannel = $channel = $this->config->get('default_channel');
  30375. $reg = &$this->config->getRegistry();
  30376. $package = $params[0];
  30377. $parsed = $reg->parsePackageName($package, $channel);
  30378. if (PEAR::isError($parsed)) {
  30379. return $this->raiseError('Invalid package name "' . $package . '"');
  30380. }
  30381. $channel = $parsed['channel'];
  30382. $this->config->set('default_channel', $channel);
  30383. $chan = $reg->getChannel($channel);
  30384. if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  30385. return $e;
  30386. }
  30387. $mirror = $this->config->get('preferred_mirror');
  30388. if ($chan->supportsREST($mirror) && $base = $chan->getBaseURL('REST1.0', $mirror)) {
  30389. $rest = &$this->config->getREST('1.0', array());
  30390. $info = $rest->packageInfo($base, $parsed['package'], $channel);
  30391. }
  30392. if (!isset($info)) {
  30393. return $this->raiseError('No supported protocol was found');
  30394. }
  30395. if (PEAR::isError($info)) {
  30396. $this->config->set('default_channel', $savechannel);
  30397. return $this->raiseError($info);
  30398. }
  30399. if (!isset($info['name'])) {
  30400. return $this->raiseError('No remote package "' . $package . '" was found');
  30401. }
  30402. $installed = $reg->packageInfo($info['name'], null, $channel);
  30403. $info['installed'] = $installed ? $installed['version'] : '- no -';
  30404. if (is_array($info['installed'])) {
  30405. $info['installed'] = $info['installed']['release'];
  30406. }
  30407. $this->ui->outputData($info, $command);
  30408. $this->config->set('default_channel', $savechannel);
  30409. return true;
  30410. }
  30411. function doRemoteList($command, $options, $params)
  30412. {
  30413. $savechannel = $channel = $this->config->get('default_channel');
  30414. $reg = &$this->config->getRegistry();
  30415. if (isset($options['channel'])) {
  30416. $channel = $options['channel'];
  30417. if (!$reg->channelExists($channel)) {
  30418. return $this->raiseError('Channel "' . $channel . '" does not exist');
  30419. }
  30420. $this->config->set('default_channel', $channel);
  30421. }
  30422. $chan = $reg->getChannel($channel);
  30423. if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  30424. return $e;
  30425. }
  30426. $list_options = false;
  30427. if ($this->config->get('preferred_state') == 'stable') {
  30428. $list_options = true;
  30429. }
  30430. $available = array();
  30431. if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  30432. $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))
  30433. ) {
  30434. // use faster list-all if available
  30435. $rest = &$this->config->getREST('1.1', array());
  30436. $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName());
  30437. } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  30438. $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  30439. $rest = &$this->config->getREST('1.0', array());
  30440. $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName());
  30441. }
  30442. if (PEAR::isError($available)) {
  30443. $this->config->set('default_channel', $savechannel);
  30444. return $this->raiseError($available);
  30445. }
  30446. $i = $j = 0;
  30447. $data = array(
  30448. 'caption' => 'Channel ' . $channel . ' Available packages:',
  30449. 'border' => true,
  30450. 'headline' => array('Package', 'Version'),
  30451. 'channel' => $channel
  30452. );
  30453. if (count($available) == 0) {
  30454. $data = '(no packages available yet)';
  30455. } else {
  30456. foreach ($available as $name => $info) {
  30457. $version = (isset($info['stable']) && $info['stable']) ? $info['stable'] : '-n/a-';
  30458. $data['data'][] = array($name, $version);
  30459. }
  30460. }
  30461. $this->ui->outputData($data, $command);
  30462. $this->config->set('default_channel', $savechannel);
  30463. return true;
  30464. }
  30465. function doListAll($command, $options, $params)
  30466. {
  30467. $savechannel = $channel = $this->config->get('default_channel');
  30468. $reg = &$this->config->getRegistry();
  30469. if (isset($options['channel'])) {
  30470. $channel = $options['channel'];
  30471. if (!$reg->channelExists($channel)) {
  30472. return $this->raiseError("Channel \"$channel\" does not exist");
  30473. }
  30474. $this->config->set('default_channel', $channel);
  30475. }
  30476. $list_options = false;
  30477. if ($this->config->get('preferred_state') == 'stable') {
  30478. $list_options = true;
  30479. }
  30480. $chan = $reg->getChannel($channel);
  30481. if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  30482. return $e;
  30483. }
  30484. if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  30485. $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
  30486. // use faster list-all if available
  30487. $rest = &$this->config->getREST('1.1', array());
  30488. $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName());
  30489. } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  30490. $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  30491. $rest = &$this->config->getREST('1.0', array());
  30492. $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName());
  30493. }
  30494. if (PEAR::isError($available)) {
  30495. $this->config->set('default_channel', $savechannel);
  30496. return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")');
  30497. }
  30498. $data = array(
  30499. 'caption' => 'All packages [Channel ' . $channel . ']:',
  30500. 'border' => true,
  30501. 'headline' => array('Package', 'Latest', 'Local'),
  30502. 'channel' => $channel,
  30503. );
  30504. if (isset($options['channelinfo'])) {
  30505. // add full channelinfo
  30506. $data['caption'] = 'Channel ' . $channel . ' All packages:';
  30507. $data['headline'] = array('Channel', 'Package', 'Latest', 'Local',
  30508. 'Description', 'Dependencies');
  30509. }
  30510. $local_pkgs = $reg->listPackages($channel);
  30511. foreach ($available as $name => $info) {
  30512. $installed = $reg->packageInfo($name, null, $channel);
  30513. if ($installed && is_array($installed['version'])) {
  30514. $installed['version'] = $installed['version']['release'];
  30515. }
  30516. $desc = $info['summary'];
  30517. if (isset($params[$name])) {
  30518. $desc .= "\n\n".$info['description'];
  30519. }
  30520. if (isset($options['mode']))
  30521. {
  30522. if ($options['mode'] == 'installed' && !isset($installed['version'])) {
  30523. continue;
  30524. }
  30525. if ($options['mode'] == 'notinstalled' && isset($installed['version'])) {
  30526. continue;
  30527. }
  30528. if ($options['mode'] == 'upgrades'
  30529. && (!isset($installed['version']) || version_compare($installed['version'],
  30530. $info['stable'], '>='))) {
  30531. continue;
  30532. }
  30533. }
  30534. $pos = array_search(strtolower($name), $local_pkgs);
  30535. if ($pos !== false) {
  30536. unset($local_pkgs[$pos]);
  30537. }
  30538. if (isset($info['stable']) && !$info['stable']) {
  30539. $info['stable'] = null;
  30540. }
  30541. if (isset($options['channelinfo'])) {
  30542. // add full channelinfo
  30543. if ($info['stable'] === $info['unstable']) {
  30544. $state = $info['state'];
  30545. } else {
  30546. $state = 'stable';
  30547. }
  30548. $latest = $info['stable'].' ('.$state.')';
  30549. $local = '';
  30550. if (isset($installed['version'])) {
  30551. $inst_state = $reg->packageInfo($name, 'release_state', $channel);
  30552. $local = $installed['version'].' ('.$inst_state.')';
  30553. }
  30554. $packageinfo = array(
  30555. $channel,
  30556. $name,
  30557. $latest,
  30558. $local,
  30559. isset($desc) ? $desc : null,
  30560. isset($info['deps']) ? $info['deps'] : null,
  30561. );
  30562. } else {
  30563. $packageinfo = array(
  30564. $reg->channelAlias($channel) . '/' . $name,
  30565. isset($info['stable']) ? $info['stable'] : null,
  30566. isset($installed['version']) ? $installed['version'] : null,
  30567. isset($desc) ? $desc : null,
  30568. isset($info['deps']) ? $info['deps'] : null,
  30569. );
  30570. }
  30571. $data['data'][$info['category']][] = $packageinfo;
  30572. }
  30573. if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) {
  30574. $this->config->set('default_channel', $savechannel);
  30575. $this->ui->outputData($data, $command);
  30576. return true;
  30577. }
  30578. foreach ($local_pkgs as $name) {
  30579. $info = &$reg->getPackage($name, $channel);
  30580. $data['data']['Local'][] = array(
  30581. $reg->channelAlias($channel) . '/' . $info->getPackage(),
  30582. '',
  30583. $info->getVersion(),
  30584. $info->getSummary(),
  30585. $info->getDeps()
  30586. );
  30587. }
  30588. $this->config->set('default_channel', $savechannel);
  30589. $this->ui->outputData($data, $command);
  30590. return true;
  30591. }
  30592. function doSearch($command, $options, $params)
  30593. {
  30594. if ((!isset($params[0]) || empty($params[0]))
  30595. && (!isset($params[1]) || empty($params[1])))
  30596. {
  30597. return $this->raiseError('no valid search string supplied');
  30598. }
  30599. $channelinfo = isset($options['channelinfo']);
  30600. $reg = &$this->config->getRegistry();
  30601. if (isset($options['allchannels'])) {
  30602. // search all channels
  30603. unset($options['allchannels']);
  30604. $channels = $reg->getChannels();
  30605. $errors = array();
  30606. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  30607. foreach ($channels as $channel) {
  30608. if ($channel->getName() != '__uri') {
  30609. $options['channel'] = $channel->getName();
  30610. $ret = $this->doSearch($command, $options, $params);
  30611. if (PEAR::isError($ret)) {
  30612. $errors[] = $ret;
  30613. }
  30614. }
  30615. }
  30616. PEAR::staticPopErrorHandling();
  30617. if (count($errors) !== 0) {
  30618. // for now, only give first error
  30619. return PEAR::raiseError($errors[0]);
  30620. }
  30621. return true;
  30622. }
  30623. $savechannel = $channel = $this->config->get('default_channel');
  30624. $package = strtolower($params[0]);
  30625. $summary = isset($params[1]) ? $params[1] : false;
  30626. if (isset($options['channel'])) {
  30627. $reg = &$this->config->getRegistry();
  30628. $channel = $options['channel'];
  30629. if (!$reg->channelExists($channel)) {
  30630. return $this->raiseError('Channel "' . $channel . '" does not exist');
  30631. }
  30632. $this->config->set('default_channel', $channel);
  30633. }
  30634. $chan = $reg->getChannel($channel);
  30635. if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  30636. return $e;
  30637. }
  30638. if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  30639. $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  30640. $rest = &$this->config->getREST('1.0', array());
  30641. $available = $rest->listAll($base, false, false, $package, $summary, $chan->getName());
  30642. }
  30643. if (PEAR::isError($available)) {
  30644. $this->config->set('default_channel', $savechannel);
  30645. return $this->raiseError($available);
  30646. }
  30647. if (!$available && !$channelinfo) {
  30648. // clean exit when not found, no error !
  30649. $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.';
  30650. $this->ui->outputData($data);
  30651. $this->config->set('default_channel', $channel);
  30652. return true;
  30653. }
  30654. if ($channelinfo) {
  30655. $data = array(
  30656. 'caption' => 'Matched packages, channel ' . $channel . ':',
  30657. 'border' => true,
  30658. 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'),
  30659. 'channel' => $channel
  30660. );
  30661. } else {
  30662. $data = array(
  30663. 'caption' => 'Matched packages, channel ' . $channel . ':',
  30664. 'border' => true,
  30665. 'headline' => array('Package', 'Stable/(Latest)', 'Local'),
  30666. 'channel' => $channel
  30667. );
  30668. }
  30669. if (!$available && $channelinfo) {
  30670. unset($data['headline']);
  30671. $data['data'] = 'No packages found that match pattern "' . $package . '".';
  30672. $available = array();
  30673. }
  30674. foreach ($available as $name => $info) {
  30675. $installed = $reg->packageInfo($name, null, $channel);
  30676. $desc = $info['summary'];
  30677. if (isset($params[$name]))
  30678. $desc .= "\n\n".$info['description'];
  30679. if (!isset($info['stable']) || !$info['stable']) {
  30680. $version_remote = 'none';
  30681. } else {
  30682. if ($info['unstable']) {
  30683. $version_remote = $info['unstable'];
  30684. } else {
  30685. $version_remote = $info['stable'];
  30686. }
  30687. $version_remote .= ' ('.$info['state'].')';
  30688. }
  30689. $version = is_array($installed['version']) ? $installed['version']['release'] :
  30690. $installed['version'];
  30691. if ($channelinfo) {
  30692. $packageinfo = array(
  30693. $channel,
  30694. $name,
  30695. $version_remote,
  30696. $version,
  30697. $desc,
  30698. );
  30699. } else {
  30700. $packageinfo = array(
  30701. $name,
  30702. $version_remote,
  30703. $version,
  30704. $desc,
  30705. );
  30706. }
  30707. $data['data'][$info['category']][] = $packageinfo;
  30708. }
  30709. $this->ui->outputData($data, $command);
  30710. $this->config->set('default_channel', $channel);
  30711. return true;
  30712. }
  30713. function &getDownloader($options)
  30714. {
  30715. if (!class_exists('PEAR_Downloader')) {
  30716. require_once 'PEAR/Downloader.php';
  30717. }
  30718. $a = new PEAR_Downloader($this->ui, $options, $this->config);
  30719. return $a;
  30720. }
  30721. function doDownload($command, $options, $params)
  30722. {
  30723. // make certain that dependencies are ignored
  30724. $options['downloadonly'] = 1;
  30725. // eliminate error messages for preferred_state-related errors
  30726. /* TODO: Should be an option, but until now download does respect
  30727. preferred state */
  30728. /* $options['ignorepreferred_state'] = 1; */
  30729. // eliminate error messages for preferred_state-related errors
  30730. $downloader = &$this->getDownloader($options);
  30731. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  30732. $e = $downloader->setDownloadDir(getcwd());
  30733. PEAR::staticPopErrorHandling();
  30734. if (PEAR::isError($e)) {
  30735. return $this->raiseError('Current directory is not writeable, cannot download');
  30736. }
  30737. $errors = array();
  30738. $downloaded = array();
  30739. $err = $downloader->download($params);
  30740. if (PEAR::isError($err)) {
  30741. return $err;
  30742. }
  30743. $errors = $downloader->getErrorMsgs();
  30744. if (count($errors)) {
  30745. foreach ($errors as $error) {
  30746. if ($error !== null) {
  30747. $this->ui->outputData($error);
  30748. }
  30749. }
  30750. return $this->raiseError("$command failed");
  30751. }
  30752. $downloaded = $downloader->getDownloadedPackages();
  30753. foreach ($downloaded as $pkg) {
  30754. $this->ui->outputData("File $pkg[file] downloaded", $command);
  30755. }
  30756. return true;
  30757. }
  30758. function downloadCallback($msg, $params = null)
  30759. {
  30760. if ($msg == 'done') {
  30761. $this->bytes_downloaded = $params;
  30762. }
  30763. }
  30764. function doListUpgrades($command, $options, $params)
  30765. {
  30766. require_once 'PEAR/Common.php';
  30767. if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) {
  30768. return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"');
  30769. }
  30770. $savechannel = $channel = $this->config->get('default_channel');
  30771. $reg = &$this->config->getRegistry();
  30772. foreach ($reg->listChannels() as $channel) {
  30773. $inst = array_flip($reg->listPackages($channel));
  30774. if (!count($inst)) {
  30775. continue;
  30776. }
  30777. if ($channel == '__uri') {
  30778. continue;
  30779. }
  30780. $this->config->set('default_channel', $channel);
  30781. $state = empty($params[0]) ? $this->config->get('preferred_state') : $params[0];
  30782. $caption = $channel . ' Available Upgrades';
  30783. $chan = $reg->getChannel($channel);
  30784. if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
  30785. return $e;
  30786. }
  30787. $latest = array();
  30788. $base2 = false;
  30789. $preferred_mirror = $this->config->get('preferred_mirror');
  30790. if ($chan->supportsREST($preferred_mirror) &&
  30791. (
  30792. ($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror))
  30793. || ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
  30794. )
  30795. ) {
  30796. if ($base2) {
  30797. $rest = &$this->config->getREST('1.3', array());
  30798. $base = $base2;
  30799. } else {
  30800. $rest = &$this->config->getREST('1.0', array());
  30801. }
  30802. if (empty($state) || $state == 'any') {
  30803. $state = false;
  30804. } else {
  30805. $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
  30806. }
  30807. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  30808. $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg);
  30809. PEAR::staticPopErrorHandling();
  30810. }
  30811. if (PEAR::isError($latest)) {
  30812. $this->ui->outputData($latest->getMessage());
  30813. continue;
  30814. }
  30815. $caption .= ':';
  30816. if (PEAR::isError($latest)) {
  30817. $this->config->set('default_channel', $savechannel);
  30818. return $latest;
  30819. }
  30820. $data = array(
  30821. 'caption' => $caption,
  30822. 'border' => 1,
  30823. 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'),
  30824. 'channel' => $channel
  30825. );
  30826. foreach ((array)$latest as $pkg => $info) {
  30827. $package = strtolower($pkg);
  30828. if (!isset($inst[$package])) {
  30829. // skip packages we don't have installed
  30830. continue;
  30831. }
  30832. extract($info);
  30833. $inst_version = $reg->packageInfo($package, 'version', $channel);
  30834. $inst_state = $reg->packageInfo($package, 'release_state', $channel);
  30835. if (version_compare("$version", "$inst_version", "le")) {
  30836. // installed version is up-to-date
  30837. continue;
  30838. }
  30839. if ($filesize >= 20480) {
  30840. $filesize += 1024 - ($filesize % 1024);
  30841. $fs = sprintf("%dkB", $filesize / 1024);
  30842. } elseif ($filesize > 0) {
  30843. $filesize += 103 - ($filesize % 103);
  30844. $fs = sprintf("%.1fkB", $filesize / 1024.0);
  30845. } else {
  30846. $fs = " -"; // XXX center instead
  30847. }
  30848. $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs);
  30849. }
  30850. if (isset($options['channelinfo'])) {
  30851. if (empty($data['data'])) {
  30852. unset($data['headline']);
  30853. if (count($inst) == 0) {
  30854. $data['data'] = '(no packages installed)';
  30855. } else {
  30856. $data['data'] = '(no upgrades available)';
  30857. }
  30858. }
  30859. $this->ui->outputData($data, $command);
  30860. } else {
  30861. if (empty($data['data'])) {
  30862. $this->ui->outputData('Channel ' . $channel . ': No upgrades available');
  30863. } else {
  30864. $this->ui->outputData($data, $command);
  30865. }
  30866. }
  30867. }
  30868. $this->config->set('default_channel', $savechannel);
  30869. return true;
  30870. }
  30871. function doClearCache($command, $options, $params)
  30872. {
  30873. $cache_dir = $this->config->get('cache_dir');
  30874. $verbose = $this->config->get('verbose');
  30875. $output = '';
  30876. if (!file_exists($cache_dir) || !is_dir($cache_dir)) {
  30877. return $this->raiseError("$cache_dir does not exist or is not a directory");
  30878. }
  30879. if (!($dp = @opendir($cache_dir))) {
  30880. return $this->raiseError("opendir($cache_dir) failed: $php_errormsg");
  30881. }
  30882. if ($verbose >= 1) {
  30883. $output .= "reading directory $cache_dir\n";
  30884. }
  30885. $num = 0;
  30886. while ($ent = readdir($dp)) {
  30887. if (preg_match('/rest.cache(file|id)\\z/', $ent)) {
  30888. $path = $cache_dir . DIRECTORY_SEPARATOR . $ent;
  30889. if (file_exists($path)) {
  30890. $ok = @unlink($path);
  30891. } else {
  30892. $ok = false;
  30893. $php_errormsg = '';
  30894. }
  30895. if ($ok) {
  30896. if ($verbose >= 2) {
  30897. $output .= "deleted $path\n";
  30898. }
  30899. $num++;
  30900. } elseif ($verbose >= 1) {
  30901. $output .= "failed to delete $path $php_errormsg\n";
  30902. }
  30903. }
  30904. }
  30905. closedir($dp);
  30906. if ($verbose >= 1) {
  30907. $output .= "$num cache entries cleared\n";
  30908. }
  30909. $this->ui->outputData(rtrim($output), $command);
  30910. return $num;
  30911. }
  30912. }
  30913. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Test.xml������������������������������������������������������������������0000644�0001750�0001750�00000003151�13565304531�016024� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<commands version="1.0">
  30914. <run-tests>
  30915. <summary>Run Regression Tests</summary>
  30916. <function>doRunTests</function>
  30917. <shortcut>rt</shortcut>
  30918. <options>
  30919. <recur>
  30920. <shortopt>r</shortopt>
  30921. <doc>Run tests in child directories, recursively. 4 dirs deep maximum</doc>
  30922. </recur>
  30923. <ini>
  30924. <shortopt>i</shortopt>
  30925. <doc>actual string of settings to pass to php in format &quot; -d setting=blah&quot;</doc>
  30926. <arg>SETTINGS</arg>
  30927. </ini>
  30928. <realtimelog>
  30929. <shortopt>l</shortopt>
  30930. <doc>Log test runs/results as they are run</doc>
  30931. </realtimelog>
  30932. <quiet>
  30933. <shortopt>q</shortopt>
  30934. <doc>Only display detail for failed tests</doc>
  30935. </quiet>
  30936. <simple>
  30937. <shortopt>s</shortopt>
  30938. <doc>Display simple output for all tests</doc>
  30939. </simple>
  30940. <package>
  30941. <shortopt>p</shortopt>
  30942. <doc>Treat parameters as installed packages from which to run tests</doc>
  30943. </package>
  30944. <phpunit>
  30945. <shortopt>u</shortopt>
  30946. <doc>Search parameters for AllTests.php, and use that to run phpunit-based tests
  30947. If none is found, all .phpt tests will be tried instead.</doc>
  30948. </phpunit>
  30949. <tapoutput>
  30950. <shortopt>t</shortopt>
  30951. <doc>Output run-tests.log in TAP-compliant format</doc>
  30952. </tapoutput>
  30953. <cgi>
  30954. <shortopt>c</shortopt>
  30955. <doc>CGI php executable (needed for tests with POST/GET section)</doc>
  30956. <arg>PHPCGI</arg>
  30957. </cgi>
  30958. <coverage>
  30959. <shortopt>x</shortopt>
  30960. <doc>Generate a code coverage report (requires Xdebug 2.0.0+)</doc>
  30961. </coverage>
  30962. </options>
  30963. <doc>[testfile|dir ...]
  30964. Run regression tests with PHP&#039;s regression testing script (run-tests.php).</doc>
  30965. </run-tests>
  30966. </commands>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command/Test.php������������������������������������������������������������������0000644�0001750�0001750�00000027550�13565304531�016024� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  30967. /**
  30968. * PEAR_Command_Test (run-tests)
  30969. *
  30970. * PHP versions 4 and 5
  30971. *
  30972. * @category pear
  30973. * @package PEAR
  30974. * @author Stig Bakken <ssb@php.net>
  30975. * @author Martin Jansen <mj@php.net>
  30976. * @author Greg Beaver <cellog@php.net>
  30977. * @copyright 1997-2009 The Authors
  30978. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  30979. * @link http://pear.php.net/package/PEAR
  30980. * @since File available since Release 0.1
  30981. */
  30982. /**
  30983. * base class
  30984. */
  30985. require_once 'PEAR/Command/Common.php';
  30986. /**
  30987. * PEAR commands for login/logout
  30988. *
  30989. * @category pear
  30990. * @package PEAR
  30991. * @author Stig Bakken <ssb@php.net>
  30992. * @author Martin Jansen <mj@php.net>
  30993. * @author Greg Beaver <cellog@php.net>
  30994. * @copyright 1997-2009 The Authors
  30995. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  30996. * @version Release: 1.10.10
  30997. * @link http://pear.php.net/package/PEAR
  30998. * @since Class available since Release 0.1
  30999. */
  31000. class PEAR_Command_Test extends PEAR_Command_Common
  31001. {
  31002. var $commands = array(
  31003. 'run-tests' => array(
  31004. 'summary' => 'Run Regression Tests',
  31005. 'function' => 'doRunTests',
  31006. 'shortcut' => 'rt',
  31007. 'options' => array(
  31008. 'recur' => array(
  31009. 'shortopt' => 'r',
  31010. 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum',
  31011. ),
  31012. 'ini' => array(
  31013. 'shortopt' => 'i',
  31014. 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"',
  31015. 'arg' => 'SETTINGS'
  31016. ),
  31017. 'realtimelog' => array(
  31018. 'shortopt' => 'l',
  31019. 'doc' => 'Log test runs/results as they are run',
  31020. ),
  31021. 'quiet' => array(
  31022. 'shortopt' => 'q',
  31023. 'doc' => 'Only display detail for failed tests',
  31024. ),
  31025. 'simple' => array(
  31026. 'shortopt' => 's',
  31027. 'doc' => 'Display simple output for all tests',
  31028. ),
  31029. 'package' => array(
  31030. 'shortopt' => 'p',
  31031. 'doc' => 'Treat parameters as installed packages from which to run tests',
  31032. ),
  31033. 'phpunit' => array(
  31034. 'shortopt' => 'u',
  31035. 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests
  31036. If none is found, all .phpt tests will be tried instead.',
  31037. ),
  31038. 'tapoutput' => array(
  31039. 'shortopt' => 't',
  31040. 'doc' => 'Output run-tests.log in TAP-compliant format',
  31041. ),
  31042. 'cgi' => array(
  31043. 'shortopt' => 'c',
  31044. 'doc' => 'CGI php executable (needed for tests with POST/GET section)',
  31045. 'arg' => 'PHPCGI',
  31046. ),
  31047. 'coverage' => array(
  31048. 'shortopt' => 'x',
  31049. 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)',
  31050. ),
  31051. 'showdiff' => array(
  31052. 'shortopt' => 'd',
  31053. 'doc' => 'Output diff on test failure',
  31054. ),
  31055. ),
  31056. 'doc' => '[testfile|dir ...]
  31057. Run regression tests with PHP\'s regression testing script (run-tests.php).',
  31058. ),
  31059. );
  31060. var $output;
  31061. /**
  31062. * PEAR_Command_Test constructor.
  31063. *
  31064. * @access public
  31065. */
  31066. function __construct(&$ui, &$config)
  31067. {
  31068. parent::__construct($ui, $config);
  31069. }
  31070. function doRunTests($command, $options, $params)
  31071. {
  31072. if (isset($options['phpunit']) && isset($options['tapoutput'])) {
  31073. return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time');
  31074. }
  31075. require_once 'PEAR/Common.php';
  31076. require_once 'System.php';
  31077. $log = new PEAR_Common;
  31078. $log->ui = &$this->ui; // slightly hacky, but it will work
  31079. $tests = array();
  31080. $depth = isset($options['recur']) ? 14 : 1;
  31081. if (!count($params)) {
  31082. $params[] = '.';
  31083. }
  31084. if (isset($options['package'])) {
  31085. $oldparams = $params;
  31086. $params = array();
  31087. $reg = &$this->config->getRegistry();
  31088. foreach ($oldparams as $param) {
  31089. $pname = $reg->parsePackageName($param, $this->config->get('default_channel'));
  31090. if (PEAR::isError($pname)) {
  31091. return $this->raiseError($pname);
  31092. }
  31093. $package = &$reg->getPackage($pname['package'], $pname['channel']);
  31094. if (!$package) {
  31095. return PEAR::raiseError('Unknown package "' .
  31096. $reg->parsedPackageNameToString($pname) . '"');
  31097. }
  31098. $filelist = $package->getFilelist();
  31099. foreach ($filelist as $name => $atts) {
  31100. if (isset($atts['role']) && $atts['role'] != 'test') {
  31101. continue;
  31102. }
  31103. if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) {
  31104. $params[] = $atts['installed_as'];
  31105. continue;
  31106. } elseif (!preg_match('/\.phpt\\z/', $name)) {
  31107. continue;
  31108. }
  31109. $params[] = $atts['installed_as'];
  31110. }
  31111. }
  31112. }
  31113. foreach ($params as $p) {
  31114. if (is_dir($p)) {
  31115. if (isset($options['phpunit'])) {
  31116. $dir = System::find(array($p, '-type', 'f',
  31117. '-maxdepth', $depth,
  31118. '-name', 'AllTests.php'));
  31119. if (count($dir)) {
  31120. foreach ($dir as $p) {
  31121. $p = realpath($p);
  31122. if (!count($tests) ||
  31123. (count($tests) && strlen($p) < strlen($tests[0]))) {
  31124. // this is in a higher-level directory, use this one instead.
  31125. $tests = array($p);
  31126. }
  31127. }
  31128. }
  31129. continue;
  31130. }
  31131. $args = array($p, '-type', 'f', '-name', '*.phpt');
  31132. } else {
  31133. if (isset($options['phpunit'])) {
  31134. if (preg_match('/AllTests\.php\\z/i', $p)) {
  31135. $p = realpath($p);
  31136. if (!count($tests) ||
  31137. (count($tests) && strlen($p) < strlen($tests[0]))) {
  31138. // this is in a higher-level directory, use this one instead.
  31139. $tests = array($p);
  31140. }
  31141. }
  31142. continue;
  31143. }
  31144. if (file_exists($p) && preg_match('/\.phpt$/', $p)) {
  31145. $tests[] = $p;
  31146. continue;
  31147. }
  31148. if (!preg_match('/\.phpt\\z/', $p)) {
  31149. $p .= '.phpt';
  31150. }
  31151. $args = array(dirname($p), '-type', 'f', '-name', $p);
  31152. }
  31153. if (!isset($options['recur'])) {
  31154. $args[] = '-maxdepth';
  31155. $args[] = 1;
  31156. }
  31157. $dir = System::find($args);
  31158. $tests = array_merge($tests, $dir);
  31159. }
  31160. $ini_settings = '';
  31161. if (isset($options['ini'])) {
  31162. $ini_settings .= $options['ini'];
  31163. }
  31164. if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) {
  31165. $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}";
  31166. }
  31167. if ($ini_settings) {
  31168. $this->ui->outputData('Using INI settings: "' . $ini_settings . '"');
  31169. }
  31170. $skipped = $passed = $failed = array();
  31171. $tests_count = count($tests);
  31172. $this->ui->outputData('Running ' . $tests_count . ' tests', $command);
  31173. $start = time();
  31174. if (isset($options['realtimelog']) && file_exists('run-tests.log')) {
  31175. unlink('run-tests.log');
  31176. }
  31177. if (isset($options['tapoutput'])) {
  31178. $tap = '1..' . $tests_count . "\n";
  31179. }
  31180. require_once 'PEAR/RunTest.php';
  31181. $run = new PEAR_RunTest($log, $options);
  31182. $run->tests_count = $tests_count;
  31183. if (isset($options['coverage']) && extension_loaded('xdebug')){
  31184. $run->xdebug_loaded = true;
  31185. } else {
  31186. $run->xdebug_loaded = false;
  31187. }
  31188. $j = $i = 1;
  31189. foreach ($tests as $t) {
  31190. if (isset($options['realtimelog'])) {
  31191. $fp = @fopen('run-tests.log', 'a');
  31192. if ($fp) {
  31193. fwrite($fp, "Running test [$i / $tests_count] $t...");
  31194. fclose($fp);
  31195. }
  31196. }
  31197. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  31198. if (isset($options['phpunit'])) {
  31199. $result = $run->runPHPUnit($t, $ini_settings);
  31200. } else {
  31201. $result = $run->run($t, $ini_settings, $j);
  31202. }
  31203. PEAR::staticPopErrorHandling();
  31204. if (PEAR::isError($result)) {
  31205. $this->ui->log($result->getMessage());
  31206. continue;
  31207. }
  31208. if (isset($options['tapoutput'])) {
  31209. $tap .= $result[0] . ' ' . $i . $result[1] . "\n";
  31210. continue;
  31211. }
  31212. if (isset($options['realtimelog'])) {
  31213. $fp = @fopen('run-tests.log', 'a');
  31214. if ($fp) {
  31215. fwrite($fp, "$result\n");
  31216. fclose($fp);
  31217. }
  31218. }
  31219. if ($result == 'FAILED') {
  31220. $failed[] = $t;
  31221. }
  31222. if ($result == 'PASSED') {
  31223. $passed[] = $t;
  31224. }
  31225. if ($result == 'SKIPPED') {
  31226. $skipped[] = $t;
  31227. }
  31228. $j++;
  31229. }
  31230. $total = date('i:s', time() - $start);
  31231. if (isset($options['tapoutput'])) {
  31232. $fp = @fopen('run-tests.log', 'w');
  31233. if ($fp) {
  31234. fwrite($fp, $tap, strlen($tap));
  31235. fclose($fp);
  31236. $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') .
  31237. '"', $command);
  31238. }
  31239. } else {
  31240. if (count($failed)) {
  31241. $output = "TOTAL TIME: $total\n";
  31242. $output .= count($passed) . " PASSED TESTS\n";
  31243. $output .= count($skipped) . " SKIPPED TESTS\n";
  31244. $output .= count($failed) . " FAILED TESTS:\n";
  31245. foreach ($failed as $failure) {
  31246. $output .= $failure . "\n";
  31247. }
  31248. $mode = isset($options['realtimelog']) ? 'a' : 'w';
  31249. $fp = @fopen('run-tests.log', $mode);
  31250. if ($fp) {
  31251. fwrite($fp, $output, strlen($output));
  31252. fclose($fp);
  31253. $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command);
  31254. }
  31255. } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) {
  31256. @unlink('run-tests.log');
  31257. }
  31258. }
  31259. $this->ui->outputData('TOTAL TIME: ' . $total);
  31260. $this->ui->outputData(count($passed) . ' PASSED TESTS', $command);
  31261. $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command);
  31262. if (count($failed)) {
  31263. $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command);
  31264. foreach ($failed as $failure) {
  31265. $this->ui->outputData($failure, $command);
  31266. }
  31267. }
  31268. if (count($failed) == 0) {
  31269. return true;
  31270. }
  31271. return $this->raiseError('Some tests failed');
  31272. }
  31273. }
  31274. ��������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Downloader/Package.php������������������������������������������������������������0000644�0001750�0001750�00000224657�13565304531�017167� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  31275. /**
  31276. * PEAR_Downloader_Package
  31277. *
  31278. * PHP versions 4 and 5
  31279. *
  31280. * @category pear
  31281. * @package PEAR
  31282. * @author Greg Beaver <cellog@php.net>
  31283. * @copyright 1997-2009 The Authors
  31284. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  31285. * @link http://pear.php.net/package/PEAR
  31286. * @since File available since Release 1.4.0a1
  31287. */
  31288. /**
  31289. * Error code when parameter initialization fails because no releases
  31290. * exist within preferred_state, but releases do exist
  31291. */
  31292. define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  31293. /**
  31294. * Error code when parameter initialization fails because no releases
  31295. * exist that will work with the existing PHP version
  31296. */
  31297. define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
  31298. /**
  31299. * Coordinates download parameters and manages their dependencies
  31300. * prior to downloading them.
  31301. *
  31302. * Input can come from three sources:
  31303. *
  31304. * - local files (archives or package.xml)
  31305. * - remote files (downloadable urls)
  31306. * - abstract package names
  31307. *
  31308. * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  31309. * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  31310. * format returned of dependencies is slightly different from that used in package.xml.
  31311. *
  31312. * This class hides the differences between these elements, and makes automatic
  31313. * dependency resolution a piece of cake. It also manages conflicts when
  31314. * two classes depend on incompatible dependencies, or differing versions of the same
  31315. * package dependency. In addition, download will not be attempted if the php version is
  31316. * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  31317. * installed.
  31318. * @category pear
  31319. * @package PEAR
  31320. * @author Greg Beaver <cellog@php.net>
  31321. * @copyright 1997-2009 The Authors
  31322. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  31323. * @version Release: 1.10.10
  31324. * @link http://pear.php.net/package/PEAR
  31325. * @since Class available since Release 1.4.0a1
  31326. */
  31327. class PEAR_Downloader_Package
  31328. {
  31329. /**
  31330. * @var PEAR_Downloader
  31331. */
  31332. var $_downloader;
  31333. /**
  31334. * @var PEAR_Config
  31335. */
  31336. var $_config;
  31337. /**
  31338. * @var PEAR_Registry
  31339. */
  31340. var $_registry;
  31341. /**
  31342. * Used to implement packagingroot properly
  31343. * @var PEAR_Registry
  31344. */
  31345. var $_installRegistry;
  31346. /**
  31347. * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  31348. */
  31349. var $_packagefile;
  31350. /**
  31351. * @var array
  31352. */
  31353. var $_parsedname;
  31354. /**
  31355. * @var array
  31356. */
  31357. var $_downloadURL;
  31358. /**
  31359. * @var array
  31360. */
  31361. var $_downloadDeps = array();
  31362. /**
  31363. * @var boolean
  31364. */
  31365. var $_valid = false;
  31366. /**
  31367. * @var boolean
  31368. */
  31369. var $_analyzed = false;
  31370. /**
  31371. * if this or a parent package was invoked with Package-state, this is set to the
  31372. * state variable.
  31373. *
  31374. * This allows temporary reassignment of preferred_state for a parent package and all of
  31375. * its dependencies.
  31376. * @var string|false
  31377. */
  31378. var $_explicitState = false;
  31379. /**
  31380. * If this package is invoked with Package#group, this variable will be true
  31381. */
  31382. var $_explicitGroup = false;
  31383. /**
  31384. * Package type local|url
  31385. * @var string
  31386. */
  31387. var $_type;
  31388. /**
  31389. * Contents of package.xml, if downloaded from a remote channel
  31390. * @var string|false
  31391. * @access private
  31392. */
  31393. var $_rawpackagefile;
  31394. /**
  31395. * @var boolean
  31396. * @access private
  31397. */
  31398. var $_validated = false;
  31399. /**
  31400. * @param PEAR_Downloader
  31401. */
  31402. function __construct(&$downloader)
  31403. {
  31404. $this->_downloader = &$downloader;
  31405. $this->_config = &$this->_downloader->config;
  31406. $this->_registry = &$this->_config->getRegistry();
  31407. $options = $downloader->getOptions();
  31408. if (isset($options['packagingroot'])) {
  31409. $this->_config->setInstallRoot($options['packagingroot']);
  31410. $this->_installRegistry = &$this->_config->getRegistry();
  31411. $this->_config->setInstallRoot(false);
  31412. } else {
  31413. $this->_installRegistry = &$this->_registry;
  31414. }
  31415. $this->_valid = $this->_analyzed = false;
  31416. }
  31417. /**
  31418. * Parse the input and determine whether this is a local file, a remote uri, or an
  31419. * abstract package name.
  31420. *
  31421. * This is the heart of the PEAR_Downloader_Package(), and is used in
  31422. * {@link PEAR_Downloader::download()}
  31423. * @param string
  31424. * @return bool|PEAR_Error
  31425. */
  31426. function initialize($param)
  31427. {
  31428. $origErr = $this->_fromFile($param);
  31429. if ($this->_valid) {
  31430. return true;
  31431. }
  31432. $options = $this->_downloader->getOptions();
  31433. if (isset($options['offline'])) {
  31434. if (PEAR::isError($origErr) && !isset($options['soft'])) {
  31435. foreach ($origErr->getUserInfo() as $userInfo) {
  31436. if (isset($userInfo['message'])) {
  31437. $this->_downloader->log(0, $userInfo['message']);
  31438. }
  31439. }
  31440. $this->_downloader->log(0, $origErr->getMessage());
  31441. }
  31442. return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
  31443. }
  31444. $err = $this->_fromUrl($param);
  31445. if (PEAR::isError($err) || !$this->_valid) {
  31446. if ($this->_type == 'url') {
  31447. if (PEAR::isError($err) && !isset($options['soft'])) {
  31448. $this->_downloader->log(0, $err->getMessage());
  31449. }
  31450. return PEAR::raiseError("Invalid or missing remote package file");
  31451. }
  31452. $err = $this->_fromString($param);
  31453. if (PEAR::isError($err) || !$this->_valid) {
  31454. if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
  31455. return false; // instruct the downloader to silently skip
  31456. }
  31457. if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) {
  31458. if (is_array($origErr->getUserInfo())) {
  31459. foreach ($origErr->getUserInfo() as $err) {
  31460. if (is_array($err)) {
  31461. $err = $err['message'];
  31462. }
  31463. if (!isset($options['soft'])) {
  31464. $this->_downloader->log(0, $err);
  31465. }
  31466. }
  31467. }
  31468. if (!isset($options['soft'])) {
  31469. $this->_downloader->log(0, $origErr->getMessage());
  31470. }
  31471. if (is_array($param)) {
  31472. $param = $this->_registry->parsedPackageNameToString($param, true);
  31473. }
  31474. if (!isset($options['soft'])) {
  31475. $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
  31476. }
  31477. // Passing no message back - already logged above
  31478. return PEAR::raiseError();
  31479. }
  31480. if (PEAR::isError($err) && !isset($options['soft'])) {
  31481. $this->_downloader->log(0, $err->getMessage());
  31482. }
  31483. if (is_array($param)) {
  31484. $param = $this->_registry->parsedPackageNameToString($param, true);
  31485. }
  31486. if (!isset($options['soft'])) {
  31487. $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
  31488. }
  31489. // Passing no message back - already logged above
  31490. return PEAR::raiseError();
  31491. }
  31492. }
  31493. return true;
  31494. }
  31495. /**
  31496. * Retrieve any non-local packages
  31497. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
  31498. */
  31499. function &download()
  31500. {
  31501. if (isset($this->_packagefile)) {
  31502. return $this->_packagefile;
  31503. }
  31504. if (isset($this->_downloadURL['url'])) {
  31505. $this->_isvalid = false;
  31506. $info = $this->getParsedPackage();
  31507. foreach ($info as $i => $p) {
  31508. $info[$i] = strtolower($p);
  31509. }
  31510. $err = $this->_fromUrl($this->_downloadURL['url'],
  31511. $this->_registry->parsedPackageNameToString($this->_parsedname, true));
  31512. $newinfo = $this->getParsedPackage();
  31513. foreach ($newinfo as $i => $p) {
  31514. $newinfo[$i] = strtolower($p);
  31515. }
  31516. if ($info != $newinfo) {
  31517. do {
  31518. if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') {
  31519. $info['channel'] = 'pear.php.net';
  31520. if ($info == $newinfo) {
  31521. // skip the channel check if a pecl package says it's a PEAR package
  31522. break;
  31523. }
  31524. }
  31525. if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') {
  31526. $info['channel'] = 'pecl.php.net';
  31527. if ($info == $newinfo) {
  31528. // skip the channel check if a pecl package says it's a PEAR package
  31529. break;
  31530. }
  31531. }
  31532. return PEAR::raiseError('CRITICAL ERROR: We are ' .
  31533. $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
  31534. 'downloaded claims to be ' .
  31535. $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
  31536. } while (false);
  31537. }
  31538. if (PEAR::isError($err) || !$this->_valid) {
  31539. return $err;
  31540. }
  31541. }
  31542. $this->_type = 'local';
  31543. return $this->_packagefile;
  31544. }
  31545. function &getPackageFile()
  31546. {
  31547. return $this->_packagefile;
  31548. }
  31549. function &getDownloader()
  31550. {
  31551. return $this->_downloader;
  31552. }
  31553. function getType()
  31554. {
  31555. return $this->_type;
  31556. }
  31557. /**
  31558. * Like {@link initialize()}, but operates on a dependency
  31559. */
  31560. function fromDepURL($dep)
  31561. {
  31562. $this->_downloadURL = $dep;
  31563. if (isset($dep['uri'])) {
  31564. $options = $this->_downloader->getOptions();
  31565. if (!extension_loaded("zlib") || isset($options['nocompress'])) {
  31566. $ext = '.tar';
  31567. } else {
  31568. $ext = '.tgz';
  31569. }
  31570. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  31571. $err = $this->_fromUrl($dep['uri'] . $ext);
  31572. PEAR::popErrorHandling();
  31573. if (PEAR::isError($err)) {
  31574. if (!isset($options['soft'])) {
  31575. $this->_downloader->log(0, $err->getMessage());
  31576. }
  31577. return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
  31578. 'cannot download');
  31579. }
  31580. } else {
  31581. $this->_parsedname =
  31582. array(
  31583. 'package' => $dep['info']->getPackage(),
  31584. 'channel' => $dep['info']->getChannel(),
  31585. 'version' => $dep['version']
  31586. );
  31587. if (!isset($dep['nodefault'])) {
  31588. $this->_parsedname['group'] = 'default'; // download the default dependency group
  31589. $this->_explicitGroup = false;
  31590. }
  31591. $this->_rawpackagefile = $dep['raw'];
  31592. }
  31593. }
  31594. function detectDependencies($params)
  31595. {
  31596. $options = $this->_downloader->getOptions();
  31597. if (isset($options['downloadonly'])) {
  31598. return;
  31599. }
  31600. if (isset($options['offline'])) {
  31601. $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
  31602. return;
  31603. }
  31604. $pname = $this->getParsedPackage();
  31605. if (!$pname) {
  31606. return;
  31607. }
  31608. $deps = $this->getDeps();
  31609. if (!$deps) {
  31610. return;
  31611. }
  31612. if (isset($deps['required'])) { // package.xml 2.0
  31613. return $this->_detect2($deps, $pname, $options, $params);
  31614. }
  31615. return $this->_detect1($deps, $pname, $options, $params);
  31616. }
  31617. function setValidated()
  31618. {
  31619. $this->_validated = true;
  31620. }
  31621. function alreadyValidated()
  31622. {
  31623. return $this->_validated;
  31624. }
  31625. /**
  31626. * Remove packages to be downloaded that are already installed
  31627. * @param array of PEAR_Downloader_Package objects
  31628. */
  31629. public static function removeInstalled(&$params)
  31630. {
  31631. if (!isset($params[0])) {
  31632. return;
  31633. }
  31634. $options = $params[0]->_downloader->getOptions();
  31635. if (!isset($options['downloadonly'])) {
  31636. foreach ($params as $i => $param) {
  31637. $package = $param->getPackage();
  31638. $channel = $param->getChannel();
  31639. // remove self if already installed with this version
  31640. // this does not need any pecl magic - we only remove exact matches
  31641. if ($param->_installRegistry->packageExists($package, $channel)) {
  31642. $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel);
  31643. if (version_compare($packageVersion, $param->getVersion(), '==')) {
  31644. if (!isset($options['force']) && !isset($options['packagingroot'])) {
  31645. $info = $param->getParsedPackage();
  31646. unset($info['version']);
  31647. unset($info['state']);
  31648. if (!isset($options['soft'])) {
  31649. $param->_downloader->log(1, 'Skipping package "' .
  31650. $param->getShortName() .
  31651. '", already installed as version ' . $packageVersion);
  31652. }
  31653. $params[$i] = false;
  31654. }
  31655. } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
  31656. !isset($options['soft']) && !isset($options['packagingroot'])) {
  31657. $info = $param->getParsedPackage();
  31658. $param->_downloader->log(1, 'Skipping package "' .
  31659. $param->getShortName() .
  31660. '", already installed as version ' . $packageVersion);
  31661. $params[$i] = false;
  31662. }
  31663. }
  31664. }
  31665. }
  31666. PEAR_Downloader_Package::removeDuplicates($params);
  31667. }
  31668. function _detect2($deps, $pname, $options, $params)
  31669. {
  31670. $this->_downloadDeps = array();
  31671. $groupnotfound = false;
  31672. foreach (array('package', 'subpackage') as $packagetype) {
  31673. // get required dependency group
  31674. if (isset($deps['required'][$packagetype])) {
  31675. if (isset($deps['required'][$packagetype][0])) {
  31676. foreach ($deps['required'][$packagetype] as $dep) {
  31677. if (isset($dep['conflicts'])) {
  31678. // skip any package that this package conflicts with
  31679. continue;
  31680. }
  31681. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  31682. if (is_array($ret)) {
  31683. $this->_downloadDeps[] = $ret;
  31684. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  31685. $this->_downloader->log(0, $ret->getMessage());
  31686. }
  31687. }
  31688. } else {
  31689. $dep = $deps['required'][$packagetype];
  31690. if (!isset($dep['conflicts'])) {
  31691. // skip any package that this package conflicts with
  31692. $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  31693. if (is_array($ret)) {
  31694. $this->_downloadDeps[] = $ret;
  31695. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  31696. $this->_downloader->log(0, $ret->getMessage());
  31697. }
  31698. }
  31699. }
  31700. }
  31701. // get optional dependency group, if any
  31702. if (isset($deps['optional'][$packagetype])) {
  31703. $skipnames = array();
  31704. if (!isset($deps['optional'][$packagetype][0])) {
  31705. $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
  31706. }
  31707. foreach ($deps['optional'][$packagetype] as $dep) {
  31708. $skip = false;
  31709. if (!isset($options['alldeps'])) {
  31710. $dep['package'] = $dep['name'];
  31711. if (!isset($options['soft'])) {
  31712. $this->_downloader->log(3, 'Notice: package "' .
  31713. $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
  31714. true) . '" optional dependency "' .
  31715. $this->_registry->parsedPackageNameToString(array('package' =>
  31716. $dep['name'], 'channel' => 'pear.php.net'), true) .
  31717. '" will not be automatically downloaded');
  31718. }
  31719. $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
  31720. $skip = true;
  31721. unset($dep['package']);
  31722. }
  31723. $ret = $this->_detect2Dep($dep, $pname, 'optional', $params);
  31724. if (PEAR::isError($ret) && !isset($options['soft'])) {
  31725. $this->_downloader->log(0, $ret->getMessage());
  31726. }
  31727. if (!$ret) {
  31728. $dep['package'] = $dep['name'];
  31729. $skip = count($skipnames) ?
  31730. $skipnames[count($skipnames) - 1] : '';
  31731. if ($skip ==
  31732. $this->_registry->parsedPackageNameToString($dep, true)) {
  31733. array_pop($skipnames);
  31734. }
  31735. }
  31736. if (!$skip && is_array($ret)) {
  31737. $this->_downloadDeps[] = $ret;
  31738. }
  31739. }
  31740. if (count($skipnames)) {
  31741. if (!isset($options['soft'])) {
  31742. $this->_downloader->log(1, 'Did not download optional dependencies: ' .
  31743. implode(', ', $skipnames) .
  31744. ', use --alldeps to download automatically');
  31745. }
  31746. }
  31747. }
  31748. // get requested dependency group, if any
  31749. $groupname = $this->getGroup();
  31750. $explicit = $this->_explicitGroup;
  31751. if (!$groupname) {
  31752. if (!$this->canDefault()) {
  31753. continue;
  31754. }
  31755. $groupname = 'default'; // try the default dependency group
  31756. }
  31757. if ($groupnotfound) {
  31758. continue;
  31759. }
  31760. if (isset($deps['group'])) {
  31761. if (isset($deps['group']['attribs'])) {
  31762. if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
  31763. $group = $deps['group'];
  31764. } elseif ($explicit) {
  31765. if (!isset($options['soft'])) {
  31766. $this->_downloader->log(0, 'Warning: package "' .
  31767. $this->_registry->parsedPackageNameToString($pname, true) .
  31768. '" has no dependency ' . 'group named "' . $groupname . '"');
  31769. }
  31770. $groupnotfound = true;
  31771. continue;
  31772. }
  31773. } else {
  31774. $found = false;
  31775. foreach ($deps['group'] as $group) {
  31776. if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
  31777. $found = true;
  31778. break;
  31779. }
  31780. }
  31781. if (!$found) {
  31782. if ($explicit) {
  31783. if (!isset($options['soft'])) {
  31784. $this->_downloader->log(0, 'Warning: package "' .
  31785. $this->_registry->parsedPackageNameToString($pname, true) .
  31786. '" has no dependency ' . 'group named "' . $groupname . '"');
  31787. }
  31788. }
  31789. $groupnotfound = true;
  31790. continue;
  31791. }
  31792. }
  31793. }
  31794. if (isset($group) && isset($group[$packagetype])) {
  31795. if (isset($group[$packagetype][0])) {
  31796. foreach ($group[$packagetype] as $dep) {
  31797. $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
  31798. $group['attribs']['name'] . '"', $params);
  31799. if (is_array($ret)) {
  31800. $this->_downloadDeps[] = $ret;
  31801. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  31802. $this->_downloader->log(0, $ret->getMessage());
  31803. }
  31804. }
  31805. } else {
  31806. $ret = $this->_detect2Dep($group[$packagetype], $pname,
  31807. 'dependency group "' .
  31808. $group['attribs']['name'] . '"', $params);
  31809. if (is_array($ret)) {
  31810. $this->_downloadDeps[] = $ret;
  31811. } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
  31812. $this->_downloader->log(0, $ret->getMessage());
  31813. }
  31814. }
  31815. }
  31816. }
  31817. }
  31818. function _detect2Dep($dep, $pname, $group, $params)
  31819. {
  31820. if (isset($dep['conflicts'])) {
  31821. return true;
  31822. }
  31823. $options = $this->_downloader->getOptions();
  31824. if (isset($dep['uri'])) {
  31825. return array('uri' => $dep['uri'], 'dep' => $dep);;
  31826. }
  31827. $testdep = $dep;
  31828. $testdep['package'] = $dep['name'];
  31829. if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
  31830. $dep['package'] = $dep['name'];
  31831. if (!isset($options['soft'])) {
  31832. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
  31833. ' dependency "' .
  31834. $this->_registry->parsedPackageNameToString($dep, true) .
  31835. '", will be installed');
  31836. }
  31837. return false;
  31838. }
  31839. $options = $this->_downloader->getOptions();
  31840. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  31841. if ($this->_explicitState) {
  31842. $pname['state'] = $this->_explicitState;
  31843. }
  31844. $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  31845. if (PEAR::isError($url)) {
  31846. PEAR::popErrorHandling();
  31847. return $url;
  31848. }
  31849. $dep['package'] = $dep['name'];
  31850. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
  31851. !isset($options['alldeps']), true);
  31852. PEAR::popErrorHandling();
  31853. if (PEAR::isError($ret)) {
  31854. if (!isset($options['soft'])) {
  31855. $this->_downloader->log(0, $ret->getMessage());
  31856. }
  31857. return false;
  31858. }
  31859. // check to see if a dep is already installed and is the same or newer
  31860. if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
  31861. $oper = 'has';
  31862. } else {
  31863. $oper = 'gt';
  31864. }
  31865. // do not try to move this before getDepPackageDownloadURL
  31866. // we can't determine whether upgrade is necessary until we know what
  31867. // version would be downloaded
  31868. if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
  31869. $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']);
  31870. $dep['package'] = $dep['name'];
  31871. if (!isset($options['soft'])) {
  31872. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  31873. ' dependency "' .
  31874. $this->_registry->parsedPackageNameToString($dep, true) .
  31875. '" version ' . $url['version'] . ', already installed as version ' .
  31876. $version);
  31877. }
  31878. return false;
  31879. }
  31880. if (isset($dep['nodefault'])) {
  31881. $ret['nodefault'] = true;
  31882. }
  31883. return $ret;
  31884. }
  31885. function _detect1($deps, $pname, $options, $params)
  31886. {
  31887. $this->_downloadDeps = array();
  31888. $skipnames = array();
  31889. foreach ($deps as $dep) {
  31890. $nodownload = false;
  31891. if (isset ($dep['type']) && $dep['type'] === 'pkg') {
  31892. $dep['channel'] = 'pear.php.net';
  31893. $dep['package'] = $dep['name'];
  31894. switch ($dep['rel']) {
  31895. case 'not' :
  31896. continue 2;
  31897. case 'ge' :
  31898. case 'eq' :
  31899. case 'gt' :
  31900. case 'has' :
  31901. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  31902. 'required' :
  31903. 'optional';
  31904. if (PEAR_Downloader_Package::willDownload($dep, $params)) {
  31905. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  31906. . ' dependency "' .
  31907. $this->_registry->parsedPackageNameToString($dep, true) .
  31908. '", will be installed');
  31909. continue 2;
  31910. }
  31911. $fakedp = new PEAR_PackageFile_v1;
  31912. $fakedp->setPackage($dep['name']);
  31913. // skip internet check if we are not upgrading (bug #5810)
  31914. if (!isset($options['upgrade']) && $this->isInstalled(
  31915. $fakedp, $dep['rel'])) {
  31916. $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  31917. . ' dependency "' .
  31918. $this->_registry->parsedPackageNameToString($dep, true) .
  31919. '", is already installed');
  31920. continue 2;
  31921. }
  31922. }
  31923. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  31924. if ($this->_explicitState) {
  31925. $pname['state'] = $this->_explicitState;
  31926. }
  31927. $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  31928. $chan = 'pear.php.net';
  31929. if (PEAR::isError($url)) {
  31930. // check to see if this is a pecl package that has jumped
  31931. // from pear.php.net to pecl.php.net channel
  31932. if (!class_exists('PEAR_Dependency2')) {
  31933. require_once 'PEAR/Dependency2.php';
  31934. }
  31935. $newdep = PEAR_Dependency2::normalizeDep($dep);
  31936. $newdep = $newdep[0];
  31937. $newdep['channel'] = 'pecl.php.net';
  31938. $chan = 'pecl.php.net';
  31939. $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
  31940. $obj = &$this->_installRegistry->getPackage($dep['name']);
  31941. if (PEAR::isError($url)) {
  31942. PEAR::popErrorHandling();
  31943. if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
  31944. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  31945. 'required' :
  31946. 'optional';
  31947. $dep['package'] = $dep['name'];
  31948. if (!isset($options['soft'])) {
  31949. $this->_downloader->log(3, $this->getShortName() .
  31950. ': Skipping ' . $group . ' dependency "' .
  31951. $this->_registry->parsedPackageNameToString($dep, true) .
  31952. '", already installed as version ' . $obj->getVersion());
  31953. }
  31954. $skip = count($skipnames) ?
  31955. $skipnames[count($skipnames) - 1] : '';
  31956. if ($skip ==
  31957. $this->_registry->parsedPackageNameToString($dep, true)) {
  31958. array_pop($skipnames);
  31959. }
  31960. continue;
  31961. } else {
  31962. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  31963. $this->_downloader->log(2, $this->getShortName() .
  31964. ': Skipping optional dependency "' .
  31965. $this->_registry->parsedPackageNameToString($dep, true) .
  31966. '", no releases exist');
  31967. continue;
  31968. } else {
  31969. return $url;
  31970. }
  31971. }
  31972. }
  31973. }
  31974. PEAR::popErrorHandling();
  31975. if (!isset($options['alldeps'])) {
  31976. if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  31977. if (!isset($options['soft'])) {
  31978. $this->_downloader->log(3, 'Notice: package "' .
  31979. $this->getShortName() .
  31980. '" optional dependency "' .
  31981. $this->_registry->parsedPackageNameToString(
  31982. array('channel' => $chan, 'package' =>
  31983. $dep['name']), true) .
  31984. '" will not be automatically downloaded');
  31985. }
  31986. $skipnames[] = $this->_registry->parsedPackageNameToString(
  31987. array('channel' => $chan, 'package' =>
  31988. $dep['name']), true);
  31989. $nodownload = true;
  31990. }
  31991. }
  31992. if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
  31993. if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  31994. if (!isset($options['soft'])) {
  31995. $this->_downloader->log(3, 'Notice: package "' .
  31996. $this->getShortName() .
  31997. '" required dependency "' .
  31998. $this->_registry->parsedPackageNameToString(
  31999. array('channel' => $chan, 'package' =>
  32000. $dep['name']), true) .
  32001. '" will not be automatically downloaded');
  32002. }
  32003. $skipnames[] = $this->_registry->parsedPackageNameToString(
  32004. array('channel' => $chan, 'package' =>
  32005. $dep['name']), true);
  32006. $nodownload = true;
  32007. }
  32008. }
  32009. // check to see if a dep is already installed
  32010. // do not try to move this before getDepPackageDownloadURL
  32011. // we can't determine whether upgrade is necessary until we know what
  32012. // version would be downloaded
  32013. if (!isset($options['force']) && $this->isInstalled(
  32014. $url, $dep['rel'])) {
  32015. $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  32016. 'required' :
  32017. 'optional';
  32018. $dep['package'] = $dep['name'];
  32019. if (isset($newdep)) {
  32020. $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']);
  32021. } else {
  32022. $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
  32023. }
  32024. $dep['version'] = $url['version'];
  32025. if (!isset($options['soft'])) {
  32026. $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  32027. ' dependency "' .
  32028. $this->_registry->parsedPackageNameToString($dep, true) .
  32029. '", already installed as version ' . $version);
  32030. }
  32031. $skip = count($skipnames) ?
  32032. $skipnames[count($skipnames) - 1] : '';
  32033. if ($skip ==
  32034. $this->_registry->parsedPackageNameToString($dep, true)) {
  32035. array_pop($skipnames);
  32036. }
  32037. continue;
  32038. }
  32039. if ($nodownload) {
  32040. continue;
  32041. }
  32042. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32043. if (isset($newdep)) {
  32044. $dep = $newdep;
  32045. }
  32046. $dep['package'] = $dep['name'];
  32047. $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
  32048. isset($dep['optional']) && $dep['optional'] == 'yes' &&
  32049. !isset($options['alldeps']), true);
  32050. PEAR::popErrorHandling();
  32051. if (PEAR::isError($ret)) {
  32052. if (!isset($options['soft'])) {
  32053. $this->_downloader->log(0, $ret->getMessage());
  32054. }
  32055. continue;
  32056. }
  32057. $this->_downloadDeps[] = $ret;
  32058. }
  32059. }
  32060. if (count($skipnames)) {
  32061. if (!isset($options['soft'])) {
  32062. $this->_downloader->log(1, 'Did not download dependencies: ' .
  32063. implode(', ', $skipnames) .
  32064. ', use --alldeps or --onlyreqdeps to download automatically');
  32065. }
  32066. }
  32067. }
  32068. function setDownloadURL($pkg)
  32069. {
  32070. $this->_downloadURL = $pkg;
  32071. }
  32072. /**
  32073. * Set the package.xml object for this downloaded package
  32074. *
  32075. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
  32076. */
  32077. function setPackageFile(&$pkg)
  32078. {
  32079. $this->_packagefile = &$pkg;
  32080. }
  32081. function getShortName()
  32082. {
  32083. return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
  32084. 'package' => $this->getPackage()), true);
  32085. }
  32086. function getParsedPackage()
  32087. {
  32088. if (isset($this->_packagefile) || isset($this->_parsedname)) {
  32089. return array('channel' => $this->getChannel(),
  32090. 'package' => $this->getPackage(),
  32091. 'version' => $this->getVersion());
  32092. }
  32093. return false;
  32094. }
  32095. function getDownloadURL()
  32096. {
  32097. return $this->_downloadURL;
  32098. }
  32099. function canDefault()
  32100. {
  32101. if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) {
  32102. return false;
  32103. }
  32104. return true;
  32105. }
  32106. function getPackage()
  32107. {
  32108. if (isset($this->_packagefile)) {
  32109. return $this->_packagefile->getPackage();
  32110. } elseif (isset($this->_downloadURL['info'])) {
  32111. return $this->_downloadURL['info']->getPackage();
  32112. }
  32113. return false;
  32114. }
  32115. /**
  32116. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  32117. */
  32118. function isSubpackage(&$pf)
  32119. {
  32120. if (isset($this->_packagefile)) {
  32121. return $this->_packagefile->isSubpackage($pf);
  32122. } elseif (isset($this->_downloadURL['info'])) {
  32123. return $this->_downloadURL['info']->isSubpackage($pf);
  32124. }
  32125. return false;
  32126. }
  32127. function getPackageType()
  32128. {
  32129. if (isset($this->_packagefile)) {
  32130. return $this->_packagefile->getPackageType();
  32131. } elseif (isset($this->_downloadURL['info'])) {
  32132. return $this->_downloadURL['info']->getPackageType();
  32133. }
  32134. return false;
  32135. }
  32136. function isBundle()
  32137. {
  32138. if (isset($this->_packagefile)) {
  32139. return $this->_packagefile->getPackageType() == 'bundle';
  32140. }
  32141. return false;
  32142. }
  32143. function getPackageXmlVersion()
  32144. {
  32145. if (isset($this->_packagefile)) {
  32146. return $this->_packagefile->getPackagexmlVersion();
  32147. } elseif (isset($this->_downloadURL['info'])) {
  32148. return $this->_downloadURL['info']->getPackagexmlVersion();
  32149. }
  32150. return '1.0';
  32151. }
  32152. function getChannel()
  32153. {
  32154. if (isset($this->_packagefile)) {
  32155. return $this->_packagefile->getChannel();
  32156. } elseif (isset($this->_downloadURL['info'])) {
  32157. return $this->_downloadURL['info']->getChannel();
  32158. }
  32159. return false;
  32160. }
  32161. function getURI()
  32162. {
  32163. if (isset($this->_packagefile)) {
  32164. return $this->_packagefile->getURI();
  32165. } elseif (isset($this->_downloadURL['info'])) {
  32166. return $this->_downloadURL['info']->getURI();
  32167. }
  32168. return false;
  32169. }
  32170. function getVersion()
  32171. {
  32172. if (isset($this->_packagefile)) {
  32173. return $this->_packagefile->getVersion();
  32174. } elseif (isset($this->_downloadURL['version'])) {
  32175. return $this->_downloadURL['version'];
  32176. }
  32177. return false;
  32178. }
  32179. function isCompatible($pf)
  32180. {
  32181. if (isset($this->_packagefile)) {
  32182. return $this->_packagefile->isCompatible($pf);
  32183. } elseif (isset($this->_downloadURL['info'])) {
  32184. return $this->_downloadURL['info']->isCompatible($pf);
  32185. }
  32186. return true;
  32187. }
  32188. function setGroup($group)
  32189. {
  32190. $this->_parsedname['group'] = $group;
  32191. }
  32192. function getGroup()
  32193. {
  32194. if (isset($this->_parsedname['group'])) {
  32195. return $this->_parsedname['group'];
  32196. }
  32197. return '';
  32198. }
  32199. function isExtension($name)
  32200. {
  32201. if (isset($this->_packagefile)) {
  32202. return $this->_packagefile->isExtension($name);
  32203. } elseif (isset($this->_downloadURL['info'])) {
  32204. if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
  32205. return $this->_downloadURL['info']->getProvidesExtension() == $name;
  32206. }
  32207. return false;
  32208. }
  32209. return false;
  32210. }
  32211. function getDeps()
  32212. {
  32213. if (isset($this->_packagefile)) {
  32214. $ver = $this->_packagefile->getPackagexmlVersion();
  32215. if (version_compare($ver, '2.0', '>=')) {
  32216. return $this->_packagefile->getDeps(true);
  32217. }
  32218. return $this->_packagefile->getDeps();
  32219. } elseif (isset($this->_downloadURL['info'])) {
  32220. $ver = $this->_downloadURL['info']->getPackagexmlVersion();
  32221. if (version_compare($ver, '2.0', '>=')) {
  32222. return $this->_downloadURL['info']->getDeps(true);
  32223. }
  32224. return $this->_downloadURL['info']->getDeps();
  32225. }
  32226. return array();
  32227. }
  32228. /**
  32229. * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
  32230. * returned from getDepDownloadURL()
  32231. */
  32232. function isEqual($param)
  32233. {
  32234. if (is_object($param)) {
  32235. $channel = $param->getChannel();
  32236. $package = $param->getPackage();
  32237. if ($param->getURI()) {
  32238. $param = array(
  32239. 'channel' => $param->getChannel(),
  32240. 'package' => $param->getPackage(),
  32241. 'version' => $param->getVersion(),
  32242. 'uri' => $param->getURI(),
  32243. );
  32244. } else {
  32245. $param = array(
  32246. 'channel' => $param->getChannel(),
  32247. 'package' => $param->getPackage(),
  32248. 'version' => $param->getVersion(),
  32249. );
  32250. }
  32251. } else {
  32252. if (isset($param['uri'])) {
  32253. if ($this->getChannel() != '__uri') {
  32254. return false;
  32255. }
  32256. return $param['uri'] == $this->getURI();
  32257. }
  32258. $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage();
  32259. $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel();
  32260. if (isset($param['rel'])) {
  32261. if (!class_exists('PEAR_Dependency2')) {
  32262. require_once 'PEAR/Dependency2.php';
  32263. }
  32264. $newdep = PEAR_Dependency2::normalizeDep($param);
  32265. $newdep = $newdep[0];
  32266. } elseif (isset($param['min'])) {
  32267. $newdep = $param;
  32268. }
  32269. }
  32270. if (isset($newdep)) {
  32271. if (!isset($newdep['min'])) {
  32272. $newdep['min'] = '0';
  32273. }
  32274. if (!isset($newdep['max'])) {
  32275. $newdep['max'] = '100000000000000000000';
  32276. }
  32277. // use magic to support pecl packages suddenly jumping to the pecl channel
  32278. // we need to support both dependency possibilities
  32279. if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
  32280. if ($package == $this->getPackage()) {
  32281. $channel = 'pecl.php.net';
  32282. }
  32283. }
  32284. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  32285. if ($package == $this->getPackage()) {
  32286. $channel = 'pear.php.net';
  32287. }
  32288. }
  32289. return (strtolower($package) == strtolower($this->getPackage()) &&
  32290. $channel == $this->getChannel() &&
  32291. version_compare($newdep['min'], $this->getVersion(), '<=') &&
  32292. version_compare($newdep['max'], $this->getVersion(), '>='));
  32293. }
  32294. // use magic to support pecl packages suddenly jumping to the pecl channel
  32295. if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  32296. if (strtolower($package) == strtolower($this->getPackage())) {
  32297. $channel = 'pear.php.net';
  32298. }
  32299. }
  32300. if (isset($param['version'])) {
  32301. return (strtolower($package) == strtolower($this->getPackage()) &&
  32302. $channel == $this->getChannel() &&
  32303. $param['version'] == $this->getVersion());
  32304. }
  32305. return strtolower($package) == strtolower($this->getPackage()) &&
  32306. $channel == $this->getChannel();
  32307. }
  32308. function isInstalled($dep, $oper = '==')
  32309. {
  32310. if (!$dep) {
  32311. return false;
  32312. }
  32313. if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
  32314. return false;
  32315. }
  32316. if (is_object($dep)) {
  32317. $package = $dep->getPackage();
  32318. $channel = $dep->getChannel();
  32319. if ($dep->getURI()) {
  32320. $dep = array(
  32321. 'uri' => $dep->getURI(),
  32322. 'version' => $dep->getVersion(),
  32323. );
  32324. } else {
  32325. $dep = array(
  32326. 'version' => $dep->getVersion(),
  32327. );
  32328. }
  32329. } else {
  32330. if (isset($dep['uri'])) {
  32331. $channel = '__uri';
  32332. $package = $dep['dep']['name'];
  32333. } else {
  32334. $channel = $dep['info']->getChannel();
  32335. $package = $dep['info']->getPackage();
  32336. }
  32337. }
  32338. $options = $this->_downloader->getOptions();
  32339. $test = $this->_installRegistry->packageExists($package, $channel);
  32340. if (!$test && $channel == 'pecl.php.net') {
  32341. // do magic to allow upgrading from old pecl packages to new ones
  32342. $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
  32343. $channel = 'pear.php.net';
  32344. }
  32345. if ($test) {
  32346. if (isset($dep['uri'])) {
  32347. if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
  32348. return true;
  32349. }
  32350. }
  32351. if (isset($options['upgrade'])) {
  32352. $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel);
  32353. if (version_compare($packageVersion, $dep['version'], '>=')) {
  32354. return true;
  32355. }
  32356. return false;
  32357. }
  32358. return true;
  32359. }
  32360. return false;
  32361. }
  32362. /**
  32363. * Detect duplicate package names with differing versions
  32364. *
  32365. * If a user requests to install Date 1.4.6 and Date 1.4.7,
  32366. * for instance, this is a logic error. This method
  32367. * detects this situation.
  32368. *
  32369. * @param array $params array of PEAR_Downloader_Package objects
  32370. * @param array $errorparams empty array
  32371. * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
  32372. */
  32373. public static function detectStupidDuplicates($params, &$errorparams)
  32374. {
  32375. $existing = array();
  32376. foreach ($params as $i => $param) {
  32377. $package = $param->getPackage();
  32378. $channel = $param->getChannel();
  32379. $group = $param->getGroup();
  32380. if (!isset($existing[$channel . '/' . $package])) {
  32381. $existing[$channel . '/' . $package] = array();
  32382. }
  32383. if (!isset($existing[$channel . '/' . $package][$group])) {
  32384. $existing[$channel . '/' . $package][$group] = array();
  32385. }
  32386. $existing[$channel . '/' . $package][$group][] = $i;
  32387. }
  32388. $indices = array();
  32389. foreach ($existing as $package => $groups) {
  32390. foreach ($groups as $group => $dupes) {
  32391. if (count($dupes) > 1) {
  32392. $indices = $indices + $dupes;
  32393. }
  32394. }
  32395. }
  32396. $indices = array_unique($indices);
  32397. foreach ($indices as $index) {
  32398. $errorparams[] = $params[$index];
  32399. }
  32400. return count($errorparams);
  32401. }
  32402. /**
  32403. * @param array
  32404. * @param bool ignore install groups - for final removal of dupe packages
  32405. */
  32406. public static function removeDuplicates(&$params, $ignoreGroups = false)
  32407. {
  32408. $pnames = array();
  32409. foreach ($params as $i => $param) {
  32410. if (!$param) {
  32411. continue;
  32412. }
  32413. if ($param->getPackage()) {
  32414. $group = $ignoreGroups ? '' : $param->getGroup();
  32415. $pnames[$i] = $param->getChannel() . '/' .
  32416. $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
  32417. }
  32418. }
  32419. $pnames = array_unique($pnames);
  32420. $unset = array_diff(array_keys($params), array_keys($pnames));
  32421. $testp = array_flip($pnames);
  32422. foreach ($params as $i => $param) {
  32423. if (!$param) {
  32424. $unset[] = $i;
  32425. continue;
  32426. }
  32427. if (!is_a($param, 'PEAR_Downloader_Package')) {
  32428. $unset[] = $i;
  32429. continue;
  32430. }
  32431. $group = $ignoreGroups ? '' : $param->getGroup();
  32432. if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
  32433. $param->getVersion() . '#' . $group])) {
  32434. $unset[] = $i;
  32435. }
  32436. }
  32437. foreach ($unset as $i) {
  32438. unset($params[$i]);
  32439. }
  32440. $ret = array();
  32441. foreach ($params as $i => $param) {
  32442. $ret[] = &$params[$i];
  32443. }
  32444. $params = array();
  32445. foreach ($ret as $i => $param) {
  32446. $params[] = &$ret[$i];
  32447. }
  32448. }
  32449. function explicitState()
  32450. {
  32451. return $this->_explicitState;
  32452. }
  32453. function setExplicitState($s)
  32454. {
  32455. $this->_explicitState = $s;
  32456. }
  32457. /**
  32458. */
  32459. public static function mergeDependencies(&$params)
  32460. {
  32461. $bundles = $newparams = array();
  32462. foreach ($params as $i => $param) {
  32463. if (!$param->isBundle()) {
  32464. continue;
  32465. }
  32466. $bundles[] = $i;
  32467. $pf = &$param->getPackageFile();
  32468. $newdeps = array();
  32469. $contents = $pf->getBundledPackages();
  32470. if (!is_array($contents)) {
  32471. $contents = array($contents);
  32472. }
  32473. foreach ($contents as $file) {
  32474. $filecontents = $pf->getFileContents($file);
  32475. $dl = &$param->getDownloader();
  32476. $options = $dl->getOptions();
  32477. if (PEAR::isError($dir = $dl->getDownloadDir())) {
  32478. return $dir;
  32479. }
  32480. $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
  32481. if (!$fp) {
  32482. continue;
  32483. }
  32484. // FIXME do symlink check
  32485. fwrite($fp, $filecontents, strlen($filecontents));
  32486. fclose($fp);
  32487. if ($s = $params[$i]->explicitState()) {
  32488. $obj->setExplicitState($s);
  32489. }
  32490. $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
  32491. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32492. if (PEAR::isError($dir = $dl->getDownloadDir())) {
  32493. PEAR::popErrorHandling();
  32494. return $dir;
  32495. }
  32496. $a = $dir . DIRECTORY_SEPARATOR . $file;
  32497. $e = $obj->_fromFile($a);
  32498. PEAR::popErrorHandling();
  32499. if (PEAR::isError($e)) {
  32500. if (!isset($options['soft'])) {
  32501. $dl->log(0, $e->getMessage());
  32502. }
  32503. continue;
  32504. }
  32505. if (!PEAR_Downloader_Package::willDownload($obj,
  32506. array_merge($params, $newparams)) && !$param->isInstalled($obj)) {
  32507. $newparams[] = $obj;
  32508. }
  32509. }
  32510. }
  32511. foreach ($bundles as $i) {
  32512. unset($params[$i]); // remove bundles - only their contents matter for installation
  32513. }
  32514. PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
  32515. if (count($newparams)) { // add in bundled packages for install
  32516. foreach ($newparams as $i => $unused) {
  32517. $params[] = &$newparams[$i];
  32518. }
  32519. $newparams = array();
  32520. }
  32521. foreach ($params as $i => $param) {
  32522. $newdeps = array();
  32523. foreach ($param->_downloadDeps as $dep) {
  32524. $merge = array_merge($params, $newparams);
  32525. if (!PEAR_Downloader_Package::willDownload($dep, $merge)
  32526. && !$param->isInstalled($dep)
  32527. ) {
  32528. $newdeps[] = $dep;
  32529. } else {
  32530. //var_dump($dep);
  32531. // detect versioning conflicts here
  32532. }
  32533. }
  32534. // convert the dependencies into PEAR_Downloader_Package objects for the next time around
  32535. $params[$i]->_downloadDeps = array();
  32536. foreach ($newdeps as $dep) {
  32537. $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
  32538. if ($s = $params[$i]->explicitState()) {
  32539. $obj->setExplicitState($s);
  32540. }
  32541. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32542. $e = $obj->fromDepURL($dep);
  32543. PEAR::popErrorHandling();
  32544. if (PEAR::isError($e)) {
  32545. if (!isset($options['soft'])) {
  32546. $obj->_downloader->log(0, $e->getMessage());
  32547. }
  32548. continue;
  32549. }
  32550. $e = $obj->detectDependencies($params);
  32551. if (PEAR::isError($e)) {
  32552. if (!isset($options['soft'])) {
  32553. $obj->_downloader->log(0, $e->getMessage());
  32554. }
  32555. }
  32556. $newparams[] = $obj;
  32557. }
  32558. }
  32559. if (count($newparams)) {
  32560. foreach ($newparams as $i => $unused) {
  32561. $params[] = &$newparams[$i];
  32562. }
  32563. return true;
  32564. }
  32565. return false;
  32566. }
  32567. /**
  32568. */
  32569. public static function willDownload($param, $params)
  32570. {
  32571. if (!is_array($params)) {
  32572. return false;
  32573. }
  32574. foreach ($params as $obj) {
  32575. if ($obj->isEqual($param)) {
  32576. return true;
  32577. }
  32578. }
  32579. return false;
  32580. }
  32581. /**
  32582. * For simpler unit-testing
  32583. * @param PEAR_Config
  32584. * @param int
  32585. * @param string
  32586. */
  32587. function &getPackagefileObject(&$c, $d)
  32588. {
  32589. $a = new PEAR_PackageFile($c, $d);
  32590. return $a;
  32591. }
  32592. /**
  32593. * This will retrieve from a local file if possible, and parse out
  32594. * a group name as well. The original parameter will be modified to reflect this.
  32595. * @param string|array can be a parsed package name as well
  32596. * @access private
  32597. */
  32598. function _fromFile(&$param)
  32599. {
  32600. $saveparam = $param;
  32601. if (is_string($param) && substr($param, 0, 10) !== 'channel://') {
  32602. if (!@file_exists($param)) {
  32603. $test = explode('#', $param);
  32604. $group = array_pop($test);
  32605. if (@file_exists(implode('#', $test))) {
  32606. $this->setGroup($group);
  32607. $param = implode('#', $test);
  32608. $this->_explicitGroup = true;
  32609. }
  32610. }
  32611. if (@is_file($param)) {
  32612. $this->_type = 'local';
  32613. $options = $this->_downloader->getOptions();
  32614. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug);
  32615. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32616. $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
  32617. PEAR::popErrorHandling();
  32618. if (PEAR::isError($pf)) {
  32619. $this->_valid = false;
  32620. $param = $saveparam;
  32621. return $pf;
  32622. }
  32623. $this->_packagefile = &$pf;
  32624. if (!$this->getGroup()) {
  32625. $this->setGroup('default'); // install the default dependency group
  32626. }
  32627. return $this->_valid = true;
  32628. }
  32629. }
  32630. $param = $saveparam;
  32631. return $this->_valid = false;
  32632. }
  32633. function _fromUrl($param, $saveparam = '')
  32634. {
  32635. if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) {
  32636. $options = $this->_downloader->getOptions();
  32637. $this->_type = 'url';
  32638. $callback = $this->_downloader->ui ?
  32639. array(&$this->_downloader, '_downloadCallback') : null;
  32640. $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
  32641. if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  32642. $this->_downloader->popErrorHandling();
  32643. return $dir;
  32644. }
  32645. $this->_downloader->log(3, 'Downloading "' . $param . '"');
  32646. $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
  32647. $dir, $callback, null, false, $this->getChannel());
  32648. $this->_downloader->popErrorHandling();
  32649. if (PEAR::isError($file)) {
  32650. if (!empty($saveparam)) {
  32651. $saveparam = ", cannot download \"$saveparam\"";
  32652. }
  32653. $err = PEAR::raiseError('Could not download from "' . $param .
  32654. '"' . $saveparam . ' (' . $file->getMessage() . ')');
  32655. return $err;
  32656. }
  32657. if ($this->_rawpackagefile) {
  32658. require_once 'Archive/Tar.php';
  32659. $tar = new Archive_Tar($file);
  32660. $packagexml = $tar->extractInString('package2.xml');
  32661. if (!$packagexml) {
  32662. $packagexml = $tar->extractInString('package.xml');
  32663. }
  32664. if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
  32665. str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
  32666. if ($this->getChannel() != 'pear.php.net') {
  32667. return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
  32668. 'not match value returned from xml-rpc');
  32669. }
  32670. // be more lax for the existing PEAR packages that have not-ok
  32671. // characters in their package.xml
  32672. $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
  32673. $this->getPackage() . '" package has invalid characters in its ' .
  32674. 'package.xml. The next version of PEAR may not be able to install ' .
  32675. 'this package for security reasons. Please open a bug report at ' .
  32676. 'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
  32677. }
  32678. }
  32679. // whew, download worked!
  32680. $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
  32681. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32682. $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
  32683. PEAR::popErrorHandling();
  32684. if (PEAR::isError($pf)) {
  32685. if (is_array($pf->getUserInfo())) {
  32686. foreach ($pf->getUserInfo() as $err) {
  32687. if (is_array($err)) {
  32688. $err = $err['message'];
  32689. }
  32690. if (!isset($options['soft'])) {
  32691. $this->_downloader->log(0, "Validation Error: $err");
  32692. }
  32693. }
  32694. }
  32695. if (!isset($options['soft'])) {
  32696. $this->_downloader->log(0, $pf->getMessage());
  32697. }
  32698. ///FIXME need to pass back some error code that we can use to match with to cancel all further operations
  32699. /// At least stop all deps of this package from being installed
  32700. $out = $saveparam ? $saveparam : $param;
  32701. $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive');
  32702. $this->_valid = false;
  32703. return $err;
  32704. }
  32705. $this->_packagefile = &$pf;
  32706. $this->setGroup('default'); // install the default dependency group
  32707. return $this->_valid = true;
  32708. }
  32709. return $this->_valid = false;
  32710. }
  32711. /**
  32712. *
  32713. * @param string|array pass in an array of format
  32714. * array(
  32715. * 'package' => 'pname',
  32716. * ['channel' => 'channame',]
  32717. * ['version' => 'version',]
  32718. * ['state' => 'state',])
  32719. * or a string of format [channame/]pname[-version|-state]
  32720. */
  32721. function _fromString($param)
  32722. {
  32723. $options = $this->_downloader->getOptions();
  32724. $channel = $this->_config->get('default_channel');
  32725. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32726. $pname = $this->_registry->parsePackageName($param, $channel);
  32727. PEAR::popErrorHandling();
  32728. if (PEAR::isError($pname)) {
  32729. if ($pname->getCode() == 'invalid') {
  32730. $this->_valid = false;
  32731. return false;
  32732. }
  32733. if ($pname->getCode() == 'channel') {
  32734. $parsed = $pname->getUserInfo();
  32735. if ($this->_downloader->discover($parsed['channel'])) {
  32736. if ($this->_config->get('auto_discover')) {
  32737. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  32738. $pname = $this->_registry->parsePackageName($param, $channel);
  32739. PEAR::popErrorHandling();
  32740. } else {
  32741. if (!isset($options['soft'])) {
  32742. $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
  32743. '" is not initialized, use ' .
  32744. '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
  32745. 'or pear config-set auto_discover 1');
  32746. }
  32747. }
  32748. }
  32749. if (PEAR::isError($pname)) {
  32750. if (!isset($options['soft'])) {
  32751. $this->_downloader->log(0, $pname->getMessage());
  32752. }
  32753. if (is_array($param)) {
  32754. $param = $this->_registry->parsedPackageNameToString($param);
  32755. }
  32756. $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
  32757. $this->_valid = false;
  32758. return $err;
  32759. }
  32760. } else {
  32761. if (!isset($options['soft'])) {
  32762. $this->_downloader->log(0, $pname->getMessage());
  32763. }
  32764. $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
  32765. $this->_valid = false;
  32766. return $err;
  32767. }
  32768. }
  32769. if (!isset($this->_type)) {
  32770. $this->_type = 'rest';
  32771. }
  32772. $this->_parsedname = $pname;
  32773. $this->_explicitState = isset($pname['state']) ? $pname['state'] : false;
  32774. $this->_explicitGroup = isset($pname['group']) ? true : false;
  32775. $info = $this->_downloader->_getPackageDownloadUrl($pname);
  32776. if (PEAR::isError($info)) {
  32777. if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
  32778. // try pecl
  32779. $pname['channel'] = 'pecl.php.net';
  32780. if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
  32781. if (!PEAR::isError($test)) {
  32782. $info = PEAR::raiseError($info->getMessage() . ' - package ' .
  32783. $this->_registry->parsedPackageNameToString($pname, true) .
  32784. ' can be installed with "pecl install ' . $pname['package'] .
  32785. '"');
  32786. } else {
  32787. $pname['channel'] = 'pear.php.net';
  32788. }
  32789. } else {
  32790. $pname['channel'] = 'pear.php.net';
  32791. }
  32792. }
  32793. return $info;
  32794. }
  32795. $this->_rawpackagefile = $info['raw'];
  32796. $ret = $this->_analyzeDownloadURL($info, $param, $pname);
  32797. if (PEAR::isError($ret)) {
  32798. return $ret;
  32799. }
  32800. if ($ret) {
  32801. $this->_downloadURL = $ret;
  32802. return $this->_valid = (bool) $ret;
  32803. }
  32804. }
  32805. /**
  32806. * @param array output of package.getDownloadURL
  32807. * @param string|array|object information for detecting packages to be downloaded, and
  32808. * for errors
  32809. * @param array name information of the package
  32810. * @param array|null packages to be downloaded
  32811. * @param bool is this an optional dependency?
  32812. * @param bool is this any kind of dependency?
  32813. * @access private
  32814. */
  32815. function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
  32816. $isdependency = false)
  32817. {
  32818. if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
  32819. return false;
  32820. }
  32821. if ($info === false) {
  32822. $saveparam = !is_string($param) ? ", cannot download \"$param\"" : '';
  32823. // no releases exist
  32824. return PEAR::raiseError('No releases for package "' .
  32825. $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
  32826. }
  32827. if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
  32828. $err = false;
  32829. if ($pname['channel'] == 'pecl.php.net') {
  32830. if ($info['info']->getChannel() != 'pear.php.net') {
  32831. $err = true;
  32832. }
  32833. } elseif ($info['info']->getChannel() == 'pecl.php.net') {
  32834. if ($pname['channel'] != 'pear.php.net') {
  32835. $err = true;
  32836. }
  32837. } else {
  32838. $err = true;
  32839. }
  32840. if ($err) {
  32841. return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
  32842. '" retrieved another channel\'s name for download! ("' .
  32843. $info['info']->getChannel() . '")');
  32844. }
  32845. }
  32846. $preferred_state = $this->_config->get('preferred_state');
  32847. if (!isset($info['url'])) {
  32848. $package_version = $this->_registry->packageInfo($info['info']->getPackage(),
  32849. 'version', $info['info']->getChannel());
  32850. if ($this->isInstalled($info)) {
  32851. if ($isdependency && version_compare($info['version'], $package_version, '<=')) {
  32852. // ignore bogus errors of "failed to download dependency"
  32853. // if it is already installed and the one that would be
  32854. // downloaded is older or the same version (Bug #7219)
  32855. return false;
  32856. }
  32857. }
  32858. if ($info['version'] === $package_version) {
  32859. if (!isset($options['soft'])) {
  32860. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  32861. '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' .
  32862. ' (' . $package_version . ') is the same as the locally installed one.');
  32863. }
  32864. return false;
  32865. }
  32866. if (version_compare($info['version'], $package_version, '<=')) {
  32867. if (!isset($options['soft'])) {
  32868. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  32869. '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' .
  32870. ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').');
  32871. }
  32872. return false;
  32873. }
  32874. $instead = ', will instead download version ' . $info['version'] .
  32875. ', stability "' . $info['info']->getState() . '"';
  32876. // releases exist, but we failed to get any
  32877. if (isset($this->_downloader->_options['force'])) {
  32878. if (isset($pname['version'])) {
  32879. $vs = ', version "' . $pname['version'] . '"';
  32880. } elseif (isset($pname['state'])) {
  32881. $vs = ', stability "' . $pname['state'] . '"';
  32882. } elseif ($param == 'dependency') {
  32883. if (!class_exists('PEAR_Common')) {
  32884. require_once 'PEAR/Common.php';
  32885. }
  32886. if (!in_array($info['info']->getState(),
  32887. PEAR_Common::betterStates($preferred_state, true))) {
  32888. if ($optional) {
  32889. // don't spit out confusing error message
  32890. return $this->_downloader->_getPackageDownloadUrl(
  32891. array('package' => $pname['package'],
  32892. 'channel' => $pname['channel'],
  32893. 'version' => $info['version']));
  32894. }
  32895. $vs = ' within preferred state "' . $preferred_state .
  32896. '"';
  32897. } else {
  32898. if (!class_exists('PEAR_Dependency2')) {
  32899. require_once 'PEAR/Dependency2.php';
  32900. }
  32901. if ($optional) {
  32902. // don't spit out confusing error message
  32903. return $this->_downloader->_getPackageDownloadUrl(
  32904. array('package' => $pname['package'],
  32905. 'channel' => $pname['channel'],
  32906. 'version' => $info['version']));
  32907. }
  32908. $vs = PEAR_Dependency2::_getExtraString($pname);
  32909. $instead = '';
  32910. }
  32911. } else {
  32912. $vs = ' within preferred state "' . $preferred_state . '"';
  32913. }
  32914. if (!isset($options['soft'])) {
  32915. $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  32916. '/' . $pname['package'] . $vs . $instead);
  32917. }
  32918. // download the latest release
  32919. return $this->_downloader->_getPackageDownloadUrl(
  32920. array('package' => $pname['package'],
  32921. 'channel' => $pname['channel'],
  32922. 'version' => $info['version']));
  32923. } else {
  32924. if (isset($info['php']) && $info['php']) {
  32925. $err = PEAR::raiseError('Failed to download ' .
  32926. $this->_registry->parsedPackageNameToString(
  32927. array('channel' => $pname['channel'],
  32928. 'package' => $pname['package']),
  32929. true) .
  32930. ', latest release is version ' . $info['php']['v'] .
  32931. ', but it requires PHP version "' .
  32932. $info['php']['m'] . '", use "' .
  32933. $this->_registry->parsedPackageNameToString(
  32934. array('channel' => $pname['channel'], 'package' => $pname['package'],
  32935. 'version' => $info['php']['v'])) . '" to install',
  32936. PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
  32937. return $err;
  32938. }
  32939. // construct helpful error message
  32940. if (isset($pname['version'])) {
  32941. $vs = ', version "' . $pname['version'] . '"';
  32942. } elseif (isset($pname['state'])) {
  32943. $vs = ', stability "' . $pname['state'] . '"';
  32944. } elseif ($param == 'dependency') {
  32945. if (!class_exists('PEAR_Common')) {
  32946. require_once 'PEAR/Common.php';
  32947. }
  32948. if (!in_array($info['info']->getState(),
  32949. PEAR_Common::betterStates($preferred_state, true))) {
  32950. if ($optional) {
  32951. // don't spit out confusing error message, and don't die on
  32952. // optional dep failure!
  32953. return $this->_downloader->_getPackageDownloadUrl(
  32954. array('package' => $pname['package'],
  32955. 'channel' => $pname['channel'],
  32956. 'version' => $info['version']));
  32957. }
  32958. $vs = ' within preferred state "' . $preferred_state . '"';
  32959. } else {
  32960. if (!class_exists('PEAR_Dependency2')) {
  32961. require_once 'PEAR/Dependency2.php';
  32962. }
  32963. if ($optional) {
  32964. // don't spit out confusing error message, and don't die on
  32965. // optional dep failure!
  32966. return $this->_downloader->_getPackageDownloadUrl(
  32967. array('package' => $pname['package'],
  32968. 'channel' => $pname['channel'],
  32969. 'version' => $info['version']));
  32970. }
  32971. $vs = PEAR_Dependency2::_getExtraString($pname);
  32972. }
  32973. } else {
  32974. $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
  32975. }
  32976. $options = $this->_downloader->getOptions();
  32977. // this is only set by the "download-all" command
  32978. if (isset($options['ignorepreferred_state'])) {
  32979. $err = PEAR::raiseError(
  32980. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  32981. array('channel' => $pname['channel'], 'package' => $pname['package']),
  32982. true)
  32983. . $vs .
  32984. ', latest release is version ' . $info['version'] .
  32985. ', stability "' . $info['info']->getState() . '", use "' .
  32986. $this->_registry->parsedPackageNameToString(
  32987. array('channel' => $pname['channel'], 'package' => $pname['package'],
  32988. 'version' => $info['version'])) . '" to install',
  32989. PEAR_DOWNLOADER_PACKAGE_STATE);
  32990. return $err;
  32991. }
  32992. // Checks if the user has a package installed already and checks the release against
  32993. // the state against the installed package, this allows upgrades for packages
  32994. // with lower stability than the preferred_state
  32995. $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']);
  32996. if (!$this->isInstalled($info)
  32997. || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true))
  32998. ) {
  32999. $err = PEAR::raiseError(
  33000. 'Failed to download ' . $this->_registry->parsedPackageNameToString(
  33001. array('channel' => $pname['channel'], 'package' => $pname['package']),
  33002. true)
  33003. . $vs .
  33004. ', latest release is version ' . $info['version'] .
  33005. ', stability "' . $info['info']->getState() . '", use "' .
  33006. $this->_registry->parsedPackageNameToString(
  33007. array('channel' => $pname['channel'], 'package' => $pname['package'],
  33008. 'version' => $info['version'])) . '" to install');
  33009. return $err;
  33010. }
  33011. }
  33012. }
  33013. if (isset($info['deprecated']) && $info['deprecated']) {
  33014. $this->_downloader->log(0,
  33015. 'WARNING: "' .
  33016. $this->_registry->parsedPackageNameToString(
  33017. array('channel' => $info['info']->getChannel(),
  33018. 'package' => $info['info']->getPackage()), true) .
  33019. '" is deprecated in favor of "' .
  33020. $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
  33021. '"');
  33022. }
  33023. return $info;
  33024. }
  33025. }
  33026. ���������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Frontend/CLI.php������������������������������������������������������������������0000644�0001750�0001750�00000062115�13565304531�015711� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  33027. /**
  33028. * PEAR_Frontend_CLI
  33029. *
  33030. * PHP versions 4 and 5
  33031. *
  33032. * @category pear
  33033. * @package PEAR
  33034. * @author Stig Bakken <ssb@php.net>
  33035. * @author Greg Beaver <cellog@php.net>
  33036. * @copyright 1997-2009 The Authors
  33037. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33038. * @link http://pear.php.net/package/PEAR
  33039. * @since File available since Release 0.1
  33040. */
  33041. /**
  33042. * base class
  33043. */
  33044. require_once 'PEAR/Frontend.php';
  33045. /**
  33046. * Command-line Frontend for the PEAR Installer
  33047. * @category pear
  33048. * @package PEAR
  33049. * @author Stig Bakken <ssb@php.net>
  33050. * @author Greg Beaver <cellog@php.net>
  33051. * @copyright 1997-2009 The Authors
  33052. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33053. * @version Release: 1.10.10
  33054. * @link http://pear.php.net/package/PEAR
  33055. * @since Class available since Release 0.1
  33056. */
  33057. class PEAR_Frontend_CLI extends PEAR_Frontend
  33058. {
  33059. /**
  33060. * What type of user interface this frontend is for.
  33061. * @var string
  33062. * @access public
  33063. */
  33064. var $type = 'CLI';
  33065. var $lp = ''; // line prefix
  33066. var $params = array();
  33067. var $term = array(
  33068. 'bold' => '',
  33069. 'normal' => '',
  33070. );
  33071. function __construct()
  33072. {
  33073. parent::__construct();
  33074. $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
  33075. if (function_exists('posix_isatty') && !posix_isatty(1)) {
  33076. // output is being redirected to a file or through a pipe
  33077. } elseif ($term) {
  33078. if (preg_match('/^(xterm|vt220|linux)/', $term)) {
  33079. $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109);
  33080. $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109);
  33081. } elseif (preg_match('/^vt100/', $term)) {
  33082. $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
  33083. $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
  33084. }
  33085. } elseif (OS_WINDOWS) {
  33086. // XXX add ANSI codes here
  33087. }
  33088. }
  33089. /**
  33090. * @param object PEAR_Error object
  33091. */
  33092. function displayError($e)
  33093. {
  33094. return $this->_displayLine($e->getMessage());
  33095. }
  33096. /**
  33097. * @param object PEAR_Error object
  33098. */
  33099. function displayFatalError($eobj)
  33100. {
  33101. $this->displayError($eobj);
  33102. if (class_exists('PEAR_Config')) {
  33103. $config = &PEAR_Config::singleton();
  33104. if ($config->get('verbose') > 5) {
  33105. if (function_exists('debug_print_backtrace')) {
  33106. debug_print_backtrace();
  33107. exit(1);
  33108. }
  33109. $raised = false;
  33110. foreach (debug_backtrace() as $i => $frame) {
  33111. if (!$raised) {
  33112. if (isset($frame['class'])
  33113. && strtolower($frame['class']) == 'pear'
  33114. && strtolower($frame['function']) == 'raiseerror'
  33115. ) {
  33116. $raised = true;
  33117. } else {
  33118. continue;
  33119. }
  33120. }
  33121. $frame['class'] = !isset($frame['class']) ? '' : $frame['class'];
  33122. $frame['type'] = !isset($frame['type']) ? '' : $frame['type'];
  33123. $frame['function'] = !isset($frame['function']) ? '' : $frame['function'];
  33124. $frame['line'] = !isset($frame['line']) ? '' : $frame['line'];
  33125. $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
  33126. }
  33127. }
  33128. }
  33129. exit(1);
  33130. }
  33131. /**
  33132. * Instruct the runInstallScript method to skip a paramgroup that matches the
  33133. * id value passed in.
  33134. *
  33135. * This method is useful for dynamically configuring which sections of a post-install script
  33136. * will be run based on the user's setup, which is very useful for making flexible
  33137. * post-install scripts without losing the cross-Frontend ability to retrieve user input
  33138. * @param string
  33139. */
  33140. function skipParamgroup($id)
  33141. {
  33142. $this->_skipSections[$id] = true;
  33143. }
  33144. function runPostinstallScripts(&$scripts)
  33145. {
  33146. foreach ($scripts as $i => $script) {
  33147. $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
  33148. }
  33149. }
  33150. /**
  33151. * @param array $xml contents of postinstallscript tag
  33152. * @param object $script post-installation script
  33153. * @param string install|upgrade
  33154. */
  33155. function runInstallScript($xml, &$script)
  33156. {
  33157. $this->_skipSections = array();
  33158. if (!is_array($xml) || !isset($xml['paramgroup'])) {
  33159. $script->run(array(), '_default');
  33160. return;
  33161. }
  33162. $completedPhases = array();
  33163. if (!isset($xml['paramgroup'][0])) {
  33164. $xml['paramgroup'] = array($xml['paramgroup']);
  33165. }
  33166. foreach ($xml['paramgroup'] as $group) {
  33167. if (isset($this->_skipSections[$group['id']])) {
  33168. // the post-install script chose to skip this section dynamically
  33169. continue;
  33170. }
  33171. if (isset($group['name'])) {
  33172. $paramname = explode('::', $group['name']);
  33173. if ($lastgroup['id'] != $paramname[0]) {
  33174. continue;
  33175. }
  33176. $group['name'] = $paramname[1];
  33177. if (!isset($answers)) {
  33178. return;
  33179. }
  33180. if (isset($answers[$group['name']])) {
  33181. switch ($group['conditiontype']) {
  33182. case '=' :
  33183. if ($answers[$group['name']] != $group['value']) {
  33184. continue 2;
  33185. }
  33186. break;
  33187. case '!=' :
  33188. if ($answers[$group['name']] == $group['value']) {
  33189. continue 2;
  33190. }
  33191. break;
  33192. case 'preg_match' :
  33193. if (!@preg_match('/' . $group['value'] . '/',
  33194. $answers[$group['name']])) {
  33195. continue 2;
  33196. }
  33197. break;
  33198. default :
  33199. return;
  33200. }
  33201. }
  33202. }
  33203. $lastgroup = $group;
  33204. if (isset($group['instructions'])) {
  33205. $this->_display($group['instructions']);
  33206. }
  33207. if (!isset($group['param'][0])) {
  33208. $group['param'] = array($group['param']);
  33209. }
  33210. if (isset($group['param'])) {
  33211. if (method_exists($script, 'postProcessPrompts')) {
  33212. $prompts = $script->postProcessPrompts($group['param'], $group['id']);
  33213. if (!is_array($prompts) || count($prompts) != count($group['param'])) {
  33214. $this->outputData('postinstall', 'Error: post-install script did not ' .
  33215. 'return proper post-processed prompts');
  33216. $prompts = $group['param'];
  33217. } else {
  33218. foreach ($prompts as $i => $var) {
  33219. if (!is_array($var) || !isset($var['prompt']) ||
  33220. !isset($var['name']) ||
  33221. ($var['name'] != $group['param'][$i]['name']) ||
  33222. ($var['type'] != $group['param'][$i]['type'])
  33223. ) {
  33224. $this->outputData('postinstall', 'Error: post-install script ' .
  33225. 'modified the variables or prompts, severe security risk. ' .
  33226. 'Will instead use the defaults from the package.xml');
  33227. $prompts = $group['param'];
  33228. }
  33229. }
  33230. }
  33231. $answers = $this->confirmDialog($prompts);
  33232. } else {
  33233. $answers = $this->confirmDialog($group['param']);
  33234. }
  33235. }
  33236. if ((isset($answers) && $answers) || !isset($group['param'])) {
  33237. if (!isset($answers)) {
  33238. $answers = array();
  33239. }
  33240. array_unshift($completedPhases, $group['id']);
  33241. if (!$script->run($answers, $group['id'])) {
  33242. $script->run($completedPhases, '_undoOnError');
  33243. return;
  33244. }
  33245. } else {
  33246. $script->run($completedPhases, '_undoOnError');
  33247. return;
  33248. }
  33249. }
  33250. }
  33251. /**
  33252. * Ask for user input, confirm the answers and continue until the user is satisfied
  33253. * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
  33254. * 'text to display', 'type' => 'string'[, default => 'default value'])
  33255. * @return array
  33256. */
  33257. function confirmDialog($params)
  33258. {
  33259. $answers = $prompts = $types = array();
  33260. foreach ($params as $param) {
  33261. $prompts[$param['name']] = $param['prompt'];
  33262. $types[$param['name']] = $param['type'];
  33263. $answers[$param['name']] = isset($param['default']) ? $param['default'] : '';
  33264. }
  33265. $tried = false;
  33266. do {
  33267. if ($tried) {
  33268. $i = 1;
  33269. foreach ($answers as $var => $value) {
  33270. if (!strlen($value)) {
  33271. echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
  33272. }
  33273. $i++;
  33274. }
  33275. }
  33276. $answers = $this->userDialog('', $prompts, $types, $answers);
  33277. $tried = true;
  33278. } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
  33279. return $answers;
  33280. }
  33281. function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20)
  33282. {
  33283. if (!is_array($prompts)) {
  33284. return array();
  33285. }
  33286. $testprompts = array_keys($prompts);
  33287. $result = $defaults;
  33288. reset($prompts);
  33289. if (count($prompts) === 1) {
  33290. foreach ($prompts as $key => $prompt) {
  33291. $type = $types[$key];
  33292. $default = @$defaults[$key];
  33293. print "$prompt ";
  33294. if ($default) {
  33295. print "[$default] ";
  33296. }
  33297. print ": ";
  33298. $line = fgets(STDIN, 2048);
  33299. $result[$key] = ($default && trim($line) == '') ? $default : trim($line);
  33300. }
  33301. return $result;
  33302. }
  33303. $first_run = true;
  33304. while (true) {
  33305. $descLength = max(array_map('strlen', $prompts));
  33306. $descFormat = "%-{$descLength}s";
  33307. $last = count($prompts);
  33308. $i = 0;
  33309. foreach ($prompts as $n => $var) {
  33310. $res = isset($result[$n]) ? $result[$n] : null;
  33311. printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res);
  33312. }
  33313. print "\n1-$last, 'all', 'abort', or Enter to continue: ";
  33314. $tmp = trim(fgets(STDIN, 1024));
  33315. if (empty($tmp)) {
  33316. break;
  33317. }
  33318. if ($tmp == 'abort') {
  33319. return false;
  33320. }
  33321. if (isset($testprompts[(int)$tmp - 1])) {
  33322. $var = $testprompts[(int)$tmp - 1];
  33323. $desc = $prompts[$var];
  33324. $current = @$result[$var];
  33325. print "$desc [$current] : ";
  33326. $tmp = trim(fgets(STDIN, 1024));
  33327. if ($tmp !== '') {
  33328. $result[$var] = $tmp;
  33329. }
  33330. } elseif ($tmp == 'all') {
  33331. foreach ($prompts as $var => $desc) {
  33332. $current = $result[$var];
  33333. print "$desc [$current] : ";
  33334. $tmp = trim(fgets(STDIN, 1024));
  33335. if (trim($tmp) !== '') {
  33336. $result[$var] = trim($tmp);
  33337. }
  33338. }
  33339. }
  33340. $first_run = false;
  33341. }
  33342. return $result;
  33343. }
  33344. function userConfirm($prompt, $default = 'yes')
  33345. {
  33346. trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
  33347. static $positives = array('y', 'yes', 'on', '1');
  33348. static $negatives = array('n', 'no', 'off', '0');
  33349. print "$this->lp$prompt [$default] : ";
  33350. $fp = fopen("php://stdin", "r");
  33351. $line = fgets($fp, 2048);
  33352. fclose($fp);
  33353. $answer = strtolower(trim($line));
  33354. if (empty($answer)) {
  33355. $answer = $default;
  33356. }
  33357. if (in_array($answer, $positives)) {
  33358. return true;
  33359. }
  33360. if (in_array($answer, $negatives)) {
  33361. return false;
  33362. }
  33363. if (in_array($default, $positives)) {
  33364. return true;
  33365. }
  33366. return false;
  33367. }
  33368. function outputData($data, $command = '_default')
  33369. {
  33370. switch ($command) {
  33371. case 'channel-info':
  33372. foreach ($data as $type => $section) {
  33373. if ($type == 'main') {
  33374. $section['data'] = array_values($section['data']);
  33375. }
  33376. $this->outputData($section);
  33377. }
  33378. break;
  33379. case 'install':
  33380. case 'upgrade':
  33381. case 'upgrade-all':
  33382. if (is_array($data) && isset($data['release_warnings'])) {
  33383. $this->_displayLine('');
  33384. $this->_startTable(array(
  33385. 'border' => false,
  33386. 'caption' => 'Release Warnings'
  33387. ));
  33388. $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
  33389. $this->_endTable();
  33390. $this->_displayLine('');
  33391. }
  33392. $this->_displayLine(is_array($data) ? $data['data'] : $data);
  33393. break;
  33394. case 'search':
  33395. $this->_startTable($data);
  33396. if (isset($data['headline']) && is_array($data['headline'])) {
  33397. $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  33398. }
  33399. $packages = array();
  33400. foreach($data['data'] as $category) {
  33401. foreach($category as $name => $pkg) {
  33402. $packages[$pkg[0]] = $pkg;
  33403. }
  33404. }
  33405. $p = array_keys($packages);
  33406. natcasesort($p);
  33407. foreach ($p as $name) {
  33408. $this->_tableRow($packages[$name], null, array(1 => array('wrap' => 55)));
  33409. }
  33410. $this->_endTable();
  33411. break;
  33412. case 'list-all':
  33413. if (!isset($data['data'])) {
  33414. $this->_displayLine('No packages in channel');
  33415. break;
  33416. }
  33417. $this->_startTable($data);
  33418. if (isset($data['headline']) && is_array($data['headline'])) {
  33419. $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  33420. }
  33421. $packages = array();
  33422. foreach($data['data'] as $category) {
  33423. foreach($category as $name => $pkg) {
  33424. $packages[$pkg[0]] = $pkg;
  33425. }
  33426. }
  33427. $p = array_keys($packages);
  33428. natcasesort($p);
  33429. foreach ($p as $name) {
  33430. $pkg = $packages[$name];
  33431. unset($pkg[4], $pkg[5]);
  33432. $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
  33433. }
  33434. $this->_endTable();
  33435. break;
  33436. case 'config-show':
  33437. $data['border'] = false;
  33438. $opts = array(
  33439. 0 => array('wrap' => 30),
  33440. 1 => array('wrap' => 20),
  33441. 2 => array('wrap' => 35)
  33442. );
  33443. $this->_startTable($data);
  33444. if (isset($data['headline']) && is_array($data['headline'])) {
  33445. $this->_tableRow($data['headline'], array('bold' => true), $opts);
  33446. }
  33447. foreach ($data['data'] as $group) {
  33448. foreach ($group as $value) {
  33449. if ($value[2] == '') {
  33450. $value[2] = "<not set>";
  33451. }
  33452. $this->_tableRow($value, null, $opts);
  33453. }
  33454. }
  33455. $this->_endTable();
  33456. break;
  33457. case 'remote-info':
  33458. $d = $data;
  33459. $data = array(
  33460. 'caption' => 'Package details:',
  33461. 'border' => false,
  33462. 'data' => array(
  33463. array("Latest", $data['stable']),
  33464. array("Installed", $data['installed']),
  33465. array("Package", $data['name']),
  33466. array("License", $data['license']),
  33467. array("Category", $data['category']),
  33468. array("Summary", $data['summary']),
  33469. array("Description", $data['description']),
  33470. ),
  33471. );
  33472. if (isset($d['deprecated']) && $d['deprecated']) {
  33473. $conf = &PEAR_Config::singleton();
  33474. $reg = $conf->getRegistry();
  33475. $name = $reg->parsedPackageNameToString($d['deprecated'], true);
  33476. $data['data'][] = array('Deprecated! use', $name);
  33477. }
  33478. default: {
  33479. if (is_array($data)) {
  33480. $this->_startTable($data);
  33481. $count = count($data['data'][0]);
  33482. if ($count == 2) {
  33483. $opts = array(0 => array('wrap' => 25),
  33484. 1 => array('wrap' => 48)
  33485. );
  33486. } elseif ($count == 3) {
  33487. $opts = array(0 => array('wrap' => 30),
  33488. 1 => array('wrap' => 20),
  33489. 2 => array('wrap' => 35)
  33490. );
  33491. } else {
  33492. $opts = null;
  33493. }
  33494. if (isset($data['headline']) && is_array($data['headline'])) {
  33495. $this->_tableRow($data['headline'],
  33496. array('bold' => true),
  33497. $opts);
  33498. }
  33499. if (is_array($data['data'])) {
  33500. foreach($data['data'] as $row) {
  33501. $this->_tableRow($row, null, $opts);
  33502. }
  33503. } else {
  33504. $this->_tableRow(array($data['data']), null, $opts);
  33505. }
  33506. $this->_endTable();
  33507. } else {
  33508. $this->_displayLine($data);
  33509. }
  33510. }
  33511. }
  33512. }
  33513. function log($text, $append_crlf = true)
  33514. {
  33515. if ($append_crlf) {
  33516. return $this->_displayLine($text);
  33517. }
  33518. return $this->_display($text);
  33519. }
  33520. function bold($text)
  33521. {
  33522. if (empty($this->term['bold'])) {
  33523. return strtoupper($text);
  33524. }
  33525. return $this->term['bold'] . $text . $this->term['normal'];
  33526. }
  33527. function _displayHeading($title)
  33528. {
  33529. print $this->lp.$this->bold($title)."\n";
  33530. print $this->lp.str_repeat("=", strlen($title))."\n";
  33531. }
  33532. function _startTable($params = array())
  33533. {
  33534. $params['table_data'] = array();
  33535. $params['widest'] = array(); // indexed by column
  33536. $params['highest'] = array(); // indexed by row
  33537. $params['ncols'] = 0;
  33538. $this->params = $params;
  33539. }
  33540. function _tableRow($columns, $rowparams = array(), $colparams = array())
  33541. {
  33542. $highest = 1;
  33543. for ($i = 0; $i < count($columns); $i++) {
  33544. $col = &$columns[$i];
  33545. if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
  33546. $col = wordwrap($col, $colparams[$i]['wrap']);
  33547. }
  33548. if (strpos($col, "\n") !== false) {
  33549. $multiline = explode("\n", $col);
  33550. $w = 0;
  33551. foreach ($multiline as $n => $line) {
  33552. $len = strlen($line);
  33553. if ($len > $w) {
  33554. $w = $len;
  33555. }
  33556. }
  33557. $lines = count($multiline);
  33558. } else {
  33559. $w = strlen($col);
  33560. }
  33561. if (isset($this->params['widest'][$i])) {
  33562. if ($w > $this->params['widest'][$i]) {
  33563. $this->params['widest'][$i] = $w;
  33564. }
  33565. } else {
  33566. $this->params['widest'][$i] = $w;
  33567. }
  33568. $tmp = count_chars($columns[$i], 1);
  33569. // handle unix, mac and windows formats
  33570. $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
  33571. if ($lines > $highest) {
  33572. $highest = $lines;
  33573. }
  33574. }
  33575. if (count($columns) > $this->params['ncols']) {
  33576. $this->params['ncols'] = count($columns);
  33577. }
  33578. $new_row = array(
  33579. 'data' => $columns,
  33580. 'height' => $highest,
  33581. 'rowparams' => $rowparams,
  33582. 'colparams' => $colparams,
  33583. );
  33584. $this->params['table_data'][] = $new_row;
  33585. }
  33586. function _endTable()
  33587. {
  33588. extract($this->params);
  33589. if (!empty($caption)) {
  33590. $this->_displayHeading($caption);
  33591. }
  33592. if (count($table_data) === 0) {
  33593. return;
  33594. }
  33595. if (!isset($width)) {
  33596. $width = $widest;
  33597. } else {
  33598. for ($i = 0; $i < $ncols; $i++) {
  33599. if (!isset($width[$i])) {
  33600. $width[$i] = $widest[$i];
  33601. }
  33602. }
  33603. }
  33604. $border = false;
  33605. if (empty($border)) {
  33606. $cellstart = '';
  33607. $cellend = ' ';
  33608. $rowend = '';
  33609. $padrowend = false;
  33610. $borderline = '';
  33611. } else {
  33612. $cellstart = '| ';
  33613. $cellend = ' ';
  33614. $rowend = '|';
  33615. $padrowend = true;
  33616. $borderline = '+';
  33617. foreach ($width as $w) {
  33618. $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
  33619. $borderline .= '+';
  33620. }
  33621. }
  33622. if ($borderline) {
  33623. $this->_displayLine($borderline);
  33624. }
  33625. for ($i = 0; $i < count($table_data); $i++) {
  33626. extract($table_data[$i]);
  33627. if (!is_array($rowparams)) {
  33628. $rowparams = array();
  33629. }
  33630. if (!is_array($colparams)) {
  33631. $colparams = array();
  33632. }
  33633. $rowlines = array();
  33634. if ($height > 1) {
  33635. for ($c = 0; $c < count($data); $c++) {
  33636. $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
  33637. if (count($rowlines[$c]) < $height) {
  33638. $rowlines[$c] = array_pad($rowlines[$c], $height, '');
  33639. }
  33640. }
  33641. } else {
  33642. for ($c = 0; $c < count($data); $c++) {
  33643. $rowlines[$c] = array($data[$c]);
  33644. }
  33645. }
  33646. for ($r = 0; $r < $height; $r++) {
  33647. $rowtext = '';
  33648. for ($c = 0; $c < count($data); $c++) {
  33649. if (isset($colparams[$c])) {
  33650. $attribs = array_merge($rowparams, $colparams);
  33651. } else {
  33652. $attribs = $rowparams;
  33653. }
  33654. $w = isset($width[$c]) ? $width[$c] : 0;
  33655. //$cell = $data[$c];
  33656. $cell = $rowlines[$c][$r];
  33657. $l = strlen($cell);
  33658. if ($l > $w) {
  33659. $cell = substr($cell, 0, $w);
  33660. }
  33661. if (isset($attribs['bold'])) {
  33662. $cell = $this->bold($cell);
  33663. }
  33664. if ($l < $w) {
  33665. // not using str_pad here because we may
  33666. // add bold escape characters to $cell
  33667. $cell .= str_repeat(' ', $w - $l);
  33668. }
  33669. $rowtext .= $cellstart . $cell . $cellend;
  33670. }
  33671. if (!$border) {
  33672. $rowtext = rtrim($rowtext);
  33673. }
  33674. $rowtext .= $rowend;
  33675. $this->_displayLine($rowtext);
  33676. }
  33677. }
  33678. if ($borderline) {
  33679. $this->_displayLine($borderline);
  33680. }
  33681. }
  33682. function _displayLine($text)
  33683. {
  33684. print "$this->lp$text\n";
  33685. }
  33686. function _display($text)
  33687. {
  33688. print $text;
  33689. }
  33690. }
  33691. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Common.php���������������������������������������������������������0000644�0001750�0001750�00000014107�13565304531�017607� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  33692. /**
  33693. * Base class for all installation roles.
  33694. *
  33695. * PHP versions 4 and 5
  33696. *
  33697. * @category pear
  33698. * @package PEAR
  33699. * @author Greg Beaver <cellog@php.net>
  33700. * @copyright 1997-2006 The PHP Group
  33701. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33702. * @link http://pear.php.net/package/PEAR
  33703. * @since File available since Release 1.4.0a1
  33704. */
  33705. /**
  33706. * Base class for all installation roles.
  33707. *
  33708. * This class allows extensibility of file roles. Packages with complex
  33709. * customization can now provide custom file roles along with the possibility of
  33710. * adding configuration values to match.
  33711. * @category pear
  33712. * @package PEAR
  33713. * @author Greg Beaver <cellog@php.net>
  33714. * @copyright 1997-2006 The PHP Group
  33715. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33716. * @version Release: 1.10.10
  33717. * @link http://pear.php.net/package/PEAR
  33718. * @since Class available since Release 1.4.0a1
  33719. */
  33720. class PEAR_Installer_Role_Common
  33721. {
  33722. /**
  33723. * @var PEAR_Config
  33724. * @access protected
  33725. */
  33726. var $config;
  33727. /**
  33728. * @param PEAR_Config
  33729. */
  33730. function __construct(&$config)
  33731. {
  33732. $this->config = $config;
  33733. }
  33734. /**
  33735. * Retrieve configuration information about a file role from its XML info
  33736. *
  33737. * @param string $role Role Classname, as in "PEAR_Installer_Role_Data"
  33738. * @return array
  33739. */
  33740. function getInfo($role)
  33741. {
  33742. if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) {
  33743. return PEAR::raiseError('Unknown Role class: "' . $role . '"');
  33744. }
  33745. return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role];
  33746. }
  33747. /**
  33748. * This is called for each file to set up the directories and files
  33749. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  33750. * @param array attributes from the <file> tag
  33751. * @param string file name
  33752. * @return array an array consisting of:
  33753. *
  33754. * 1 the original, pre-baseinstalldir installation directory
  33755. * 2 the final installation directory
  33756. * 3 the full path to the final location of the file
  33757. * 4 the location of the pre-installation file
  33758. */
  33759. function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
  33760. {
  33761. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  33762. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  33763. if (PEAR::isError($roleInfo)) {
  33764. return $roleInfo;
  33765. }
  33766. if (!$roleInfo['locationconfig']) {
  33767. return false;
  33768. }
  33769. if ($roleInfo['honorsbaseinstall']) {
  33770. $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer,
  33771. $pkg->getChannel());
  33772. if (!empty($atts['baseinstalldir'])) {
  33773. $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
  33774. }
  33775. } elseif ($roleInfo['unusualbaseinstall']) {
  33776. $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
  33777. $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
  33778. if (!empty($atts['baseinstalldir'])) {
  33779. $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
  33780. }
  33781. } else {
  33782. $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
  33783. $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
  33784. }
  33785. if (dirname($file) != '.' && empty($atts['install-as'])) {
  33786. $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
  33787. }
  33788. if (empty($atts['install-as'])) {
  33789. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
  33790. } else {
  33791. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
  33792. }
  33793. $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
  33794. // Clean up the DIRECTORY_SEPARATOR mess
  33795. $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  33796. list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
  33797. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR,
  33798. DIRECTORY_SEPARATOR),
  33799. array($dest_dir, $dest_file, $orig_file));
  33800. return array($save_destdir, $dest_dir, $dest_file, $orig_file);
  33801. }
  33802. /**
  33803. * Get the name of the configuration variable that specifies the location of this file
  33804. * @return string|false
  33805. */
  33806. function getLocationConfig()
  33807. {
  33808. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  33809. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  33810. if (PEAR::isError($roleInfo)) {
  33811. return $roleInfo;
  33812. }
  33813. return $roleInfo['locationconfig'];
  33814. }
  33815. /**
  33816. * Do any unusual setup here
  33817. * @param PEAR_Installer
  33818. * @param PEAR_PackageFile_v2
  33819. * @param array file attributes
  33820. * @param string file name
  33821. */
  33822. function setup(&$installer, $pkg, $atts, $file)
  33823. {
  33824. }
  33825. function isExecutable()
  33826. {
  33827. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  33828. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  33829. if (PEAR::isError($roleInfo)) {
  33830. return $roleInfo;
  33831. }
  33832. return $roleInfo['executable'];
  33833. }
  33834. function isInstallable()
  33835. {
  33836. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  33837. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  33838. if (PEAR::isError($roleInfo)) {
  33839. return $roleInfo;
  33840. }
  33841. return $roleInfo['installable'];
  33842. }
  33843. function isExtension()
  33844. {
  33845. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  33846. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  33847. if (PEAR::isError($roleInfo)) {
  33848. return $roleInfo;
  33849. }
  33850. return $roleInfo['phpextension'];
  33851. }
  33852. }
  33853. ?>
  33854. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Cfg.xml������������������������������������������������������������0000644�0001750�0001750�00000000645�13565304531�017071� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  33855. <releasetypes>php</releasetypes>
  33856. <releasetypes>extsrc</releasetypes>
  33857. <releasetypes>extbin</releasetypes>
  33858. <releasetypes>zendextsrc</releasetypes>
  33859. <releasetypes>zendextbin</releasetypes>
  33860. <installable>1</installable>
  33861. <locationconfig>cfg_dir</locationconfig>
  33862. <honorsbaseinstall />
  33863. <unusualbaseinstall>1</unusualbaseinstall>
  33864. <phpfile />
  33865. <executable />
  33866. <phpextension />
  33867. <config_vars />
  33868. </role>�������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Cfg.php������������������������������������������������������������0000644�0001750�0001750�00000007577�13565304531�017073� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  33869. /**
  33870. * PEAR_Installer_Role_Cfg
  33871. *
  33872. * PHP versions 4 and 5
  33873. *
  33874. * @category pear
  33875. * @package PEAR
  33876. * @author Greg Beaver <cellog@php.net>
  33877. * @copyright 2007-2009 The Authors
  33878. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33879. * @link http://pear.php.net/package/PEAR
  33880. * @since File available since Release 1.7.0
  33881. */
  33882. /**
  33883. * @category pear
  33884. * @package PEAR
  33885. * @author Greg Beaver <cellog@php.net>
  33886. * @copyright 2007-2009 The Authors
  33887. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33888. * @version Release: 1.10.10
  33889. * @link http://pear.php.net/package/PEAR
  33890. * @since Class available since Release 1.7.0
  33891. */
  33892. class PEAR_Installer_Role_Cfg extends PEAR_Installer_Role_Common
  33893. {
  33894. /**
  33895. * @var PEAR_Installer
  33896. */
  33897. var $installer;
  33898. /**
  33899. * the md5 of the original file
  33900. *
  33901. * @var unknown_type
  33902. */
  33903. var $md5 = null;
  33904. /**
  33905. * Do any unusual setup here
  33906. * @param PEAR_Installer
  33907. * @param PEAR_PackageFile_v2
  33908. * @param array file attributes
  33909. * @param string file name
  33910. */
  33911. function setup(&$installer, $pkg, $atts, $file)
  33912. {
  33913. $this->installer = &$installer;
  33914. $reg = &$this->installer->config->getRegistry();
  33915. $package = $reg->getPackage($pkg->getPackage(), $pkg->getChannel());
  33916. if ($package) {
  33917. $filelist = $package->getFilelist();
  33918. if (isset($filelist[$file]) && isset($filelist[$file]['md5sum'])) {
  33919. $this->md5 = $filelist[$file]['md5sum'];
  33920. }
  33921. }
  33922. }
  33923. function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
  33924. {
  33925. $test = parent::processInstallation($pkg, $atts, $file, $tmp_path, $layer);
  33926. if (@file_exists($test[2]) && @file_exists($test[3])) {
  33927. $md5 = md5_file($test[2]);
  33928. // configuration has already been installed, check for mods
  33929. if ($md5 !== $this->md5 && $md5 !== md5_file($test[3])) {
  33930. // configuration has been modified, so save our version as
  33931. // configfile-version
  33932. $old = $test[2];
  33933. $test[2] .= '.new-' . $pkg->getVersion();
  33934. // backup original and re-install it
  33935. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  33936. $tmpcfg = $this->config->get('temp_dir');
  33937. $newloc = System::mkdir(array('-p', $tmpcfg));
  33938. if (!$newloc) {
  33939. // try temp_dir
  33940. $newloc = System::mktemp(array('-d'));
  33941. if (!$newloc || PEAR::isError($newloc)) {
  33942. PEAR::popErrorHandling();
  33943. return PEAR::raiseError('Could not save existing configuration file '.
  33944. $old . ', unable to install. Please set temp_dir ' .
  33945. 'configuration variable to a writeable location and try again');
  33946. }
  33947. } else {
  33948. $newloc = $tmpcfg;
  33949. }
  33950. $temp_file = $newloc . DIRECTORY_SEPARATOR . uniqid('savefile');
  33951. if (!@copy($old, $temp_file)) {
  33952. PEAR::popErrorHandling();
  33953. return PEAR::raiseError('Could not save existing configuration file '.
  33954. $old . ', unable to install. Please set temp_dir ' .
  33955. 'configuration variable to a writeable location and try again');
  33956. }
  33957. PEAR::popErrorHandling();
  33958. $this->installer->log(0, "WARNING: configuration file $old is being installed as $test[2], you should manually merge in changes to the existing configuration file");
  33959. $this->installer->addFileOperation('rename', array($temp_file, $old, false));
  33960. $this->installer->addFileOperation('delete', array($temp_file));
  33961. }
  33962. }
  33963. return $test;
  33964. }
  33965. }���������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Data.xml�����������������������������������������������������������0000644�0001750�0001750�00000000622�13565304531�017236� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  33966. <releasetypes>php</releasetypes>
  33967. <releasetypes>extsrc</releasetypes>
  33968. <releasetypes>extbin</releasetypes>
  33969. <releasetypes>zendextsrc</releasetypes>
  33970. <releasetypes>zendextbin</releasetypes>
  33971. <installable>1</installable>
  33972. <locationconfig>data_dir</locationconfig>
  33973. <honorsbaseinstall />
  33974. <unusualbaseinstall />
  33975. <phpfile />
  33976. <executable />
  33977. <phpextension />
  33978. <config_vars />
  33979. </role>��������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Data.php�����������������������������������������������������������0000644�0001750�0001750�00000001417�13565304531�017230� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  33980. /**
  33981. * PEAR_Installer_Role_Data
  33982. *
  33983. * PHP versions 4 and 5
  33984. *
  33985. * @category pear
  33986. * @package PEAR
  33987. * @author Greg Beaver <cellog@php.net>
  33988. * @copyright 1997-2009 The Authors
  33989. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33990. * @link http://pear.php.net/package/PEAR
  33991. * @since File available since Release 1.4.0a1
  33992. */
  33993. /**
  33994. * @category pear
  33995. * @package PEAR
  33996. * @author Greg Beaver <cellog@php.net>
  33997. * @copyright 1997-2009 The Authors
  33998. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  33999. * @version Release: 1.10.10
  34000. * @link http://pear.php.net/package/PEAR
  34001. * @since Class available since Release 1.4.0a1
  34002. */
  34003. class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {}
  34004. ?>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Doc.xml������������������������������������������������������������0000644�0001750�0001750�00000000621�13565304531�017071� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34005. <releasetypes>php</releasetypes>
  34006. <releasetypes>extsrc</releasetypes>
  34007. <releasetypes>extbin</releasetypes>
  34008. <releasetypes>zendextsrc</releasetypes>
  34009. <releasetypes>zendextbin</releasetypes>
  34010. <installable>1</installable>
  34011. <locationconfig>doc_dir</locationconfig>
  34012. <honorsbaseinstall />
  34013. <unusualbaseinstall />
  34014. <phpfile />
  34015. <executable />
  34016. <phpextension />
  34017. <config_vars />
  34018. </role>���������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Doc.php������������������������������������������������������������0000644�0001750�0001750�00000001415�13565304531�017062� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34019. /**
  34020. * PEAR_Installer_Role_Doc
  34021. *
  34022. * PHP versions 4 and 5
  34023. *
  34024. * @category pear
  34025. * @package PEAR
  34026. * @author Greg Beaver <cellog@php.net>
  34027. * @copyright 1997-2009 The Authors
  34028. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34029. * @link http://pear.php.net/package/PEAR
  34030. * @since File available since Release 1.4.0a1
  34031. */
  34032. /**
  34033. * @category pear
  34034. * @package PEAR
  34035. * @author Greg Beaver <cellog@php.net>
  34036. * @copyright 1997-2009 The Authors
  34037. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34038. * @version Release: 1.10.10
  34039. * @link http://pear.php.net/package/PEAR
  34040. * @since Class available since Release 1.4.0a1
  34041. */
  34042. class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {}
  34043. ?>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Ext.xml������������������������������������������������������������0000644�0001750�0001750�00000000502�13565304531�017122� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34044. <releasetypes>extbin</releasetypes>
  34045. <releasetypes>zendextbin</releasetypes>
  34046. <installable>1</installable>
  34047. <locationconfig>ext_dir</locationconfig>
  34048. <honorsbaseinstall>1</honorsbaseinstall>
  34049. <unusualbaseinstall />
  34050. <phpfile />
  34051. <executable />
  34052. <phpextension>1</phpextension>
  34053. <config_vars />
  34054. </role>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Ext.php������������������������������������������������������������0000644�0001750�0001750�00000001415�13565304531�017115� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34055. /**
  34056. * PEAR_Installer_Role_Ext
  34057. *
  34058. * PHP versions 4 and 5
  34059. *
  34060. * @category pear
  34061. * @package PEAR
  34062. * @author Greg Beaver <cellog@php.net>
  34063. * @copyright 1997-2009 The Authors
  34064. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34065. * @link http://pear.php.net/package/PEAR
  34066. * @since File available since Release 1.4.0a1
  34067. */
  34068. /**
  34069. * @category pear
  34070. * @package PEAR
  34071. * @author Greg Beaver <cellog@php.net>
  34072. * @copyright 1997-2009 The Authors
  34073. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34074. * @version Release: 1.10.10
  34075. * @link http://pear.php.net/package/PEAR
  34076. * @since Class available since Release 1.4.0a1
  34077. */
  34078. class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {}
  34079. ?>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Man.xml������������������������������������������������������������0000644�0001750�0001750�00000000645�13565304531�017105� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34080. <releasetypes>php</releasetypes>
  34081. <releasetypes>extsrc</releasetypes>
  34082. <releasetypes>extbin</releasetypes>
  34083. <releasetypes>zendextsrc</releasetypes>
  34084. <releasetypes>zendextbin</releasetypes>
  34085. <installable>1</installable>
  34086. <locationconfig>man_dir</locationconfig>
  34087. <honorsbaseinstall>1</honorsbaseinstall>
  34088. <unusualbaseinstall />
  34089. <phpfile />
  34090. <executable />
  34091. <phpextension />
  34092. <config_vars />
  34093. </role>
  34094. �������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Man.php������������������������������������������������������������0000644�0001750�0001750�00000001445�13565304531�017073� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34095. /**
  34096. * PEAR_Installer_Role_Man
  34097. *
  34098. * PHP versions 4 and 5
  34099. *
  34100. * @category pear
  34101. * @package PEAR
  34102. * @author Hannes Magnusson <bjori@php.net>
  34103. * @copyright 2011 The Authors
  34104. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34105. * @version SVN: $Id: $
  34106. * @link http://pear.php.net/package/PEAR
  34107. * @since File available since Release 1.10.0
  34108. */
  34109. /**
  34110. * @category pear
  34111. * @package PEAR
  34112. * @author Hannes Magnusson <bjori@php.net>
  34113. * @copyright 2011 The Authors
  34114. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34115. * @version Release: 1.10.10
  34116. * @link http://pear.php.net/package/PEAR
  34117. * @since Class available since Release 1.10.0
  34118. */
  34119. class PEAR_Installer_Role_Man extends PEAR_Installer_Role_Common {}
  34120. ?>
  34121. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Php.xml������������������������������������������������������������0000644�0001750�0001750�00000000655�13565304531�017122� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34122. <releasetypes>php</releasetypes>
  34123. <releasetypes>extsrc</releasetypes>
  34124. <releasetypes>extbin</releasetypes>
  34125. <releasetypes>zendextsrc</releasetypes>
  34126. <releasetypes>zendextbin</releasetypes>
  34127. <installable>1</installable>
  34128. <locationconfig>php_dir</locationconfig>
  34129. <honorsbaseinstall>1</honorsbaseinstall>
  34130. <unusualbaseinstall />
  34131. <phpfile>1</phpfile>
  34132. <executable />
  34133. <phpextension />
  34134. <config_vars />
  34135. </role>�����������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Php.php������������������������������������������������������������0000644�0001750�0001750�00000001415�13565304531�017104� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34136. /**
  34137. * PEAR_Installer_Role_Php
  34138. *
  34139. * PHP versions 4 and 5
  34140. *
  34141. * @category pear
  34142. * @package PEAR
  34143. * @author Greg Beaver <cellog@php.net>
  34144. * @copyright 1997-2009 The Authors
  34145. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34146. * @link http://pear.php.net/package/PEAR
  34147. * @since File available since Release 1.4.0a1
  34148. */
  34149. /**
  34150. * @category pear
  34151. * @package PEAR
  34152. * @author Greg Beaver <cellog@php.net>
  34153. * @copyright 1997-2009 The Authors
  34154. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34155. * @version Release: 1.10.10
  34156. * @link http://pear.php.net/package/PEAR
  34157. * @since Class available since Release 1.4.0a1
  34158. */
  34159. class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {}
  34160. ?>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Script.xml���������������������������������������������������������0000644�0001750�0001750�00000000660�13565304531�017633� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34161. <releasetypes>php</releasetypes>
  34162. <releasetypes>extsrc</releasetypes>
  34163. <releasetypes>extbin</releasetypes>
  34164. <releasetypes>zendextsrc</releasetypes>
  34165. <releasetypes>zendextbin</releasetypes>
  34166. <installable>1</installable>
  34167. <locationconfig>bin_dir</locationconfig>
  34168. <honorsbaseinstall>1</honorsbaseinstall>
  34169. <unusualbaseinstall />
  34170. <phpfile />
  34171. <executable>1</executable>
  34172. <phpextension />
  34173. <config_vars />
  34174. </role>��������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Script.php���������������������������������������������������������0000644�0001750�0001750�00000001423�13565304531�017620� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34175. /**
  34176. * PEAR_Installer_Role_Script
  34177. *
  34178. * PHP versions 4 and 5
  34179. *
  34180. * @category pear
  34181. * @package PEAR
  34182. * @author Greg Beaver <cellog@php.net>
  34183. * @copyright 1997-2009 The Authors
  34184. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34185. * @link http://pear.php.net/package/PEAR
  34186. * @since File available since Release 1.4.0a1
  34187. */
  34188. /**
  34189. * @category pear
  34190. * @package PEAR
  34191. * @author Greg Beaver <cellog@php.net>
  34192. * @copyright 1997-2009 The Authors
  34193. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34194. * @version Release: 1.10.10
  34195. * @link http://pear.php.net/package/PEAR
  34196. * @since Class available since Release 1.4.0a1
  34197. */
  34198. class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {}
  34199. ?>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Src.xml������������������������������������������������������������0000644�0001750�0001750�00000000442�13565304531�017114� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34200. <releasetypes>extsrc</releasetypes>
  34201. <releasetypes>zendextsrc</releasetypes>
  34202. <installable>1</installable>
  34203. <locationconfig>temp_dir</locationconfig>
  34204. <honorsbaseinstall />
  34205. <unusualbaseinstall />
  34206. <phpfile />
  34207. <executable />
  34208. <phpextension />
  34209. <config_vars />
  34210. </role>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Src.php������������������������������������������������������������0000644�0001750�0001750�00000001562�13565304531�017107� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34211. /**
  34212. * PEAR_Installer_Role_Src
  34213. *
  34214. * PHP versions 4 and 5
  34215. *
  34216. * @category pear
  34217. * @package PEAR
  34218. * @author Greg Beaver <cellog@php.net>
  34219. * @copyright 1997-2009 The Authors
  34220. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34221. * @link http://pear.php.net/package/PEAR
  34222. * @since File available since Release 1.4.0a1
  34223. */
  34224. /**
  34225. * @category pear
  34226. * @package PEAR
  34227. * @author Greg Beaver <cellog@php.net>
  34228. * @copyright 1997-2009 The Authors
  34229. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34230. * @version Release: 1.10.10
  34231. * @link http://pear.php.net/package/PEAR
  34232. * @since Class available since Release 1.4.0a1
  34233. */
  34234. class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common
  34235. {
  34236. function setup(&$installer, $pkg, $atts, $file)
  34237. {
  34238. $installer->source_files++;
  34239. }
  34240. }
  34241. ?>����������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Test.xml�����������������������������������������������������������0000644�0001750�0001750�00000000622�13565304531�017304� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34242. <releasetypes>php</releasetypes>
  34243. <releasetypes>extsrc</releasetypes>
  34244. <releasetypes>extbin</releasetypes>
  34245. <releasetypes>zendextsrc</releasetypes>
  34246. <releasetypes>zendextbin</releasetypes>
  34247. <installable>1</installable>
  34248. <locationconfig>test_dir</locationconfig>
  34249. <honorsbaseinstall />
  34250. <unusualbaseinstall />
  34251. <phpfile />
  34252. <executable />
  34253. <phpextension />
  34254. <config_vars />
  34255. </role>��������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Test.php�����������������������������������������������������������0000644�0001750�0001750�00000001417�13565304531�017276� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34256. /**
  34257. * PEAR_Installer_Role_Test
  34258. *
  34259. * PHP versions 4 and 5
  34260. *
  34261. * @category pear
  34262. * @package PEAR
  34263. * @author Greg Beaver <cellog@php.net>
  34264. * @copyright 1997-2009 The Authors
  34265. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34266. * @link http://pear.php.net/package/PEAR
  34267. * @since File available since Release 1.4.0a1
  34268. */
  34269. /**
  34270. * @category pear
  34271. * @package PEAR
  34272. * @author Greg Beaver <cellog@php.net>
  34273. * @copyright 1997-2009 The Authors
  34274. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34275. * @version Release: 1.10.10
  34276. * @link http://pear.php.net/package/PEAR
  34277. * @since Class available since Release 1.4.0a1
  34278. */
  34279. class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {}
  34280. ?>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Www.xml������������������������������������������������������������0000644�0001750�0001750�00000000644�13565304531�017155� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<role version="1.0">
  34281. <releasetypes>php</releasetypes>
  34282. <releasetypes>extsrc</releasetypes>
  34283. <releasetypes>extbin</releasetypes>
  34284. <releasetypes>zendextsrc</releasetypes>
  34285. <releasetypes>zendextbin</releasetypes>
  34286. <installable>1</installable>
  34287. <locationconfig>www_dir</locationconfig>
  34288. <honorsbaseinstall>1</honorsbaseinstall>
  34289. <unusualbaseinstall />
  34290. <phpfile />
  34291. <executable />
  34292. <phpextension />
  34293. <config_vars />
  34294. </role>��������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role/Www.php������������������������������������������������������������0000644�0001750�0001750�00000001411�13565304531�017135� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34295. /**
  34296. * PEAR_Installer_Role_Www
  34297. *
  34298. * PHP versions 4 and 5
  34299. *
  34300. * @category pear
  34301. * @package PEAR
  34302. * @author Greg Beaver <cellog@php.net>
  34303. * @copyright 2007-2009 The Authors
  34304. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34305. * @link http://pear.php.net/package/PEAR
  34306. * @since File available since Release 1.7.0
  34307. */
  34308. /**
  34309. * @category pear
  34310. * @package PEAR
  34311. * @author Greg Beaver <cellog@php.net>
  34312. * @copyright 2007-2009 The Authors
  34313. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34314. * @version Release: 1.10.10
  34315. * @link http://pear.php.net/package/PEAR
  34316. * @since Class available since Release 1.7.0
  34317. */
  34318. class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {}
  34319. ?>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Installer/Role.php����������������������������������������������������������������0000644�0001750�0001750�00000017274�13565304531�016367� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34320. /**
  34321. * PEAR_Installer_Role
  34322. *
  34323. * PHP versions 4 and 5
  34324. *
  34325. * @category pear
  34326. * @package PEAR
  34327. * @author Greg Beaver <cellog@php.net>
  34328. * @copyright 1997-2009 The Authors
  34329. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34330. * @link http://pear.php.net/package/PEAR
  34331. * @since File available since Release 1.4.0a1
  34332. */
  34333. /**
  34334. * base class for installer roles
  34335. */
  34336. require_once 'PEAR/Installer/Role/Common.php';
  34337. require_once 'PEAR/XMLParser.php';
  34338. /**
  34339. * @category pear
  34340. * @package PEAR
  34341. * @author Greg Beaver <cellog@php.net>
  34342. * @copyright 1997-2009 The Authors
  34343. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34344. * @version Release: 1.10.10
  34345. * @link http://pear.php.net/package/PEAR
  34346. * @since Class available since Release 1.4.0a1
  34347. */
  34348. class PEAR_Installer_Role
  34349. {
  34350. /**
  34351. * Set up any additional configuration variables that file roles require
  34352. *
  34353. * Never call this directly, it is called by the PEAR_Config constructor
  34354. * @param PEAR_Config
  34355. */
  34356. public static function initializeConfig(&$config)
  34357. {
  34358. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  34359. PEAR_Installer_Role::registerRoles();
  34360. }
  34361. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) {
  34362. if (!$info['config_vars']) {
  34363. continue;
  34364. }
  34365. $config->_addConfigVars($class, $info['config_vars']);
  34366. }
  34367. }
  34368. /**
  34369. * @param PEAR_PackageFile_v2
  34370. * @param string role name
  34371. * @param PEAR_Config
  34372. * @return PEAR_Installer_Role_Common
  34373. */
  34374. public static function &factory($pkg, $role, &$config)
  34375. {
  34376. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  34377. PEAR_Installer_Role::registerRoles();
  34378. }
  34379. if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
  34380. $a = false;
  34381. return $a;
  34382. }
  34383. $a = 'PEAR_Installer_Role_' . ucfirst($role);
  34384. if (!class_exists($a)) {
  34385. require_once str_replace('_', '/', $a) . '.php';
  34386. }
  34387. $b = new $a($config);
  34388. return $b;
  34389. }
  34390. /**
  34391. * Get a list of file roles that are valid for the particular release type.
  34392. *
  34393. * For instance, src files serve no purpose in regular php releases.
  34394. * @param string
  34395. * @param bool clear cache
  34396. * @return array
  34397. */
  34398. public static function getValidRoles($release, $clear = false)
  34399. {
  34400. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  34401. PEAR_Installer_Role::registerRoles();
  34402. }
  34403. static $ret = array();
  34404. if ($clear) {
  34405. $ret = array();
  34406. }
  34407. if (isset($ret[$release])) {
  34408. return $ret[$release];
  34409. }
  34410. $ret[$release] = array();
  34411. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  34412. if (in_array($release, $okreleases['releasetypes'])) {
  34413. $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  34414. }
  34415. }
  34416. return $ret[$release];
  34417. }
  34418. /**
  34419. * Get a list of roles that require their files to be installed
  34420. *
  34421. * Most roles must be installed, but src and package roles, for instance
  34422. * are pseudo-roles. src files are compiled into a new extension. Package
  34423. * roles are actually fully bundled releases of a package
  34424. * @param bool clear cache
  34425. * @return array
  34426. */
  34427. public static function getInstallableRoles($clear = false)
  34428. {
  34429. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  34430. PEAR_Installer_Role::registerRoles();
  34431. }
  34432. static $ret;
  34433. if ($clear) {
  34434. unset($ret);
  34435. }
  34436. if (isset($ret)) {
  34437. return $ret;
  34438. }
  34439. $ret = array();
  34440. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  34441. if ($okreleases['installable']) {
  34442. $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  34443. }
  34444. }
  34445. return $ret;
  34446. }
  34447. /**
  34448. * Return an array of roles that are affected by the baseinstalldir attribute
  34449. *
  34450. * Most roles ignore this attribute, and instead install directly into:
  34451. * PackageName/filepath
  34452. * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php
  34453. * @param bool clear cache
  34454. * @return array
  34455. */
  34456. public static function getBaseinstallRoles($clear = false)
  34457. {
  34458. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  34459. PEAR_Installer_Role::registerRoles();
  34460. }
  34461. static $ret;
  34462. if ($clear) {
  34463. unset($ret);
  34464. }
  34465. if (isset($ret)) {
  34466. return $ret;
  34467. }
  34468. $ret = array();
  34469. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  34470. if ($okreleases['honorsbaseinstall']) {
  34471. $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  34472. }
  34473. }
  34474. return $ret;
  34475. }
  34476. /**
  34477. * Return an array of file roles that should be analyzed for PHP content at package time,
  34478. * like the "php" role.
  34479. * @param bool clear cache
  34480. * @return array
  34481. */
  34482. public static function getPhpRoles($clear = false)
  34483. {
  34484. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  34485. PEAR_Installer_Role::registerRoles();
  34486. }
  34487. static $ret;
  34488. if ($clear) {
  34489. unset($ret);
  34490. }
  34491. if (isset($ret)) {
  34492. return $ret;
  34493. }
  34494. $ret = array();
  34495. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  34496. if ($okreleases['phpfile']) {
  34497. $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  34498. }
  34499. }
  34500. return $ret;
  34501. }
  34502. /**
  34503. * Scan through the Command directory looking for classes
  34504. * and see what commands they implement.
  34505. * @param string which directory to look for classes, defaults to
  34506. * the Installer/Roles subdirectory of
  34507. * the directory from where this file (__FILE__) is
  34508. * included.
  34509. *
  34510. * @return bool TRUE on success, a PEAR error on failure
  34511. */
  34512. public static function registerRoles($dir = null)
  34513. {
  34514. $GLOBALS['_PEAR_INSTALLER_ROLES'] = array();
  34515. $parser = new PEAR_XMLParser;
  34516. if ($dir === null) {
  34517. $dir = dirname(__FILE__) . '/Role';
  34518. }
  34519. if (!file_exists($dir) || !is_dir($dir)) {
  34520. return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory");
  34521. }
  34522. $dp = @opendir($dir);
  34523. if (empty($dp)) {
  34524. return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg");
  34525. }
  34526. while ($entry = readdir($dp)) {
  34527. if ($entry[0] == '.' || substr($entry, -4) != '.xml') {
  34528. continue;
  34529. }
  34530. $class = "PEAR_Installer_Role_".substr($entry, 0, -4);
  34531. // List of roles
  34532. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) {
  34533. $file = "$dir/$entry";
  34534. $parser->parse(file_get_contents($file));
  34535. $data = $parser->getData();
  34536. if (!is_array($data['releasetypes'])) {
  34537. $data['releasetypes'] = array($data['releasetypes']);
  34538. }
  34539. $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data;
  34540. }
  34541. }
  34542. closedir($dp);
  34543. ksort($GLOBALS['_PEAR_INSTALLER_ROLES']);
  34544. PEAR_Installer_Role::getBaseinstallRoles(true);
  34545. PEAR_Installer_Role::getInstallableRoles(true);
  34546. PEAR_Installer_Role::getPhpRoles(true);
  34547. PEAR_Installer_Role::getValidRoles('****', true);
  34548. return true;
  34549. }
  34550. }������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/Generator/v1.php������������������������������������������������������0000644�0001750�0001750�00000142261�13565304531�020133� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  34551. /**
  34552. * package.xml generation class, package.xml version 1.0
  34553. *
  34554. * PHP versions 4 and 5
  34555. *
  34556. * @category pear
  34557. * @package PEAR
  34558. * @author Greg Beaver <cellog@php.net>
  34559. * @copyright 1997-2009 The Authors
  34560. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34561. * @link http://pear.php.net/package/PEAR
  34562. * @since File available since Release 1.4.0a1
  34563. */
  34564. /**
  34565. * needed for PEAR_VALIDATE_* constants
  34566. */
  34567. require_once 'PEAR/Validate.php';
  34568. require_once 'System.php';
  34569. require_once 'PEAR/PackageFile/v2.php';
  34570. /**
  34571. * This class converts a PEAR_PackageFile_v1 object into any output format.
  34572. *
  34573. * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
  34574. * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
  34575. * @category pear
  34576. * @package PEAR
  34577. * @author Greg Beaver <cellog@php.net>
  34578. * @copyright 1997-2009 The Authors
  34579. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  34580. * @version Release: 1.10.10
  34581. * @link http://pear.php.net/package/PEAR
  34582. * @since Class available since Release 1.4.0a1
  34583. */
  34584. class PEAR_PackageFile_Generator_v1
  34585. {
  34586. /**
  34587. * @var PEAR_PackageFile_v1
  34588. */
  34589. var $_packagefile;
  34590. function __construct(&$packagefile)
  34591. {
  34592. $this->_packagefile = &$packagefile;
  34593. }
  34594. function getPackagerVersion()
  34595. {
  34596. return '1.10.10';
  34597. }
  34598. /**
  34599. * @param PEAR_Packager
  34600. * @param bool if true, a .tgz is written, otherwise a .tar is written
  34601. * @param string|null directory in which to save the .tgz
  34602. * @return string|PEAR_Error location of package or error object
  34603. */
  34604. function toTgz(&$packager, $compress = true, $where = null)
  34605. {
  34606. require_once 'Archive/Tar.php';
  34607. if ($where === null) {
  34608. if (!($where = System::mktemp(array('-d')))) {
  34609. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
  34610. }
  34611. } elseif (!@System::mkDir(array('-p', $where))) {
  34612. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
  34613. ' not be created');
  34614. }
  34615. if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
  34616. !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
  34617. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
  34618. ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
  34619. }
  34620. if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
  34621. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
  34622. }
  34623. $pkginfo = $this->_packagefile->getArray();
  34624. $ext = $compress ? '.tgz' : '.tar';
  34625. $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
  34626. $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
  34627. if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
  34628. !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
  34629. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
  34630. getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
  34631. }
  34632. if ($pkgfile = $this->_packagefile->getPackageFile()) {
  34633. $pkgdir = dirname(realpath($pkgfile));
  34634. $pkgfile = basename($pkgfile);
  34635. } else {
  34636. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
  34637. 'be created from a real file');
  34638. }
  34639. // {{{ Create the package file list
  34640. $filelist = array();
  34641. $i = 0;
  34642. foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
  34643. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  34644. if (!file_exists($file)) {
  34645. return PEAR::raiseError("File does not exist: $fname");
  34646. } else {
  34647. $filelist[$i++] = $file;
  34648. if (!isset($atts['md5sum'])) {
  34649. $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
  34650. }
  34651. $packager->log(2, "Adding file $fname");
  34652. }
  34653. }
  34654. // }}}
  34655. $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
  34656. if ($packagexml) {
  34657. $tar = new Archive_Tar($dest_package, $compress);
  34658. $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
  34659. // ----- Creates with the package.xml file
  34660. $ok = $tar->createModify(array($packagexml), '', $where);
  34661. if (PEAR::isError($ok)) {
  34662. return $ok;
  34663. } elseif (!$ok) {
  34664. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
  34665. }
  34666. // ----- Add the content of the package
  34667. if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
  34668. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
  34669. }
  34670. return $dest_package;
  34671. }
  34672. }
  34673. /**
  34674. * @param string|null directory to place the package.xml in, or null for a temporary dir
  34675. * @param int one of the PEAR_VALIDATE_* constants
  34676. * @param string name of the generated file
  34677. * @param bool if true, then no analysis will be performed on role="php" files
  34678. * @return string|PEAR_Error path to the created file on success
  34679. */
  34680. function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
  34681. $nofilechecking = false)
  34682. {
  34683. if (!$this->_packagefile->validate($state, $nofilechecking)) {
  34684. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
  34685. null, null, null, $this->_packagefile->getValidationWarnings());
  34686. }
  34687. if ($where === null) {
  34688. if (!($where = System::mktemp(array('-d')))) {
  34689. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
  34690. }
  34691. } elseif (!@System::mkDir(array('-p', $where))) {
  34692. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
  34693. ' not be created');
  34694. }
  34695. $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
  34696. $np = @fopen($newpkgfile, 'wb');
  34697. if (!$np) {
  34698. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
  34699. "$name as $newpkgfile");
  34700. }
  34701. fwrite($np, $this->toXml($state, true));
  34702. fclose($np);
  34703. return $newpkgfile;
  34704. }
  34705. /**
  34706. * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
  34707. *
  34708. * @param string $string
  34709. * @return string
  34710. * @access private
  34711. */
  34712. function _fixXmlEncoding($string)
  34713. {
  34714. return strtr($string, array(
  34715. '&' => '&amp;',
  34716. '>' => '&gt;',
  34717. '<' => '&lt;',
  34718. '"' => '&quot;',
  34719. '\'' => '&apos;' ));
  34720. }
  34721. /**
  34722. * Return an XML document based on the package info (as returned
  34723. * by the PEAR_Common::infoFrom* methods).
  34724. *
  34725. * @return string XML data
  34726. */
  34727. function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
  34728. {
  34729. $this->_packagefile->setDate(date('Y-m-d'));
  34730. if (!$this->_packagefile->validate($state, $nofilevalidation)) {
  34731. return false;
  34732. }
  34733. $pkginfo = $this->_packagefile->getArray();
  34734. static $maint_map = array(
  34735. "handle" => "user",
  34736. "name" => "name",
  34737. "email" => "email",
  34738. "role" => "role",
  34739. );
  34740. $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
  34741. $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n";
  34742. $ret .= "<package version=\"1.0\" packagerversion=\"1.10.10\">\n" .
  34743. " <name>$pkginfo[package]</name>";
  34744. if (isset($pkginfo['extends'])) {
  34745. $ret .= "\n<extends>$pkginfo[extends]</extends>";
  34746. }
  34747. $ret .=
  34748. "\n <summary>".$this->_fixXmlEncoding($pkginfo['summary'])."</summary>\n" .
  34749. " <description>".trim($this->_fixXmlEncoding($pkginfo['description']))."\n </description>\n" .
  34750. " <maintainers>\n";
  34751. foreach ($pkginfo['maintainers'] as $maint) {
  34752. $ret .= " <maintainer>\n";
  34753. foreach ($maint_map as $idx => $elm) {
  34754. $ret .= " <$elm>";
  34755. $ret .= $this->_fixXmlEncoding($maint[$idx]);
  34756. $ret .= "</$elm>\n";
  34757. }
  34758. $ret .= " </maintainer>\n";
  34759. }
  34760. $ret .= " </maintainers>\n";
  34761. $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
  34762. if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
  34763. $ret .= " <changelog>\n";
  34764. foreach ($pkginfo['changelog'] as $oldrelease) {
  34765. $ret .= $this->_makeReleaseXml($oldrelease, true);
  34766. }
  34767. $ret .= " </changelog>\n";
  34768. }
  34769. $ret .= "</package>\n";
  34770. return $ret;
  34771. }
  34772. // }}}
  34773. // {{{ _makeReleaseXml()
  34774. /**
  34775. * Generate part of an XML description with release information.
  34776. *
  34777. * @param array $pkginfo array with release information
  34778. * @param bool $changelog whether the result will be in a changelog element
  34779. *
  34780. * @return string XML data
  34781. *
  34782. * @access private
  34783. */
  34784. function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
  34785. {
  34786. // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
  34787. $indent = $changelog ? " " : "";
  34788. $ret = "$indent <release>\n";
  34789. if (!empty($pkginfo['version'])) {
  34790. $ret .= "$indent <version>$pkginfo[version]</version>\n";
  34791. }
  34792. if (!empty($pkginfo['release_date'])) {
  34793. $ret .= "$indent <date>$pkginfo[release_date]</date>\n";
  34794. }
  34795. if (!empty($pkginfo['release_license'])) {
  34796. $ret .= "$indent <license>$pkginfo[release_license]</license>\n";
  34797. }
  34798. if (!empty($pkginfo['release_state'])) {
  34799. $ret .= "$indent <state>$pkginfo[release_state]</state>\n";
  34800. }
  34801. if (!empty($pkginfo['release_notes'])) {
  34802. $ret .= "$indent <notes>".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
  34803. ."\n$indent </notes>\n";
  34804. }
  34805. if (!empty($pkginfo['release_warnings'])) {
  34806. $ret .= "$indent <warnings>".$this->_fixXmlEncoding($pkginfo['release_warnings'])."</warnings>\n";
  34807. }
  34808. if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
  34809. $ret .= "$indent <deps>\n";
  34810. foreach ($pkginfo['release_deps'] as $dep) {
  34811. $ret .= "$indent <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
  34812. if (isset($dep['version'])) {
  34813. $ret .= " version=\"$dep[version]\"";
  34814. }
  34815. if (isset($dep['optional'])) {
  34816. $ret .= " optional=\"$dep[optional]\"";
  34817. }
  34818. if (isset($dep['name'])) {
  34819. $ret .= ">$dep[name]</dep>\n";
  34820. } else {
  34821. $ret .= "/>\n";
  34822. }
  34823. }
  34824. $ret .= "$indent </deps>\n";
  34825. }
  34826. if (isset($pkginfo['configure_options'])) {
  34827. $ret .= "$indent <configureoptions>\n";
  34828. foreach ($pkginfo['configure_options'] as $c) {
  34829. $ret .= "$indent <configureoption name=\"".
  34830. $this->_fixXmlEncoding($c['name']) . "\"";
  34831. if (isset($c['default'])) {
  34832. $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
  34833. }
  34834. $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
  34835. $ret .= "/>\n";
  34836. }
  34837. $ret .= "$indent </configureoptions>\n";
  34838. }
  34839. if (isset($pkginfo['provides'])) {
  34840. foreach ($pkginfo['provides'] as $key => $what) {
  34841. $ret .= "$indent <provides type=\"$what[type]\" ";
  34842. $ret .= "name=\"$what[name]\" ";
  34843. if (isset($what['extends'])) {
  34844. $ret .= "extends=\"$what[extends]\" ";
  34845. }
  34846. $ret .= "/>\n";
  34847. }
  34848. }
  34849. if (isset($pkginfo['filelist'])) {
  34850. $ret .= "$indent <filelist>\n";
  34851. if ($state ^ PEAR_VALIDATE_PACKAGING) {
  34852. $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']);
  34853. } else {
  34854. foreach ($pkginfo['filelist'] as $file => $fa) {
  34855. if (!isset($fa['role'])) {
  34856. $fa['role'] = '';
  34857. }
  34858. $ret .= "$indent <file role=\"$fa[role]\"";
  34859. if (isset($fa['baseinstalldir'])) {
  34860. $ret .= ' baseinstalldir="' .
  34861. $this->_fixXmlEncoding($fa['baseinstalldir']) . '"';
  34862. }
  34863. if (isset($fa['md5sum'])) {
  34864. $ret .= " md5sum=\"$fa[md5sum]\"";
  34865. }
  34866. if (isset($fa['platform'])) {
  34867. $ret .= " platform=\"$fa[platform]\"";
  34868. }
  34869. if (!empty($fa['install-as'])) {
  34870. $ret .= ' install-as="' .
  34871. $this->_fixXmlEncoding($fa['install-as']) . '"';
  34872. }
  34873. $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
  34874. if (empty($fa['replacements'])) {
  34875. $ret .= "/>\n";
  34876. } else {
  34877. $ret .= ">\n";
  34878. foreach ($fa['replacements'] as $r) {
  34879. $ret .= "$indent <replace";
  34880. foreach ($r as $k => $v) {
  34881. $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
  34882. }
  34883. $ret .= "/>\n";
  34884. }
  34885. $ret .= "$indent </file>\n";
  34886. }
  34887. }
  34888. }
  34889. $ret .= "$indent </filelist>\n";
  34890. }
  34891. $ret .= "$indent </release>\n";
  34892. return $ret;
  34893. }
  34894. /**
  34895. * @param array
  34896. * @access protected
  34897. */
  34898. function recursiveXmlFilelist($list)
  34899. {
  34900. $this->_dirs = array();
  34901. foreach ($list as $file => $attributes) {
  34902. $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
  34903. }
  34904. return $this->_formatDir($this->_dirs);
  34905. }
  34906. /**
  34907. * @param array
  34908. * @param array
  34909. * @param string|null
  34910. * @param array|null
  34911. * @access private
  34912. */
  34913. function _addDir(&$dirs, $dir, $file = null, $attributes = null)
  34914. {
  34915. if ($dir == array() || $dir == array('.')) {
  34916. $dirs['files'][basename($file)] = $attributes;
  34917. return;
  34918. }
  34919. $curdir = array_shift($dir);
  34920. if (!isset($dirs['dirs'][$curdir])) {
  34921. $dirs['dirs'][$curdir] = array();
  34922. }
  34923. $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
  34924. }
  34925. /**
  34926. * @param array
  34927. * @param string
  34928. * @param string
  34929. * @access private
  34930. */
  34931. function _formatDir($dirs, $indent = '', $curdir = '')
  34932. {
  34933. $ret = '';
  34934. if (!count($dirs)) {
  34935. return '';
  34936. }
  34937. if (isset($dirs['dirs'])) {
  34938. uksort($dirs['dirs'], 'strnatcasecmp');
  34939. foreach ($dirs['dirs'] as $dir => $contents) {
  34940. $usedir = "$curdir/$dir";
  34941. $ret .= "$indent <dir name=\"$dir\">\n";
  34942. $ret .= $this->_formatDir($contents, "$indent ", $usedir);
  34943. $ret .= "$indent </dir> <!-- $usedir -->\n";
  34944. }
  34945. }
  34946. if (isset($dirs['files'])) {
  34947. uksort($dirs['files'], 'strnatcasecmp');
  34948. foreach ($dirs['files'] as $file => $attribs) {
  34949. $ret .= $this->_formatFile($file, $attribs, $indent);
  34950. }
  34951. }
  34952. return $ret;
  34953. }
  34954. /**
  34955. * @param string
  34956. * @param array
  34957. * @param string
  34958. * @access private
  34959. */
  34960. function _formatFile($file, $attributes, $indent)
  34961. {
  34962. $ret = "$indent <file role=\"$attributes[role]\"";
  34963. if (isset($attributes['baseinstalldir'])) {
  34964. $ret .= ' baseinstalldir="' .
  34965. $this->_fixXmlEncoding($attributes['baseinstalldir']) . '"';
  34966. }
  34967. if (isset($attributes['md5sum'])) {
  34968. $ret .= " md5sum=\"$attributes[md5sum]\"";
  34969. }
  34970. if (isset($attributes['platform'])) {
  34971. $ret .= " platform=\"$attributes[platform]\"";
  34972. }
  34973. if (!empty($attributes['install-as'])) {
  34974. $ret .= ' install-as="' .
  34975. $this->_fixXmlEncoding($attributes['install-as']) . '"';
  34976. }
  34977. $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
  34978. if (empty($attributes['replacements'])) {
  34979. $ret .= "/>\n";
  34980. } else {
  34981. $ret .= ">\n";
  34982. foreach ($attributes['replacements'] as $r) {
  34983. $ret .= "$indent <replace";
  34984. foreach ($r as $k => $v) {
  34985. $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
  34986. }
  34987. $ret .= "/>\n";
  34988. }
  34989. $ret .= "$indent </file>\n";
  34990. }
  34991. return $ret;
  34992. }
  34993. // {{{ _unIndent()
  34994. /**
  34995. * Unindent given string (?)
  34996. *
  34997. * @param string $str The string that has to be unindented.
  34998. * @return string
  34999. * @access private
  35000. */
  35001. function _unIndent($str)
  35002. {
  35003. // remove leading newlines
  35004. $str = preg_replace('/^[\r\n]+/', '', $str);
  35005. // find whitespace at the beginning of the first line
  35006. $indent_len = strspn($str, " \t");
  35007. $indent = substr($str, 0, $indent_len);
  35008. $data = '';
  35009. // remove the same amount of whitespace from following lines
  35010. foreach (explode("\n", $str) as $line) {
  35011. if (substr($line, 0, $indent_len) == $indent) {
  35012. $data .= substr($line, $indent_len) . "\n";
  35013. }
  35014. }
  35015. return $data;
  35016. }
  35017. /**
  35018. * @return array
  35019. */
  35020. function dependenciesToV2()
  35021. {
  35022. $arr = array();
  35023. $this->_convertDependencies2_0($arr);
  35024. return $arr['dependencies'];
  35025. }
  35026. /**
  35027. * Convert a package.xml version 1.0 into version 2.0
  35028. *
  35029. * Note that this does a basic conversion, to allow more advanced
  35030. * features like bundles and multiple releases
  35031. * @param string the classname to instantiate and return. This must be
  35032. * PEAR_PackageFile_v2 or a descendant
  35033. * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
  35034. * strictest parameters will be converted
  35035. * @return PEAR_PackageFile_v2|PEAR_Error
  35036. */
  35037. function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
  35038. {
  35039. if ($strict) {
  35040. if (!$this->_packagefile->validate()) {
  35041. $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
  35042. ' to version 2.0', null, null, null,
  35043. $this->_packagefile->getValidationWarnings(true));
  35044. return $a;
  35045. }
  35046. }
  35047. $arr = array(
  35048. 'attribs' => array(
  35049. 'version' => '2.0',
  35050. 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
  35051. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  35052. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  35053. 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
  35054. "http://pear.php.net/dtd/tasks-1.0.xsd\n" .
  35055. "http://pear.php.net/dtd/package-2.0\n" .
  35056. 'http://pear.php.net/dtd/package-2.0.xsd',
  35057. ),
  35058. 'name' => $this->_packagefile->getPackage(),
  35059. 'channel' => 'pear.php.net',
  35060. );
  35061. $arr['summary'] = $this->_packagefile->getSummary();
  35062. $arr['description'] = $this->_packagefile->getDescription();
  35063. $maintainers = $this->_packagefile->getMaintainers();
  35064. foreach ($maintainers as $maintainer) {
  35065. if ($maintainer['role'] != 'lead') {
  35066. continue;
  35067. }
  35068. $new = array(
  35069. 'name' => $maintainer['name'],
  35070. 'user' => $maintainer['handle'],
  35071. 'email' => $maintainer['email'],
  35072. 'active' => 'yes',
  35073. );
  35074. $arr['lead'][] = $new;
  35075. }
  35076. if (!isset($arr['lead'])) { // some people... you know?
  35077. $arr['lead'] = array(
  35078. 'name' => 'unknown',
  35079. 'user' => 'unknown',
  35080. 'email' => 'noleadmaintainer@example.com',
  35081. 'active' => 'no',
  35082. );
  35083. }
  35084. if (count($arr['lead']) == 1) {
  35085. $arr['lead'] = $arr['lead'][0];
  35086. }
  35087. foreach ($maintainers as $maintainer) {
  35088. if ($maintainer['role'] == 'lead') {
  35089. continue;
  35090. }
  35091. $new = array(
  35092. 'name' => $maintainer['name'],
  35093. 'user' => $maintainer['handle'],
  35094. 'email' => $maintainer['email'],
  35095. 'active' => 'yes',
  35096. );
  35097. $arr[$maintainer['role']][] = $new;
  35098. }
  35099. if (isset($arr['developer']) && count($arr['developer']) == 1) {
  35100. $arr['developer'] = $arr['developer'][0];
  35101. }
  35102. if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
  35103. $arr['contributor'] = $arr['contributor'][0];
  35104. }
  35105. if (isset($arr['helper']) && count($arr['helper']) == 1) {
  35106. $arr['helper'] = $arr['helper'][0];
  35107. }
  35108. $arr['date'] = $this->_packagefile->getDate();
  35109. $arr['version'] =
  35110. array(
  35111. 'release' => $this->_packagefile->getVersion(),
  35112. 'api' => $this->_packagefile->getVersion(),
  35113. );
  35114. $arr['stability'] =
  35115. array(
  35116. 'release' => $this->_packagefile->getState(),
  35117. 'api' => $this->_packagefile->getState(),
  35118. );
  35119. $licensemap =
  35120. array(
  35121. 'php' => 'http://www.php.net/license',
  35122. 'php license' => 'http://www.php.net/license',
  35123. 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
  35124. 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
  35125. 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
  35126. 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
  35127. 'mit' => 'http://www.opensource.org/licenses/mit-license.php',
  35128. 'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
  35129. 'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
  35130. );
  35131. if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
  35132. $arr['license'] = array(
  35133. 'attribs' => array('uri' =>
  35134. $licensemap[strtolower($this->_packagefile->getLicense())]),
  35135. '_content' => $this->_packagefile->getLicense()
  35136. );
  35137. } else {
  35138. // don't use bogus uri
  35139. $arr['license'] = $this->_packagefile->getLicense();
  35140. }
  35141. $arr['notes'] = $this->_packagefile->getNotes();
  35142. $temp = array();
  35143. $arr['contents'] = $this->_convertFilelist2_0($temp);
  35144. $this->_convertDependencies2_0($arr);
  35145. $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
  35146. 'extsrcrelease' : 'phprelease';
  35147. if ($release == 'extsrcrelease') {
  35148. $arr['channel'] = 'pecl.php.net';
  35149. $arr['providesextension'] = $arr['name']; // assumption
  35150. }
  35151. $arr[$release] = array();
  35152. if ($this->_packagefile->getConfigureOptions()) {
  35153. $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
  35154. foreach ($arr[$release]['configureoption'] as $i => $opt) {
  35155. $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
  35156. }
  35157. if (count($arr[$release]['configureoption']) == 1) {
  35158. $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
  35159. }
  35160. }
  35161. $this->_convertRelease2_0($arr[$release], $temp);
  35162. if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
  35163. // multiple extsrcrelease tags added in PEAR 1.4.1
  35164. $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
  35165. }
  35166. if ($cl = $this->_packagefile->getChangelog()) {
  35167. foreach ($cl as $release) {
  35168. $rel = array();
  35169. $rel['version'] =
  35170. array(
  35171. 'release' => $release['version'],
  35172. 'api' => $release['version'],
  35173. );
  35174. if (!isset($release['release_state'])) {
  35175. $release['release_state'] = 'stable';
  35176. }
  35177. $rel['stability'] =
  35178. array(
  35179. 'release' => $release['release_state'],
  35180. 'api' => $release['release_state'],
  35181. );
  35182. if (isset($release['release_date'])) {
  35183. $rel['date'] = $release['release_date'];
  35184. } else {
  35185. $rel['date'] = date('Y-m-d');
  35186. }
  35187. if (isset($release['release_license'])) {
  35188. if (isset($licensemap[strtolower($release['release_license'])])) {
  35189. $uri = $licensemap[strtolower($release['release_license'])];
  35190. } else {
  35191. $uri = 'http://www.example.com';
  35192. }
  35193. $rel['license'] = array(
  35194. 'attribs' => array('uri' => $uri),
  35195. '_content' => $release['release_license']
  35196. );
  35197. } else {
  35198. $rel['license'] = $arr['license'];
  35199. }
  35200. if (!isset($release['release_notes'])) {
  35201. $release['release_notes'] = 'no release notes';
  35202. }
  35203. $rel['notes'] = $release['release_notes'];
  35204. $arr['changelog']['release'][] = $rel;
  35205. }
  35206. }
  35207. $ret = new $class;
  35208. $ret->setConfig($this->_packagefile->_config);
  35209. if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) {
  35210. $ret->setLogger($this->_packagefile->_logger);
  35211. }
  35212. $ret->fromArray($arr);
  35213. return $ret;
  35214. }
  35215. /**
  35216. * @param array
  35217. * @param bool
  35218. * @access private
  35219. */
  35220. function _convertDependencies2_0(&$release, $internal = false)
  35221. {
  35222. $peardep = array('pearinstaller' =>
  35223. array('min' => '1.4.0b1')); // this is a lot safer
  35224. $required = $optional = array();
  35225. $release['dependencies'] = array('required' => array());
  35226. if ($this->_packagefile->hasDeps()) {
  35227. foreach ($this->_packagefile->getDeps() as $dep) {
  35228. if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  35229. $required[] = $dep;
  35230. } else {
  35231. $optional[] = $dep;
  35232. }
  35233. }
  35234. foreach (array('required', 'optional') as $arr) {
  35235. $deps = array();
  35236. foreach ($$arr as $dep) {
  35237. // organize deps by dependency type and name
  35238. if (!isset($deps[$dep['type']])) {
  35239. $deps[$dep['type']] = array();
  35240. }
  35241. if (isset($dep['name'])) {
  35242. $deps[$dep['type']][$dep['name']][] = $dep;
  35243. } else {
  35244. $deps[$dep['type']][] = $dep;
  35245. }
  35246. }
  35247. do {
  35248. if (isset($deps['php'])) {
  35249. $php = array();
  35250. if (count($deps['php']) > 1) {
  35251. $php = $this->_processPhpDeps($deps['php']);
  35252. } else {
  35253. if (!isset($deps['php'][0])) {
  35254. // Buggy versions
  35255. $key = key($deps['php']);
  35256. $info = current($deps['php']);
  35257. $deps['php'] = array($info[0]);
  35258. }
  35259. $php = $this->_processDep($deps['php'][0]);
  35260. if (!$php) {
  35261. break; // poor mans throw
  35262. }
  35263. }
  35264. $release['dependencies'][$arr]['php'] = $php;
  35265. }
  35266. } while (false);
  35267. do {
  35268. if (isset($deps['pkg'])) {
  35269. $pkg = array();
  35270. $pkg = $this->_processMultipleDepsName($deps['pkg']);
  35271. if (!$pkg) {
  35272. break; // poor mans throw
  35273. }
  35274. $release['dependencies'][$arr]['package'] = $pkg;
  35275. }
  35276. } while (false);
  35277. do {
  35278. if (isset($deps['ext'])) {
  35279. $pkg = array();
  35280. $pkg = $this->_processMultipleDepsName($deps['ext']);
  35281. $release['dependencies'][$arr]['extension'] = $pkg;
  35282. }
  35283. } while (false);
  35284. // skip sapi - it's not supported so nobody will have used it
  35285. // skip os - it's not supported in 1.0
  35286. }
  35287. }
  35288. if (isset($release['dependencies']['required'])) {
  35289. $release['dependencies']['required'] =
  35290. array_merge($peardep, $release['dependencies']['required']);
  35291. } else {
  35292. $release['dependencies']['required'] = $peardep;
  35293. }
  35294. if (!isset($release['dependencies']['required']['php'])) {
  35295. $release['dependencies']['required']['php'] =
  35296. array('min' => '4.0.0');
  35297. }
  35298. $order = array();
  35299. $bewm = $release['dependencies']['required'];
  35300. $order['php'] = $bewm['php'];
  35301. $order['pearinstaller'] = $bewm['pearinstaller'];
  35302. isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
  35303. isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
  35304. $release['dependencies']['required'] = $order;
  35305. }
  35306. /**
  35307. * @param array
  35308. * @access private
  35309. */
  35310. function _convertFilelist2_0(&$package)
  35311. {
  35312. $ret = array('dir' =>
  35313. array(
  35314. 'attribs' => array('name' => '/'),
  35315. 'file' => array()
  35316. )
  35317. );
  35318. $package['platform'] =
  35319. $package['install-as'] = array();
  35320. $this->_isExtension = false;
  35321. foreach ($this->_packagefile->getFilelist() as $name => $file) {
  35322. $file['name'] = $name;
  35323. if (isset($file['role']) && $file['role'] == 'src') {
  35324. $this->_isExtension = true;
  35325. }
  35326. if (isset($file['replacements'])) {
  35327. $repl = $file['replacements'];
  35328. unset($file['replacements']);
  35329. } else {
  35330. unset($repl);
  35331. }
  35332. if (isset($file['install-as'])) {
  35333. $package['install-as'][$name] = $file['install-as'];
  35334. unset($file['install-as']);
  35335. }
  35336. if (isset($file['platform'])) {
  35337. $package['platform'][$name] = $file['platform'];
  35338. unset($file['platform']);
  35339. }
  35340. $file = array('attribs' => $file);
  35341. if (isset($repl)) {
  35342. foreach ($repl as $replace ) {
  35343. $file['tasks:replace'][] = array('attribs' => $replace);
  35344. }
  35345. if (count($repl) == 1) {
  35346. $file['tasks:replace'] = $file['tasks:replace'][0];
  35347. }
  35348. }
  35349. $ret['dir']['file'][] = $file;
  35350. }
  35351. return $ret;
  35352. }
  35353. /**
  35354. * Post-process special files with install-as/platform attributes and
  35355. * make the release tag.
  35356. *
  35357. * This complex method follows this work-flow to create the release tags:
  35358. *
  35359. * <pre>
  35360. * - if any install-as/platform exist, create a generic release and fill it with
  35361. * o <install as=..> tags for <file name=... install-as=...>
  35362. * o <install as=..> tags for <file name=... platform=!... install-as=..>
  35363. * o <ignore> tags for <file name=... platform=...>
  35364. * o <ignore> tags for <file name=... platform=... install-as=..>
  35365. * - create a release for each platform encountered and fill with
  35366. * o <install as..> tags for <file name=... install-as=...>
  35367. * o <install as..> tags for <file name=... platform=this platform install-as=..>
  35368. * o <install as..> tags for <file name=... platform=!other platform install-as=..>
  35369. * o <ignore> tags for <file name=... platform=!this platform>
  35370. * o <ignore> tags for <file name=... platform=other platform>
  35371. * o <ignore> tags for <file name=... platform=other platform install-as=..>
  35372. * o <ignore> tags for <file name=... platform=!this platform install-as=..>
  35373. * </pre>
  35374. *
  35375. * It does this by accessing the $package parameter, which contains an array with
  35376. * indices:
  35377. *
  35378. * - platform: mapping of file => OS the file should be installed on
  35379. * - install-as: mapping of file => installed name
  35380. * - osmap: mapping of OS => list of files that should be installed
  35381. * on that OS
  35382. * - notosmap: mapping of OS => list of files that should not be
  35383. * installed on that OS
  35384. *
  35385. * @param array
  35386. * @param array
  35387. * @access private
  35388. */
  35389. function _convertRelease2_0(&$release, $package)
  35390. {
  35391. //- if any install-as/platform exist, create a generic release and fill it with
  35392. if (count($package['platform']) || count($package['install-as'])) {
  35393. $generic = array();
  35394. $genericIgnore = array();
  35395. foreach ($package['install-as'] as $file => $as) {
  35396. //o <install as=..> tags for <file name=... install-as=...>
  35397. if (!isset($package['platform'][$file])) {
  35398. $generic[] = $file;
  35399. continue;
  35400. }
  35401. //o <install as=..> tags for <file name=... platform=!... install-as=..>
  35402. if (isset($package['platform'][$file]) &&
  35403. $package['platform'][$file][0] == '!') {
  35404. $generic[] = $file;
  35405. continue;
  35406. }
  35407. //o <ignore> tags for <file name=... platform=... install-as=..>
  35408. if (isset($package['platform'][$file]) &&
  35409. $package['platform'][$file][0] != '!') {
  35410. $genericIgnore[] = $file;
  35411. continue;
  35412. }
  35413. }
  35414. foreach ($package['platform'] as $file => $platform) {
  35415. if (isset($package['install-as'][$file])) {
  35416. continue;
  35417. }
  35418. if ($platform[0] != '!') {
  35419. //o <ignore> tags for <file name=... platform=...>
  35420. $genericIgnore[] = $file;
  35421. }
  35422. }
  35423. if (count($package['platform'])) {
  35424. $oses = $notplatform = $platform = array();
  35425. foreach ($package['platform'] as $file => $os) {
  35426. // get a list of oses
  35427. if ($os[0] == '!') {
  35428. if (isset($oses[substr($os, 1)])) {
  35429. continue;
  35430. }
  35431. $oses[substr($os, 1)] = count($oses);
  35432. } else {
  35433. if (isset($oses[$os])) {
  35434. continue;
  35435. }
  35436. $oses[$os] = count($oses);
  35437. }
  35438. }
  35439. //- create a release for each platform encountered and fill with
  35440. foreach ($oses as $os => $releaseNum) {
  35441. $release[$releaseNum]['installconditions']['os']['name'] = $os;
  35442. $release[$releaseNum]['filelist'] = array('install' => array(),
  35443. 'ignore' => array());
  35444. foreach ($package['install-as'] as $file => $as) {
  35445. //o <install as=..> tags for <file name=... install-as=...>
  35446. if (!isset($package['platform'][$file])) {
  35447. $release[$releaseNum]['filelist']['install'][] =
  35448. array(
  35449. 'attribs' => array(
  35450. 'name' => $file,
  35451. 'as' => $as,
  35452. ),
  35453. );
  35454. continue;
  35455. }
  35456. //o <install as..> tags for
  35457. // <file name=... platform=this platform install-as=..>
  35458. if (isset($package['platform'][$file]) &&
  35459. $package['platform'][$file] == $os) {
  35460. $release[$releaseNum]['filelist']['install'][] =
  35461. array(
  35462. 'attribs' => array(
  35463. 'name' => $file,
  35464. 'as' => $as,
  35465. ),
  35466. );
  35467. continue;
  35468. }
  35469. //o <install as..> tags for
  35470. // <file name=... platform=!other platform install-as=..>
  35471. if (isset($package['platform'][$file]) &&
  35472. $package['platform'][$file] != "!$os" &&
  35473. $package['platform'][$file][0] == '!') {
  35474. $release[$releaseNum]['filelist']['install'][] =
  35475. array(
  35476. 'attribs' => array(
  35477. 'name' => $file,
  35478. 'as' => $as,
  35479. ),
  35480. );
  35481. continue;
  35482. }
  35483. //o <ignore> tags for
  35484. // <file name=... platform=!this platform install-as=..>
  35485. if (isset($package['platform'][$file]) &&
  35486. $package['platform'][$file] == "!$os") {
  35487. $release[$releaseNum]['filelist']['ignore'][] =
  35488. array(
  35489. 'attribs' => array(
  35490. 'name' => $file,
  35491. ),
  35492. );
  35493. continue;
  35494. }
  35495. //o <ignore> tags for
  35496. // <file name=... platform=other platform install-as=..>
  35497. if (isset($package['platform'][$file]) &&
  35498. $package['platform'][$file][0] != '!' &&
  35499. $package['platform'][$file] != $os) {
  35500. $release[$releaseNum]['filelist']['ignore'][] =
  35501. array(
  35502. 'attribs' => array(
  35503. 'name' => $file,
  35504. ),
  35505. );
  35506. continue;
  35507. }
  35508. }
  35509. foreach ($package['platform'] as $file => $platform) {
  35510. if (isset($package['install-as'][$file])) {
  35511. continue;
  35512. }
  35513. //o <ignore> tags for <file name=... platform=!this platform>
  35514. if ($platform == "!$os") {
  35515. $release[$releaseNum]['filelist']['ignore'][] =
  35516. array(
  35517. 'attribs' => array(
  35518. 'name' => $file,
  35519. ),
  35520. );
  35521. continue;
  35522. }
  35523. //o <ignore> tags for <file name=... platform=other platform>
  35524. if ($platform[0] != '!' && $platform != $os) {
  35525. $release[$releaseNum]['filelist']['ignore'][] =
  35526. array(
  35527. 'attribs' => array(
  35528. 'name' => $file,
  35529. ),
  35530. );
  35531. }
  35532. }
  35533. if (!count($release[$releaseNum]['filelist']['install'])) {
  35534. unset($release[$releaseNum]['filelist']['install']);
  35535. }
  35536. if (!count($release[$releaseNum]['filelist']['ignore'])) {
  35537. unset($release[$releaseNum]['filelist']['ignore']);
  35538. }
  35539. }
  35540. if (count($generic) || count($genericIgnore)) {
  35541. $release[count($oses)] = array();
  35542. if (count($generic)) {
  35543. foreach ($generic as $file) {
  35544. if (isset($package['install-as'][$file])) {
  35545. $installas = $package['install-as'][$file];
  35546. } else {
  35547. $installas = $file;
  35548. }
  35549. $release[count($oses)]['filelist']['install'][] =
  35550. array(
  35551. 'attribs' => array(
  35552. 'name' => $file,
  35553. 'as' => $installas,
  35554. )
  35555. );
  35556. }
  35557. }
  35558. if (count($genericIgnore)) {
  35559. foreach ($genericIgnore as $file) {
  35560. $release[count($oses)]['filelist']['ignore'][] =
  35561. array(
  35562. 'attribs' => array(
  35563. 'name' => $file,
  35564. )
  35565. );
  35566. }
  35567. }
  35568. }
  35569. // cleanup
  35570. foreach ($release as $i => $rel) {
  35571. if (isset($rel['filelist']['install']) &&
  35572. count($rel['filelist']['install']) == 1) {
  35573. $release[$i]['filelist']['install'] =
  35574. $release[$i]['filelist']['install'][0];
  35575. }
  35576. if (isset($rel['filelist']['ignore']) &&
  35577. count($rel['filelist']['ignore']) == 1) {
  35578. $release[$i]['filelist']['ignore'] =
  35579. $release[$i]['filelist']['ignore'][0];
  35580. }
  35581. }
  35582. if (count($release) == 1) {
  35583. $release = $release[0];
  35584. }
  35585. } else {
  35586. // no platform atts, but some install-as atts
  35587. foreach ($package['install-as'] as $file => $value) {
  35588. $release['filelist']['install'][] =
  35589. array(
  35590. 'attribs' => array(
  35591. 'name' => $file,
  35592. 'as' => $value
  35593. )
  35594. );
  35595. }
  35596. if (count($release['filelist']['install']) == 1) {
  35597. $release['filelist']['install'] = $release['filelist']['install'][0];
  35598. }
  35599. }
  35600. }
  35601. }
  35602. /**
  35603. * @param array
  35604. * @return array
  35605. * @access private
  35606. */
  35607. function _processDep($dep)
  35608. {
  35609. if ($dep['type'] == 'php') {
  35610. if ($dep['rel'] == 'has') {
  35611. // come on - everyone has php!
  35612. return false;
  35613. }
  35614. }
  35615. $php = array();
  35616. if ($dep['type'] != 'php') {
  35617. $php['name'] = $dep['name'];
  35618. if ($dep['type'] == 'pkg') {
  35619. $php['channel'] = 'pear.php.net';
  35620. }
  35621. }
  35622. switch ($dep['rel']) {
  35623. case 'gt' :
  35624. $php['min'] = $dep['version'];
  35625. $php['exclude'] = $dep['version'];
  35626. break;
  35627. case 'ge' :
  35628. if (!isset($dep['version'])) {
  35629. if ($dep['type'] == 'php') {
  35630. if (isset($dep['name'])) {
  35631. $dep['version'] = $dep['name'];
  35632. }
  35633. }
  35634. }
  35635. $php['min'] = $dep['version'];
  35636. break;
  35637. case 'lt' :
  35638. $php['max'] = $dep['version'];
  35639. $php['exclude'] = $dep['version'];
  35640. break;
  35641. case 'le' :
  35642. $php['max'] = $dep['version'];
  35643. break;
  35644. case 'eq' :
  35645. $php['min'] = $dep['version'];
  35646. $php['max'] = $dep['version'];
  35647. break;
  35648. case 'ne' :
  35649. $php['exclude'] = $dep['version'];
  35650. break;
  35651. case 'not' :
  35652. $php['conflicts'] = 'yes';
  35653. break;
  35654. }
  35655. return $php;
  35656. }
  35657. /**
  35658. * @param array
  35659. * @return array
  35660. */
  35661. function _processPhpDeps($deps)
  35662. {
  35663. $test = array();
  35664. foreach ($deps as $dep) {
  35665. $test[] = $this->_processDep($dep);
  35666. }
  35667. $min = array();
  35668. $max = array();
  35669. foreach ($test as $dep) {
  35670. if (!$dep) {
  35671. continue;
  35672. }
  35673. if (isset($dep['min'])) {
  35674. $min[$dep['min']] = count($min);
  35675. }
  35676. if (isset($dep['max'])) {
  35677. $max[$dep['max']] = count($max);
  35678. }
  35679. }
  35680. if (count($min) > 0) {
  35681. uksort($min, 'version_compare');
  35682. }
  35683. if (count($max) > 0) {
  35684. uksort($max, 'version_compare');
  35685. }
  35686. if (count($min)) {
  35687. // get the highest minimum
  35688. $a = array_flip($min);
  35689. $min = array_pop($a);
  35690. } else {
  35691. $min = false;
  35692. }
  35693. if (count($max)) {
  35694. // get the lowest maximum
  35695. $a = array_flip($max);
  35696. $max = array_shift($a);
  35697. } else {
  35698. $max = false;
  35699. }
  35700. if ($min) {
  35701. $php['min'] = $min;
  35702. }
  35703. if ($max) {
  35704. $php['max'] = $max;
  35705. }
  35706. $exclude = array();
  35707. foreach ($test as $dep) {
  35708. if (!isset($dep['exclude'])) {
  35709. continue;
  35710. }
  35711. $exclude[] = $dep['exclude'];
  35712. }
  35713. if (count($exclude)) {
  35714. $php['exclude'] = $exclude;
  35715. }
  35716. return $php;
  35717. }
  35718. /**
  35719. * process multiple dependencies that have a name, like package deps
  35720. * @param array
  35721. * @return array
  35722. * @access private
  35723. */
  35724. function _processMultipleDepsName($deps)
  35725. {
  35726. $ret = $tests = array();
  35727. foreach ($deps as $name => $dep) {
  35728. foreach ($dep as $d) {
  35729. $tests[$name][] = $this->_processDep($d);
  35730. }
  35731. }
  35732. foreach ($tests as $name => $test) {
  35733. $max = $min = $php = array();
  35734. $php['name'] = $name;
  35735. foreach ($test as $dep) {
  35736. if (!$dep) {
  35737. continue;
  35738. }
  35739. if (isset($dep['channel'])) {
  35740. $php['channel'] = 'pear.php.net';
  35741. }
  35742. if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
  35743. $php['conflicts'] = 'yes';
  35744. }
  35745. if (isset($dep['min'])) {
  35746. $min[$dep['min']] = count($min);
  35747. }
  35748. if (isset($dep['max'])) {
  35749. $max[$dep['max']] = count($max);
  35750. }
  35751. }
  35752. if (count($min) > 0) {
  35753. uksort($min, 'version_compare');
  35754. }
  35755. if (count($max) > 0) {
  35756. uksort($max, 'version_compare');
  35757. }
  35758. if (count($min)) {
  35759. // get the highest minimum
  35760. $a = array_flip($min);
  35761. $min = array_pop($a);
  35762. } else {
  35763. $min = false;
  35764. }
  35765. if (count($max)) {
  35766. // get the lowest maximum
  35767. $a = array_flip($max);
  35768. $max = array_shift($a);
  35769. } else {
  35770. $max = false;
  35771. }
  35772. if ($min) {
  35773. $php['min'] = $min;
  35774. }
  35775. if ($max) {
  35776. $php['max'] = $max;
  35777. }
  35778. $exclude = array();
  35779. foreach ($test as $dep) {
  35780. if (!isset($dep['exclude'])) {
  35781. continue;
  35782. }
  35783. $exclude[] = $dep['exclude'];
  35784. }
  35785. if (count($exclude)) {
  35786. $php['exclude'] = $exclude;
  35787. }
  35788. $ret[] = $php;
  35789. }
  35790. return $ret;
  35791. }
  35792. }
  35793. ?>
  35794. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/Generator/v2.php������������������������������������������������������0000644�0001750�0001750�00000100711�13565304531�020126� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  35795. /**
  35796. * package.xml generation class, package.xml version 2.0
  35797. *
  35798. * PHP versions 4 and 5
  35799. *
  35800. * @category pear
  35801. * @package PEAR
  35802. * @author Greg Beaver <cellog@php.net>
  35803. * @author Stephan Schmidt (original XML_Serializer code)
  35804. * @copyright 1997-2009 The Authors
  35805. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  35806. * @link http://pear.php.net/package/PEAR
  35807. * @since File available since Release 1.4.0a1
  35808. */
  35809. /**
  35810. * file/dir manipulation routines
  35811. */
  35812. require_once 'System.php';
  35813. require_once 'XML/Util.php';
  35814. /**
  35815. * This class converts a PEAR_PackageFile_v2 object into any output format.
  35816. *
  35817. * Supported output formats include array, XML string (using S. Schmidt's
  35818. * XML_Serializer, slightly customized)
  35819. * @category pear
  35820. * @package PEAR
  35821. * @author Greg Beaver <cellog@php.net>
  35822. * @author Stephan Schmidt (original XML_Serializer code)
  35823. * @copyright 1997-2009 The Authors
  35824. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  35825. * @version Release: 1.10.10
  35826. * @link http://pear.php.net/package/PEAR
  35827. * @since Class available since Release 1.4.0a1
  35828. */
  35829. class PEAR_PackageFile_Generator_v2
  35830. {
  35831. /**
  35832. * default options for the serialization
  35833. * @access private
  35834. * @var array $_defaultOptions
  35835. */
  35836. var $_defaultOptions = array(
  35837. 'indent' => ' ', // string used for indentation
  35838. 'linebreak' => "\n", // string used for newlines
  35839. 'typeHints' => false, // automatically add type hin attributes
  35840. 'addDecl' => true, // add an XML declaration
  35841. 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
  35842. 'classAsTagName' => false, // use classname for objects in indexed arrays
  35843. 'keyAttribute' => '_originalKey', // attribute where original key is stored
  35844. 'typeAttribute' => '_type', // attribute for type (only if typeHints => true)
  35845. 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true)
  35846. 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute
  35847. 'prependAttributes' => '', // prepend string for attributes
  35848. 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
  35849. 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array
  35850. 'addDoctype' => false, // add a doctype declaration
  35851. 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
  35852. 'rootName' => 'package', // name of the root tag
  35853. 'rootAttributes' => array(
  35854. 'version' => '2.0',
  35855. 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
  35856. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  35857. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  35858. 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
  35859. http://pear.php.net/dtd/tasks-1.0.xsd
  35860. http://pear.php.net/dtd/package-2.0
  35861. http://pear.php.net/dtd/package-2.0.xsd',
  35862. ), // attributes of the root tag
  35863. 'attributesArray' => 'attribs', // all values in this key will be treated as attributes
  35864. 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjunction with attributesArray
  35865. 'beautifyFilelist' => false,
  35866. 'encoding' => 'UTF-8',
  35867. );
  35868. /**
  35869. * options for the serialization
  35870. * @access private
  35871. * @var array $options
  35872. */
  35873. var $options = array();
  35874. /**
  35875. * current tag depth
  35876. * @var integer $_tagDepth
  35877. */
  35878. var $_tagDepth = 0;
  35879. /**
  35880. * serilialized representation of the data
  35881. * @var string $_serializedData
  35882. */
  35883. var $_serializedData = null;
  35884. /**
  35885. * @var PEAR_PackageFile_v2
  35886. */
  35887. var $_packagefile;
  35888. /**
  35889. * @param PEAR_PackageFile_v2
  35890. */
  35891. function __construct(&$packagefile)
  35892. {
  35893. $this->_packagefile = &$packagefile;
  35894. if (isset($this->_packagefile->encoding)) {
  35895. $this->_defaultOptions['encoding'] = $this->_packagefile->encoding;
  35896. }
  35897. }
  35898. /**
  35899. * @return string
  35900. */
  35901. function getPackagerVersion()
  35902. {
  35903. return '1.10.10';
  35904. }
  35905. /**
  35906. * @param PEAR_Packager
  35907. * @param bool generate a .tgz or a .tar
  35908. * @param string|null temporary directory to package in
  35909. */
  35910. function toTgz(&$packager, $compress = true, $where = null)
  35911. {
  35912. $a = null;
  35913. return $this->toTgz2($packager, $a, $compress, $where);
  35914. }
  35915. /**
  35916. * Package up both a package.xml and package2.xml for the same release
  35917. * @param PEAR_Packager
  35918. * @param PEAR_PackageFile_v1
  35919. * @param bool generate a .tgz or a .tar
  35920. * @param string|null temporary directory to package in
  35921. */
  35922. function toTgz2(&$packager, &$pf1, $compress = true, $where = null)
  35923. {
  35924. require_once 'Archive/Tar.php';
  35925. if (!$this->_packagefile->isEquivalent($pf1)) {
  35926. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' .
  35927. basename($pf1->getPackageFile()) .
  35928. '" is not equivalent to "' . basename($this->_packagefile->getPackageFile())
  35929. . '"');
  35930. }
  35931. if ($where === null) {
  35932. if (!($where = System::mktemp(array('-d')))) {
  35933. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed');
  35934. }
  35935. } elseif (!@System::mkDir(array('-p', $where))) {
  35936. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
  35937. ' not be created');
  35938. }
  35939. $file = $where . DIRECTORY_SEPARATOR . 'package.xml';
  35940. if (file_exists($file) && !is_file($file)) {
  35941. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
  35942. ' "' . $file .'"');
  35943. }
  35944. if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
  35945. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
  35946. }
  35947. $ext = $compress ? '.tgz' : '.tar';
  35948. $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion();
  35949. $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
  35950. if (file_exists($dest_package) && !is_file($dest_package)) {
  35951. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
  35952. $dest_package . '"');
  35953. }
  35954. $pkgfile = $this->_packagefile->getPackageFile();
  35955. if (!$pkgfile) {
  35956. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
  35957. 'be created from a real file');
  35958. }
  35959. $pkgdir = dirname(realpath($pkgfile));
  35960. $pkgfile = basename($pkgfile);
  35961. // {{{ Create the package file list
  35962. $filelist = array();
  35963. $i = 0;
  35964. $this->_packagefile->flattenFilelist();
  35965. $contents = $this->_packagefile->getContents();
  35966. if (isset($contents['bundledpackage'])) { // bundles of packages
  35967. $contents = $contents['bundledpackage'];
  35968. if (!isset($contents[0])) {
  35969. $contents = array($contents);
  35970. }
  35971. $packageDir = $where;
  35972. foreach ($contents as $i => $package) {
  35973. $fname = $package;
  35974. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  35975. if (!file_exists($file)) {
  35976. return $packager->raiseError("File does not exist: $fname");
  35977. }
  35978. $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
  35979. System::mkdir(array('-p', dirname($tfile)));
  35980. copy($file, $tfile);
  35981. $filelist[$i++] = $tfile;
  35982. $packager->log(2, "Adding package $fname");
  35983. }
  35984. } else { // normal packages
  35985. $contents = $contents['dir']['file'];
  35986. if (!isset($contents[0])) {
  35987. $contents = array($contents);
  35988. }
  35989. $packageDir = $where;
  35990. foreach ($contents as $i => $file) {
  35991. $fname = $file['attribs']['name'];
  35992. $atts = $file['attribs'];
  35993. $orig = $file;
  35994. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  35995. if (!file_exists($file)) {
  35996. return $packager->raiseError("File does not exist: $fname");
  35997. }
  35998. $origperms = fileperms($file);
  35999. $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
  36000. unset($orig['attribs']);
  36001. if (count($orig)) { // file with tasks
  36002. // run any package-time tasks
  36003. $contents = file_get_contents($file);
  36004. foreach ($orig as $tag => $raw) {
  36005. $tag = str_replace(
  36006. array($this->_packagefile->getTasksNs() . ':', '-'),
  36007. array('', '_'), $tag);
  36008. $task = "PEAR_Task_$tag";
  36009. $task = new $task($this->_packagefile->_config,
  36010. $this->_packagefile->_logger,
  36011. PEAR_TASK_PACKAGE);
  36012. $task->init($raw, $atts, null);
  36013. $res = $task->startSession($this->_packagefile, $contents, $tfile);
  36014. if (!$res) {
  36015. continue; // skip this task
  36016. }
  36017. if (PEAR::isError($res)) {
  36018. return $res;
  36019. }
  36020. $contents = $res; // save changes
  36021. System::mkdir(array('-p', dirname($tfile)));
  36022. $wp = fopen($tfile, "wb");
  36023. fwrite($wp, $contents);
  36024. fclose($wp);
  36025. }
  36026. }
  36027. if (!file_exists($tfile)) {
  36028. System::mkdir(array('-p', dirname($tfile)));
  36029. copy($file, $tfile);
  36030. }
  36031. chmod($tfile, $origperms);
  36032. $filelist[$i++] = $tfile;
  36033. $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1);
  36034. $packager->log(2, "Adding file $fname");
  36035. }
  36036. }
  36037. // }}}
  36038. $name = $pf1 !== null ? 'package2.xml' : 'package.xml';
  36039. $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name);
  36040. if ($packagexml) {
  36041. $tar = new Archive_Tar($dest_package, $compress);
  36042. $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
  36043. // ----- Creates with the package.xml file
  36044. $ok = $tar->createModify(array($packagexml), '', $where);
  36045. if (PEAR::isError($ok)) {
  36046. return $packager->raiseError($ok);
  36047. } elseif (!$ok) {
  36048. return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
  36049. ' failed');
  36050. }
  36051. // ----- Add the content of the package
  36052. if (!$tar->addModify($filelist, $pkgver, $where)) {
  36053. return $packager->raiseError(
  36054. 'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
  36055. }
  36056. // add the package.xml version 1.0
  36057. if ($pf1 !== null) {
  36058. $pfgen = &$pf1->getDefaultGenerator();
  36059. $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
  36060. if (!$tar->addModify(array($packagexml1), '', $where)) {
  36061. return $packager->raiseError(
  36062. 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
  36063. }
  36064. }
  36065. return $dest_package;
  36066. }
  36067. }
  36068. function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml')
  36069. {
  36070. if (!$this->_packagefile->validate($state)) {
  36071. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
  36072. null, null, null, $this->_packagefile->getValidationWarnings());
  36073. }
  36074. if ($where === null) {
  36075. if (!($where = System::mktemp(array('-d')))) {
  36076. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
  36077. }
  36078. } elseif (!@System::mkDir(array('-p', $where))) {
  36079. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
  36080. ' not be created');
  36081. }
  36082. $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
  36083. $np = @fopen($newpkgfile, 'wb');
  36084. if (!$np) {
  36085. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
  36086. "$name as $newpkgfile");
  36087. }
  36088. fwrite($np, $this->toXml($state));
  36089. fclose($np);
  36090. return $newpkgfile;
  36091. }
  36092. function &toV2()
  36093. {
  36094. return $this->_packagefile;
  36095. }
  36096. /**
  36097. * Return an XML document based on the package info (as returned
  36098. * by the PEAR_Common::infoFrom* methods).
  36099. *
  36100. * @return string XML data
  36101. */
  36102. function toXml($state = PEAR_VALIDATE_NORMAL, $options = array())
  36103. {
  36104. $this->_packagefile->setDate(date('Y-m-d'));
  36105. $this->_packagefile->setTime(date('H:i:s'));
  36106. if (!$this->_packagefile->validate($state)) {
  36107. return false;
  36108. }
  36109. if (is_array($options)) {
  36110. $this->options = array_merge($this->_defaultOptions, $options);
  36111. } else {
  36112. $this->options = $this->_defaultOptions;
  36113. }
  36114. $arr = $this->_packagefile->getArray();
  36115. if (isset($arr['filelist'])) {
  36116. unset($arr['filelist']);
  36117. }
  36118. if (isset($arr['_lastversion'])) {
  36119. unset($arr['_lastversion']);
  36120. }
  36121. // Fix the notes a little bit
  36122. if (isset($arr['notes'])) {
  36123. // This trims out the indenting, needs fixing
  36124. $arr['notes'] = "\n" . trim($arr['notes']) . "\n";
  36125. }
  36126. if (isset($arr['changelog']) && !empty($arr['changelog'])) {
  36127. // Fix for inconsistency how the array is filled depending on the changelog release amount
  36128. if (!isset($arr['changelog']['release'][0])) {
  36129. $release = $arr['changelog']['release'];
  36130. unset($arr['changelog']['release']);
  36131. $arr['changelog']['release'] = array();
  36132. $arr['changelog']['release'][0] = $release;
  36133. }
  36134. foreach (array_keys($arr['changelog']['release']) as $key) {
  36135. $c =& $arr['changelog']['release'][$key];
  36136. if (isset($c['notes'])) {
  36137. // This trims out the indenting, needs fixing
  36138. $c['notes'] = "\n" . trim($c['notes']) . "\n";
  36139. }
  36140. }
  36141. }
  36142. if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) {
  36143. $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']);
  36144. unset($arr['contents']['dir']['file']);
  36145. if (isset($use['dir'])) {
  36146. $arr['contents']['dir']['dir'] = $use['dir'];
  36147. }
  36148. if (isset($use['file'])) {
  36149. $arr['contents']['dir']['file'] = $use['file'];
  36150. }
  36151. $this->options['beautifyFilelist'] = true;
  36152. }
  36153. $arr['attribs']['packagerversion'] = '1.10.10';
  36154. if ($this->serialize($arr, $options)) {
  36155. return $this->_serializedData . "\n";
  36156. }
  36157. return false;
  36158. }
  36159. function _recursiveXmlFilelist($list)
  36160. {
  36161. $dirs = array();
  36162. if (isset($list['attribs'])) {
  36163. $file = $list['attribs']['name'];
  36164. unset($list['attribs']['name']);
  36165. $attributes = $list['attribs'];
  36166. $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes);
  36167. } else {
  36168. foreach ($list as $a) {
  36169. $file = $a['attribs']['name'];
  36170. $attributes = $a['attribs'];
  36171. unset($a['attribs']);
  36172. $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a);
  36173. }
  36174. }
  36175. $this->_formatDir($dirs);
  36176. $this->_deFormat($dirs);
  36177. return $dirs;
  36178. }
  36179. function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null)
  36180. {
  36181. if (!$tasks) {
  36182. $tasks = array();
  36183. }
  36184. if ($dir == array() || $dir == array('.')) {
  36185. $dirs['file'][basename($file)] = $tasks;
  36186. $attributes['name'] = basename($file);
  36187. $dirs['file'][basename($file)]['attribs'] = $attributes;
  36188. return;
  36189. }
  36190. $curdir = array_shift($dir);
  36191. if (!isset($dirs['dir'][$curdir])) {
  36192. $dirs['dir'][$curdir] = array();
  36193. }
  36194. $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks);
  36195. }
  36196. function _formatDir(&$dirs)
  36197. {
  36198. if (!count($dirs)) {
  36199. return array();
  36200. }
  36201. $newdirs = array();
  36202. if (isset($dirs['dir'])) {
  36203. $newdirs['dir'] = $dirs['dir'];
  36204. }
  36205. if (isset($dirs['file'])) {
  36206. $newdirs['file'] = $dirs['file'];
  36207. }
  36208. $dirs = $newdirs;
  36209. if (isset($dirs['dir'])) {
  36210. uksort($dirs['dir'], 'strnatcasecmp');
  36211. foreach ($dirs['dir'] as $dir => $contents) {
  36212. $this->_formatDir($dirs['dir'][$dir]);
  36213. }
  36214. }
  36215. if (isset($dirs['file'])) {
  36216. uksort($dirs['file'], 'strnatcasecmp');
  36217. };
  36218. }
  36219. function _deFormat(&$dirs)
  36220. {
  36221. if (!count($dirs)) {
  36222. return array();
  36223. }
  36224. $newdirs = array();
  36225. if (isset($dirs['dir'])) {
  36226. foreach ($dirs['dir'] as $dir => $contents) {
  36227. $newdir = array();
  36228. $newdir['attribs']['name'] = $dir;
  36229. $this->_deFormat($contents);
  36230. foreach ($contents as $tag => $val) {
  36231. $newdir[$tag] = $val;
  36232. }
  36233. $newdirs['dir'][] = $newdir;
  36234. }
  36235. if (count($newdirs['dir']) == 1) {
  36236. $newdirs['dir'] = $newdirs['dir'][0];
  36237. }
  36238. }
  36239. if (isset($dirs['file'])) {
  36240. foreach ($dirs['file'] as $name => $file) {
  36241. $newdirs['file'][] = $file;
  36242. }
  36243. if (count($newdirs['file']) == 1) {
  36244. $newdirs['file'] = $newdirs['file'][0];
  36245. }
  36246. }
  36247. $dirs = $newdirs;
  36248. }
  36249. /**
  36250. * reset all options to default options
  36251. *
  36252. * @access public
  36253. * @see setOption(), XML_Unserializer()
  36254. */
  36255. function resetOptions()
  36256. {
  36257. $this->options = $this->_defaultOptions;
  36258. }
  36259. /**
  36260. * set an option
  36261. *
  36262. * You can use this method if you do not want to set all options in the constructor
  36263. *
  36264. * @access public
  36265. * @see resetOption(), XML_Serializer()
  36266. */
  36267. function setOption($name, $value)
  36268. {
  36269. $this->options[$name] = $value;
  36270. }
  36271. /**
  36272. * sets several options at once
  36273. *
  36274. * You can use this method if you do not want to set all options in the constructor
  36275. *
  36276. * @access public
  36277. * @see resetOption(), XML_Unserializer(), setOption()
  36278. */
  36279. function setOptions($options)
  36280. {
  36281. $this->options = array_merge($this->options, $options);
  36282. }
  36283. /**
  36284. * serialize data
  36285. *
  36286. * @access public
  36287. * @param mixed $data data to serialize
  36288. * @return boolean true on success, pear error on failure
  36289. */
  36290. function serialize($data, $options = null)
  36291. {
  36292. // if options have been specified, use them instead
  36293. // of the previously defined ones
  36294. if (is_array($options)) {
  36295. $optionsBak = $this->options;
  36296. if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
  36297. $this->options = array_merge($this->_defaultOptions, $options);
  36298. } else {
  36299. $this->options = array_merge($this->options, $options);
  36300. }
  36301. } else {
  36302. $optionsBak = null;
  36303. }
  36304. // start depth is zero
  36305. $this->_tagDepth = 0;
  36306. $this->_serializedData = '';
  36307. // serialize an array
  36308. if (is_array($data)) {
  36309. $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array';
  36310. $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']);
  36311. }
  36312. // add doctype declaration
  36313. if ($this->options['addDoctype'] === true) {
  36314. $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype'])
  36315. . $this->options['linebreak']
  36316. . $this->_serializedData;
  36317. }
  36318. // build xml declaration
  36319. if ($this->options['addDecl']) {
  36320. $atts = array();
  36321. $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null;
  36322. $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding)
  36323. . $this->options['linebreak']
  36324. . $this->_serializedData;
  36325. }
  36326. if ($optionsBak !== null) {
  36327. $this->options = $optionsBak;
  36328. }
  36329. return true;
  36330. }
  36331. /**
  36332. * get the result of the serialization
  36333. *
  36334. * @access public
  36335. * @return string serialized XML
  36336. */
  36337. function getSerializedData()
  36338. {
  36339. if ($this->_serializedData === null) {
  36340. return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
  36341. }
  36342. return $this->_serializedData;
  36343. }
  36344. /**
  36345. * serialize any value
  36346. *
  36347. * This method checks for the type of the value and calls the appropriate method
  36348. *
  36349. * @access private
  36350. * @param mixed $value
  36351. * @param string $tagName
  36352. * @param array $attributes
  36353. * @return string
  36354. */
  36355. function _serializeValue($value, $tagName = null, $attributes = array())
  36356. {
  36357. if (is_array($value)) {
  36358. $xml = $this->_serializeArray($value, $tagName, $attributes);
  36359. } elseif (is_object($value)) {
  36360. $xml = $this->_serializeObject($value, $tagName);
  36361. } else {
  36362. $tag = array(
  36363. 'qname' => $tagName,
  36364. 'attributes' => $attributes,
  36365. 'content' => $value
  36366. );
  36367. $xml = $this->_createXMLTag($tag);
  36368. }
  36369. return $xml;
  36370. }
  36371. /**
  36372. * serialize an array
  36373. *
  36374. * @access private
  36375. * @param array $array array to serialize
  36376. * @param string $tagName name of the root tag
  36377. * @param array $attributes attributes for the root tag
  36378. * @return string $string serialized data
  36379. * @uses XML_Util::isValidName() to check, whether key has to be substituted
  36380. */
  36381. function _serializeArray(&$array, $tagName = null, $attributes = array())
  36382. {
  36383. $_content = null;
  36384. /**
  36385. * check for special attributes
  36386. */
  36387. if ($this->options['attributesArray'] !== null) {
  36388. if (isset($array[$this->options['attributesArray']])) {
  36389. $attributes = $array[$this->options['attributesArray']];
  36390. unset($array[$this->options['attributesArray']]);
  36391. }
  36392. /**
  36393. * check for special content
  36394. */
  36395. if ($this->options['contentName'] !== null) {
  36396. if (isset($array[$this->options['contentName']])) {
  36397. $_content = $array[$this->options['contentName']];
  36398. unset($array[$this->options['contentName']]);
  36399. }
  36400. }
  36401. }
  36402. /*
  36403. * if mode is set to simpleXML, check whether
  36404. * the array is associative or indexed
  36405. */
  36406. if (is_array($array) && $this->options['mode'] == 'simplexml') {
  36407. $indexed = true;
  36408. if (!count($array)) {
  36409. $indexed = false;
  36410. }
  36411. foreach ($array as $key => $val) {
  36412. if (!is_int($key)) {
  36413. $indexed = false;
  36414. break;
  36415. }
  36416. }
  36417. if ($indexed && $this->options['mode'] == 'simplexml') {
  36418. $string = '';
  36419. foreach ($array as $key => $val) {
  36420. if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
  36421. if (!isset($this->_curdir)) {
  36422. $this->_curdir = '';
  36423. }
  36424. $savedir = $this->_curdir;
  36425. if (isset($val['attribs'])) {
  36426. if ($val['attribs']['name'] == '/') {
  36427. $this->_curdir = '/';
  36428. } else {
  36429. if ($this->_curdir == '/') {
  36430. $this->_curdir = '';
  36431. }
  36432. $this->_curdir .= '/' . $val['attribs']['name'];
  36433. }
  36434. }
  36435. }
  36436. $string .= $this->_serializeValue( $val, $tagName, $attributes);
  36437. if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
  36438. $string .= ' <!-- ' . $this->_curdir . ' -->';
  36439. if (empty($savedir)) {
  36440. unset($this->_curdir);
  36441. } else {
  36442. $this->_curdir = $savedir;
  36443. }
  36444. }
  36445. $string .= $this->options['linebreak'];
  36446. // do indentation
  36447. if ($this->options['indent'] !== null && $this->_tagDepth > 0) {
  36448. $string .= str_repeat($this->options['indent'], $this->_tagDepth);
  36449. }
  36450. }
  36451. return rtrim($string);
  36452. }
  36453. }
  36454. if ($this->options['scalarAsAttributes'] === true) {
  36455. foreach ($array as $key => $value) {
  36456. if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
  36457. unset($array[$key]);
  36458. $attributes[$this->options['prependAttributes'].$key] = $value;
  36459. }
  36460. }
  36461. }
  36462. // check for empty array => create empty tag
  36463. if (empty($array)) {
  36464. $tag = array(
  36465. 'qname' => $tagName,
  36466. 'content' => $_content,
  36467. 'attributes' => $attributes
  36468. );
  36469. } else {
  36470. $this->_tagDepth++;
  36471. $tmp = $this->options['linebreak'];
  36472. foreach ($array as $key => $value) {
  36473. // do indentation
  36474. if ($this->options['indent'] !== null && $this->_tagDepth > 0) {
  36475. $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
  36476. }
  36477. // copy key
  36478. $origKey = $key;
  36479. // key cannot be used as tagname => use default tag
  36480. $valid = XML_Util::isValidName($key);
  36481. if (PEAR::isError($valid)) {
  36482. if ($this->options['classAsTagName'] && is_object($value)) {
  36483. $key = get_class($value);
  36484. } else {
  36485. $key = $this->options['defaultTagName'];
  36486. }
  36487. }
  36488. $atts = array();
  36489. if ($this->options['typeHints'] === true) {
  36490. $atts[$this->options['typeAttribute']] = gettype($value);
  36491. if ($key !== $origKey) {
  36492. $atts[$this->options['keyAttribute']] = (string)$origKey;
  36493. }
  36494. }
  36495. if ($this->options['beautifyFilelist'] && $key == 'dir') {
  36496. if (!isset($this->_curdir)) {
  36497. $this->_curdir = '';
  36498. }
  36499. $savedir = $this->_curdir;
  36500. if (isset($value['attribs'])) {
  36501. if ($value['attribs']['name'] == '/') {
  36502. $this->_curdir = '/';
  36503. } else {
  36504. $this->_curdir .= '/' . $value['attribs']['name'];
  36505. }
  36506. }
  36507. }
  36508. if (is_string($value) && $value && ($value[strlen($value) - 1] == "\n")) {
  36509. $value .= str_repeat($this->options['indent'], $this->_tagDepth);
  36510. }
  36511. $tmp .= $this->_createXMLTag(array(
  36512. 'qname' => $key,
  36513. 'attributes' => $atts,
  36514. 'content' => $value )
  36515. );
  36516. if ($this->options['beautifyFilelist'] && $key == 'dir') {
  36517. if (isset($value['attribs'])) {
  36518. $tmp .= ' <!-- ' . $this->_curdir . ' -->';
  36519. if (empty($savedir)) {
  36520. unset($this->_curdir);
  36521. } else {
  36522. $this->_curdir = $savedir;
  36523. }
  36524. }
  36525. }
  36526. $tmp .= $this->options['linebreak'];
  36527. }
  36528. $this->_tagDepth--;
  36529. if ($this->options['indent']!==null && $this->_tagDepth>0) {
  36530. $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
  36531. }
  36532. if (trim($tmp) === '') {
  36533. $tmp = null;
  36534. }
  36535. $tag = array(
  36536. 'qname' => $tagName,
  36537. 'content' => $tmp,
  36538. 'attributes' => $attributes
  36539. );
  36540. }
  36541. if ($this->options['typeHints'] === true) {
  36542. if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
  36543. $tag['attributes'][$this->options['typeAttribute']] = 'array';
  36544. }
  36545. }
  36546. $string = $this->_createXMLTag($tag, false);
  36547. return $string;
  36548. }
  36549. /**
  36550. * create a tag from an array
  36551. * this method awaits an array in the following format
  36552. * array(
  36553. * 'qname' => $tagName,
  36554. * 'attributes' => array(),
  36555. * 'content' => $content, // optional
  36556. * 'namespace' => $namespace // optional
  36557. * 'namespaceUri' => $namespaceUri // optional
  36558. * )
  36559. *
  36560. * @access private
  36561. * @param array $tag tag definition
  36562. * @param boolean $replaceEntities whether to replace XML entities in content or not
  36563. * @return string $string XML tag
  36564. */
  36565. function _createXMLTag($tag, $replaceEntities = true)
  36566. {
  36567. if ($this->options['indentAttributes'] !== false) {
  36568. $multiline = true;
  36569. $indent = str_repeat($this->options['indent'], $this->_tagDepth);
  36570. if ($this->options['indentAttributes'] == '_auto') {
  36571. $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
  36572. } else {
  36573. $indent .= $this->options['indentAttributes'];
  36574. }
  36575. } else {
  36576. $indent = $multiline = false;
  36577. }
  36578. if (is_array($tag['content'])) {
  36579. if (empty($tag['content'])) {
  36580. $tag['content'] = '';
  36581. }
  36582. } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
  36583. $tag['content'] = '';
  36584. }
  36585. if (is_scalar($tag['content']) || is_null($tag['content'])) {
  36586. if ($replaceEntities === true) {
  36587. $replaceEntities = XML_UTIL_ENTITIES_XML;
  36588. }
  36589. $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']);
  36590. } elseif (is_array($tag['content'])) {
  36591. $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
  36592. } elseif (is_object($tag['content'])) {
  36593. $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
  36594. } elseif (is_resource($tag['content'])) {
  36595. settype($tag['content'], 'string');
  36596. $tag = XML_Util::createTagFromArray($tag, $replaceEntities);
  36597. }
  36598. return $tag;
  36599. }
  36600. }
  36601. �������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/Parser/v1.php���������������������������������������������������������0000644�0001750�0001750�00000040207�13565304531�017436� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  36602. /**
  36603. * package.xml parsing class, package.xml version 1.0
  36604. *
  36605. * PHP versions 4 and 5
  36606. *
  36607. * @category pear
  36608. * @package PEAR
  36609. * @author Greg Beaver <cellog@php.net>
  36610. * @copyright 1997-2009 The Authors
  36611. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  36612. * @link http://pear.php.net/package/PEAR
  36613. * @since File available since Release 1.4.0a1
  36614. */
  36615. /**
  36616. * package.xml abstraction class
  36617. */
  36618. require_once 'PEAR/PackageFile/v1.php';
  36619. /**
  36620. * Parser for package.xml version 1.0
  36621. * @category pear
  36622. * @package PEAR
  36623. * @author Greg Beaver <cellog@php.net>
  36624. * @copyright 1997-2009 The Authors
  36625. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  36626. * @version Release: @PEAR-VER@
  36627. * @link http://pear.php.net/package/PEAR
  36628. * @since Class available since Release 1.4.0a1
  36629. */
  36630. class PEAR_PackageFile_Parser_v1
  36631. {
  36632. var $_registry;
  36633. var $_config;
  36634. var $_logger;
  36635. /**
  36636. * BC hack to allow PEAR_Common::infoFromString() to sort of
  36637. * work with the version 2.0 format - there's no filelist though
  36638. * @param PEAR_PackageFile_v2
  36639. */
  36640. function fromV2($packagefile)
  36641. {
  36642. $info = $packagefile->getArray(true);
  36643. $ret = new PEAR_PackageFile_v1;
  36644. $ret->fromArray($info['old']);
  36645. }
  36646. function setConfig(&$c)
  36647. {
  36648. $this->_config = &$c;
  36649. $this->_registry = &$c->getRegistry();
  36650. }
  36651. function setLogger(&$l)
  36652. {
  36653. $this->_logger = &$l;
  36654. }
  36655. /**
  36656. * @param string contents of package.xml file, version 1.0
  36657. * @return bool success of parsing
  36658. */
  36659. function &parse($data, $file, $archive = false)
  36660. {
  36661. if (!extension_loaded('xml')) {
  36662. return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension');
  36663. }
  36664. $xp = xml_parser_create();
  36665. if (!$xp) {
  36666. $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml');
  36667. return $a;
  36668. }
  36669. xml_set_object($xp, $this);
  36670. xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0');
  36671. xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0');
  36672. xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
  36673. $this->element_stack = array();
  36674. $this->_packageInfo = array('provides' => array());
  36675. $this->current_element = false;
  36676. unset($this->dir_install);
  36677. $this->_packageInfo['filelist'] = array();
  36678. $this->filelist =& $this->_packageInfo['filelist'];
  36679. $this->dir_names = array();
  36680. $this->in_changelog = false;
  36681. $this->d_i = 0;
  36682. $this->cdata = '';
  36683. $this->_isValid = true;
  36684. if (!xml_parse($xp, $data, 1)) {
  36685. $code = xml_get_error_code($xp);
  36686. $line = xml_get_current_line_number($xp);
  36687. xml_parser_free($xp);
  36688. $a = PEAR::raiseError(sprintf("XML error: %s at line %d",
  36689. $str = xml_error_string($code), $line), 2);
  36690. return $a;
  36691. }
  36692. xml_parser_free($xp);
  36693. $pf = new PEAR_PackageFile_v1;
  36694. $pf->setConfig($this->_config);
  36695. if (isset($this->_logger)) {
  36696. $pf->setLogger($this->_logger);
  36697. }
  36698. $pf->setPackagefile($file, $archive);
  36699. $pf->fromArray($this->_packageInfo);
  36700. return $pf;
  36701. }
  36702. // {{{ _unIndent()
  36703. /**
  36704. * Unindent given string
  36705. *
  36706. * @param string $str The string that has to be unindented.
  36707. * @return string
  36708. * @access private
  36709. */
  36710. function _unIndent($str)
  36711. {
  36712. // remove leading newlines
  36713. $str = preg_replace('/^[\r\n]+/', '', $str);
  36714. // find whitespace at the beginning of the first line
  36715. $indent_len = strspn($str, " \t");
  36716. $indent = substr($str, 0, $indent_len);
  36717. $data = '';
  36718. // remove the same amount of whitespace from following lines
  36719. foreach (explode("\n", $str) as $line) {
  36720. if (substr($line, 0, $indent_len) == $indent) {
  36721. $data .= substr($line, $indent_len) . "\n";
  36722. } elseif (trim(substr($line, 0, $indent_len))) {
  36723. $data .= ltrim($line);
  36724. }
  36725. }
  36726. return $data;
  36727. }
  36728. // Support for package DTD v1.0:
  36729. // {{{ _element_start_1_0()
  36730. /**
  36731. * XML parser callback for ending elements. Used for version 1.0
  36732. * packages.
  36733. *
  36734. * @param resource $xp XML parser resource
  36735. * @param string $name name of ending element
  36736. *
  36737. * @return void
  36738. *
  36739. * @access private
  36740. */
  36741. function _element_start_1_0($xp, $name, $attribs)
  36742. {
  36743. array_push($this->element_stack, $name);
  36744. $this->current_element = $name;
  36745. $spos = sizeof($this->element_stack) - 2;
  36746. $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
  36747. $this->current_attributes = $attribs;
  36748. $this->cdata = '';
  36749. switch ($name) {
  36750. case 'dir':
  36751. if ($this->in_changelog) {
  36752. break;
  36753. }
  36754. if (array_key_exists('name', $attribs) && $attribs['name'] != '/') {
  36755. $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
  36756. $attribs['name']);
  36757. if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) {
  36758. $attribs['name'] = substr($attribs['name'], 0,
  36759. strlen($attribs['name']) - 1);
  36760. }
  36761. if (strpos($attribs['name'], '/') === 0) {
  36762. $attribs['name'] = substr($attribs['name'], 1);
  36763. }
  36764. $this->dir_names[] = $attribs['name'];
  36765. }
  36766. if (isset($attribs['baseinstalldir'])) {
  36767. $this->dir_install = $attribs['baseinstalldir'];
  36768. }
  36769. if (isset($attribs['role'])) {
  36770. $this->dir_role = $attribs['role'];
  36771. }
  36772. break;
  36773. case 'file':
  36774. if ($this->in_changelog) {
  36775. break;
  36776. }
  36777. if (isset($attribs['name'])) {
  36778. $path = '';
  36779. if (count($this->dir_names)) {
  36780. foreach ($this->dir_names as $dir) {
  36781. $path .= $dir . '/';
  36782. }
  36783. }
  36784. $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
  36785. $attribs['name']);
  36786. unset($attribs['name']);
  36787. $this->current_path = $path;
  36788. $this->filelist[$path] = $attribs;
  36789. // Set the baseinstalldir only if the file don't have this attrib
  36790. if (!isset($this->filelist[$path]['baseinstalldir']) &&
  36791. isset($this->dir_install))
  36792. {
  36793. $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
  36794. }
  36795. // Set the Role
  36796. if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
  36797. $this->filelist[$path]['role'] = $this->dir_role;
  36798. }
  36799. }
  36800. break;
  36801. case 'replace':
  36802. if (!$this->in_changelog) {
  36803. $this->filelist[$this->current_path]['replacements'][] = $attribs;
  36804. }
  36805. break;
  36806. case 'maintainers':
  36807. $this->_packageInfo['maintainers'] = array();
  36808. $this->m_i = 0; // maintainers array index
  36809. break;
  36810. case 'maintainer':
  36811. // compatibility check
  36812. if (!isset($this->_packageInfo['maintainers'])) {
  36813. $this->_packageInfo['maintainers'] = array();
  36814. $this->m_i = 0;
  36815. }
  36816. $this->_packageInfo['maintainers'][$this->m_i] = array();
  36817. $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i];
  36818. break;
  36819. case 'changelog':
  36820. $this->_packageInfo['changelog'] = array();
  36821. $this->c_i = 0; // changelog array index
  36822. $this->in_changelog = true;
  36823. break;
  36824. case 'release':
  36825. if ($this->in_changelog) {
  36826. $this->_packageInfo['changelog'][$this->c_i] = array();
  36827. $this->current_release = &$this->_packageInfo['changelog'][$this->c_i];
  36828. } else {
  36829. $this->current_release = &$this->_packageInfo;
  36830. }
  36831. break;
  36832. case 'deps':
  36833. if (!$this->in_changelog) {
  36834. $this->_packageInfo['release_deps'] = array();
  36835. }
  36836. break;
  36837. case 'dep':
  36838. // dependencies array index
  36839. if (!$this->in_changelog) {
  36840. $this->d_i++;
  36841. isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false;
  36842. $this->_packageInfo['release_deps'][$this->d_i] = $attribs;
  36843. }
  36844. break;
  36845. case 'configureoptions':
  36846. if (!$this->in_changelog) {
  36847. $this->_packageInfo['configure_options'] = array();
  36848. }
  36849. break;
  36850. case 'configureoption':
  36851. if (!$this->in_changelog) {
  36852. $this->_packageInfo['configure_options'][] = $attribs;
  36853. }
  36854. break;
  36855. case 'provides':
  36856. if (empty($attribs['type']) || empty($attribs['name'])) {
  36857. break;
  36858. }
  36859. $attribs['explicit'] = true;
  36860. $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs;
  36861. break;
  36862. case 'package' :
  36863. if (isset($attribs['version'])) {
  36864. $this->_packageInfo['xsdversion'] = trim($attribs['version']);
  36865. } else {
  36866. $this->_packageInfo['xsdversion'] = '1.0';
  36867. }
  36868. if (isset($attribs['packagerversion'])) {
  36869. $this->_packageInfo['packagerversion'] = $attribs['packagerversion'];
  36870. }
  36871. break;
  36872. }
  36873. }
  36874. // }}}
  36875. // {{{ _element_end_1_0()
  36876. /**
  36877. * XML parser callback for ending elements. Used for version 1.0
  36878. * packages.
  36879. *
  36880. * @param resource $xp XML parser resource
  36881. * @param string $name name of ending element
  36882. *
  36883. * @return void
  36884. *
  36885. * @access private
  36886. */
  36887. function _element_end_1_0($xp, $name)
  36888. {
  36889. $data = trim($this->cdata);
  36890. switch ($name) {
  36891. case 'name':
  36892. switch ($this->prev_element) {
  36893. case 'package':
  36894. $this->_packageInfo['package'] = $data;
  36895. break;
  36896. case 'maintainer':
  36897. $this->current_maintainer['name'] = $data;
  36898. break;
  36899. }
  36900. break;
  36901. case 'extends' :
  36902. $this->_packageInfo['extends'] = $data;
  36903. break;
  36904. case 'summary':
  36905. $this->_packageInfo['summary'] = $data;
  36906. break;
  36907. case 'description':
  36908. $data = $this->_unIndent($this->cdata);
  36909. $this->_packageInfo['description'] = $data;
  36910. break;
  36911. case 'user':
  36912. $this->current_maintainer['handle'] = $data;
  36913. break;
  36914. case 'email':
  36915. $this->current_maintainer['email'] = $data;
  36916. break;
  36917. case 'role':
  36918. $this->current_maintainer['role'] = $data;
  36919. break;
  36920. case 'version':
  36921. if ($this->in_changelog) {
  36922. $this->current_release['version'] = $data;
  36923. } else {
  36924. $this->_packageInfo['version'] = $data;
  36925. }
  36926. break;
  36927. case 'date':
  36928. if ($this->in_changelog) {
  36929. $this->current_release['release_date'] = $data;
  36930. } else {
  36931. $this->_packageInfo['release_date'] = $data;
  36932. }
  36933. break;
  36934. case 'notes':
  36935. // try to "de-indent" release notes in case someone
  36936. // has been over-indenting their xml ;-)
  36937. // Trim only on the right side
  36938. $data = rtrim($this->_unIndent($this->cdata));
  36939. if ($this->in_changelog) {
  36940. $this->current_release['release_notes'] = $data;
  36941. } else {
  36942. $this->_packageInfo['release_notes'] = $data;
  36943. }
  36944. break;
  36945. case 'warnings':
  36946. if ($this->in_changelog) {
  36947. $this->current_release['release_warnings'] = $data;
  36948. } else {
  36949. $this->_packageInfo['release_warnings'] = $data;
  36950. }
  36951. break;
  36952. case 'state':
  36953. if ($this->in_changelog) {
  36954. $this->current_release['release_state'] = $data;
  36955. } else {
  36956. $this->_packageInfo['release_state'] = $data;
  36957. }
  36958. break;
  36959. case 'license':
  36960. if ($this->in_changelog) {
  36961. $this->current_release['release_license'] = $data;
  36962. } else {
  36963. $this->_packageInfo['release_license'] = $data;
  36964. }
  36965. break;
  36966. case 'dep':
  36967. if ($data && !$this->in_changelog) {
  36968. $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data;
  36969. }
  36970. break;
  36971. case 'dir':
  36972. if ($this->in_changelog) {
  36973. break;
  36974. }
  36975. array_pop($this->dir_names);
  36976. break;
  36977. case 'file':
  36978. if ($this->in_changelog) {
  36979. break;
  36980. }
  36981. if ($data) {
  36982. $path = '';
  36983. if (count($this->dir_names)) {
  36984. foreach ($this->dir_names as $dir) {
  36985. $path .= $dir . '/';
  36986. }
  36987. }
  36988. $path .= $data;
  36989. $this->filelist[$path] = $this->current_attributes;
  36990. // Set the baseinstalldir only if the file don't have this attrib
  36991. if (!isset($this->filelist[$path]['baseinstalldir']) &&
  36992. isset($this->dir_install))
  36993. {
  36994. $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
  36995. }
  36996. // Set the Role
  36997. if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
  36998. $this->filelist[$path]['role'] = $this->dir_role;
  36999. }
  37000. }
  37001. break;
  37002. case 'maintainer':
  37003. if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) {
  37004. $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead';
  37005. }
  37006. $this->m_i++;
  37007. break;
  37008. case 'release':
  37009. if ($this->in_changelog) {
  37010. $this->c_i++;
  37011. }
  37012. break;
  37013. case 'changelog':
  37014. $this->in_changelog = false;
  37015. break;
  37016. }
  37017. array_pop($this->element_stack);
  37018. $spos = sizeof($this->element_stack) - 1;
  37019. $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : '';
  37020. $this->cdata = '';
  37021. }
  37022. // }}}
  37023. // {{{ _pkginfo_cdata_1_0()
  37024. /**
  37025. * XML parser callback for character data. Used for version 1.0
  37026. * packages.
  37027. *
  37028. * @param resource $xp XML parser resource
  37029. * @param string $name character data
  37030. *
  37031. * @return void
  37032. *
  37033. * @access private
  37034. */
  37035. function _pkginfo_cdata_1_0($xp, $data)
  37036. {
  37037. if (isset($this->cdata)) {
  37038. $this->cdata .= $data;
  37039. }
  37040. }
  37041. // }}}
  37042. }
  37043. ?>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/Parser/v2.php���������������������������������������������������������0000644�0001750�0001750�00000006110�13565304531�017432� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  37044. /**
  37045. * package.xml parsing class, package.xml version 2.0
  37046. *
  37047. * PHP versions 4 and 5
  37048. *
  37049. * @category pear
  37050. * @package PEAR
  37051. * @author Greg Beaver <cellog@php.net>
  37052. * @copyright 1997-2009 The Authors
  37053. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  37054. * @link http://pear.php.net/package/PEAR
  37055. * @since File available since Release 1.4.0a1
  37056. */
  37057. /**
  37058. * base xml parser class
  37059. */
  37060. require_once 'PEAR/XMLParser.php';
  37061. require_once 'PEAR/PackageFile/v2.php';
  37062. /**
  37063. * Parser for package.xml version 2.0
  37064. * @category pear
  37065. * @package PEAR
  37066. * @author Greg Beaver <cellog@php.net>
  37067. * @copyright 1997-2009 The Authors
  37068. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  37069. * @version Release: @PEAR-VER@
  37070. * @link http://pear.php.net/package/PEAR
  37071. * @since Class available since Release 1.4.0a1
  37072. */
  37073. class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser
  37074. {
  37075. var $_config;
  37076. var $_logger;
  37077. var $_registry;
  37078. function setConfig(&$c)
  37079. {
  37080. $this->_config = &$c;
  37081. $this->_registry = &$c->getRegistry();
  37082. }
  37083. function setLogger(&$l)
  37084. {
  37085. $this->_logger = &$l;
  37086. }
  37087. /**
  37088. * Unindent given string
  37089. *
  37090. * @param string $str The string that has to be unindented.
  37091. * @return string
  37092. * @access private
  37093. */
  37094. function _unIndent($str)
  37095. {
  37096. // remove leading newlines
  37097. $str = preg_replace('/^[\r\n]+/', '', $str);
  37098. // find whitespace at the beginning of the first line
  37099. $indent_len = strspn($str, " \t");
  37100. $indent = substr($str, 0, $indent_len);
  37101. $data = '';
  37102. // remove the same amount of whitespace from following lines
  37103. foreach (explode("\n", $str) as $line) {
  37104. if (substr($line, 0, $indent_len) == $indent) {
  37105. $data .= substr($line, $indent_len) . "\n";
  37106. } else {
  37107. $data .= $line . "\n";
  37108. }
  37109. }
  37110. return $data;
  37111. }
  37112. /**
  37113. * post-process data
  37114. *
  37115. * @param string $data
  37116. * @param string $element element name
  37117. */
  37118. function postProcess($data, $element)
  37119. {
  37120. if ($element == 'notes') {
  37121. return trim($this->_unIndent($data));
  37122. }
  37123. return trim($data);
  37124. }
  37125. /**
  37126. * @param string
  37127. * @param string file name of the package.xml
  37128. * @param string|false name of the archive this package.xml came from, if any
  37129. * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or
  37130. * a subclass
  37131. * @return PEAR_PackageFile_v2
  37132. */
  37133. function parse($data, $file = null, $archive = false, $class = 'PEAR_PackageFile_v2')
  37134. {
  37135. if (PEAR::isError($err = parent::parse($data))) {
  37136. return $err;
  37137. }
  37138. $ret = new $class;
  37139. $ret->encoding = $this->encoding;
  37140. $ret->setConfig($this->_config);
  37141. if (isset($this->_logger)) {
  37142. $ret->setLogger($this->_logger);
  37143. }
  37144. $ret->fromArray($this->_unserializedData);
  37145. $ret->setPackagefile($file, $archive);
  37146. return $ret;
  37147. }
  37148. }��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/v2/rw.php�������������������������������������������������������������0000644�0001750�0001750�00000173137�13565304531�016644� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  37149. /**
  37150. * PEAR_PackageFile_v2, package.xml version 2.0, read/write version
  37151. *
  37152. * PHP versions 4 and 5
  37153. *
  37154. * @category pear
  37155. * @package PEAR
  37156. * @author Greg Beaver <cellog@php.net>
  37157. * @copyright 1997-2009 The Authors
  37158. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  37159. * @link http://pear.php.net/package/PEAR
  37160. * @since File available since Release 1.4.0a8
  37161. */
  37162. /**
  37163. * For base class
  37164. */
  37165. require_once 'PEAR/PackageFile/v2.php';
  37166. /**
  37167. * @category pear
  37168. * @package PEAR
  37169. * @author Greg Beaver <cellog@php.net>
  37170. * @copyright 1997-2009 The Authors
  37171. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  37172. * @version Release: 1.10.10
  37173. * @link http://pear.php.net/package/PEAR
  37174. * @since Class available since Release 1.4.0a8
  37175. */
  37176. class PEAR_PackageFile_v2_rw extends PEAR_PackageFile_v2
  37177. {
  37178. /**
  37179. * @param string Extension name
  37180. * @return bool success of operation
  37181. */
  37182. function setProvidesExtension($extension)
  37183. {
  37184. if (in_array($this->getPackageType(),
  37185. array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
  37186. if (!isset($this->_packageInfo['providesextension'])) {
  37187. // ensure that the channel tag is set up in the right location
  37188. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37189. array('usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease',
  37190. 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37191. 'bundle', 'changelog'),
  37192. $extension, 'providesextension');
  37193. }
  37194. $this->_packageInfo['providesextension'] = $extension;
  37195. return true;
  37196. }
  37197. return false;
  37198. }
  37199. function setPackage($package)
  37200. {
  37201. $this->_isValid = 0;
  37202. if (!isset($this->_packageInfo['attribs'])) {
  37203. $this->_packageInfo = array_merge(array('attribs' => array(
  37204. 'version' => '2.0',
  37205. 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
  37206. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  37207. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  37208. 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
  37209. http://pear.php.net/dtd/tasks-1.0.xsd
  37210. http://pear.php.net/dtd/package-2.0
  37211. http://pear.php.net/dtd/package-2.0.xsd',
  37212. )), $this->_packageInfo);
  37213. }
  37214. if (!isset($this->_packageInfo['name'])) {
  37215. return $this->_packageInfo = array_merge(array('name' => $package),
  37216. $this->_packageInfo);
  37217. }
  37218. $this->_packageInfo['name'] = $package;
  37219. }
  37220. /**
  37221. * set this as a package.xml version 2.1
  37222. * @access private
  37223. */
  37224. function _setPackageVersion2_1()
  37225. {
  37226. $info = array(
  37227. 'version' => '2.1',
  37228. 'xmlns' => 'http://pear.php.net/dtd/package-2.1',
  37229. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  37230. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  37231. 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
  37232. http://pear.php.net/dtd/tasks-1.0.xsd
  37233. http://pear.php.net/dtd/package-2.1
  37234. http://pear.php.net/dtd/package-2.1.xsd',
  37235. );
  37236. if (!isset($this->_packageInfo['attribs'])) {
  37237. $this->_packageInfo = array_merge(array('attribs' => $info), $this->_packageInfo);
  37238. } else {
  37239. $this->_packageInfo['attribs'] = $info;
  37240. }
  37241. }
  37242. function setUri($uri)
  37243. {
  37244. unset($this->_packageInfo['channel']);
  37245. $this->_isValid = 0;
  37246. if (!isset($this->_packageInfo['uri'])) {
  37247. // ensure that the uri tag is set up in the right location
  37248. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37249. array('extends', 'summary', 'description', 'lead',
  37250. 'developer', 'contributor', 'helper', 'date', 'time', 'version',
  37251. 'stability', 'license', 'notes', 'contents', 'compatible',
  37252. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37253. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37254. 'extbinrelease', 'bundle', 'changelog'), $uri, 'uri');
  37255. }
  37256. $this->_packageInfo['uri'] = $uri;
  37257. }
  37258. function setChannel($channel)
  37259. {
  37260. unset($this->_packageInfo['uri']);
  37261. $this->_isValid = 0;
  37262. if (!isset($this->_packageInfo['channel'])) {
  37263. // ensure that the channel tag is set up in the right location
  37264. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37265. array('extends', 'summary', 'description', 'lead',
  37266. 'developer', 'contributor', 'helper', 'date', 'time', 'version',
  37267. 'stability', 'license', 'notes', 'contents', 'compatible',
  37268. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37269. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37270. 'extbinrelease', 'bundle', 'changelog'), $channel, 'channel');
  37271. }
  37272. $this->_packageInfo['channel'] = $channel;
  37273. }
  37274. function setExtends($extends)
  37275. {
  37276. $this->_isValid = 0;
  37277. if (!isset($this->_packageInfo['extends'])) {
  37278. // ensure that the extends tag is set up in the right location
  37279. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37280. array('summary', 'description', 'lead',
  37281. 'developer', 'contributor', 'helper', 'date', 'time', 'version',
  37282. 'stability', 'license', 'notes', 'contents', 'compatible',
  37283. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37284. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37285. 'extbinrelease', 'bundle', 'changelog'), $extends, 'extends');
  37286. }
  37287. $this->_packageInfo['extends'] = $extends;
  37288. }
  37289. function setSummary($summary)
  37290. {
  37291. $this->_isValid = 0;
  37292. if (!isset($this->_packageInfo['summary'])) {
  37293. // ensure that the summary tag is set up in the right location
  37294. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37295. array('description', 'lead',
  37296. 'developer', 'contributor', 'helper', 'date', 'time', 'version',
  37297. 'stability', 'license', 'notes', 'contents', 'compatible',
  37298. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37299. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37300. 'extbinrelease', 'bundle', 'changelog'), $summary, 'summary');
  37301. }
  37302. $this->_packageInfo['summary'] = $summary;
  37303. }
  37304. function setDescription($desc)
  37305. {
  37306. $this->_isValid = 0;
  37307. if (!isset($this->_packageInfo['description'])) {
  37308. // ensure that the description tag is set up in the right location
  37309. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37310. array('lead',
  37311. 'developer', 'contributor', 'helper', 'date', 'time', 'version',
  37312. 'stability', 'license', 'notes', 'contents', 'compatible',
  37313. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37314. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37315. 'extbinrelease', 'bundle', 'changelog'), $desc, 'description');
  37316. }
  37317. $this->_packageInfo['description'] = $desc;
  37318. }
  37319. /**
  37320. * Adds a new maintainer - no checking of duplicates is performed, use
  37321. * updatemaintainer for that purpose.
  37322. */
  37323. function addMaintainer($role, $handle, $name, $email, $active = 'yes')
  37324. {
  37325. if (!in_array($role, array('lead', 'developer', 'contributor', 'helper'))) {
  37326. return false;
  37327. }
  37328. if (isset($this->_packageInfo[$role])) {
  37329. if (!isset($this->_packageInfo[$role][0])) {
  37330. $this->_packageInfo[$role] = array($this->_packageInfo[$role]);
  37331. }
  37332. $this->_packageInfo[$role][] =
  37333. array(
  37334. 'name' => $name,
  37335. 'user' => $handle,
  37336. 'email' => $email,
  37337. 'active' => $active,
  37338. );
  37339. } else {
  37340. $testarr = array('lead',
  37341. 'developer', 'contributor', 'helper', 'date', 'time', 'version',
  37342. 'stability', 'license', 'notes', 'contents', 'compatible',
  37343. 'dependencies', 'providesextension', 'usesrole', 'usestask',
  37344. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
  37345. 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog');
  37346. foreach (array('lead', 'developer', 'contributor', 'helper') as $testrole) {
  37347. array_shift($testarr);
  37348. if ($role == $testrole) {
  37349. break;
  37350. }
  37351. }
  37352. if (!isset($this->_packageInfo[$role])) {
  37353. // ensure that the extends tag is set up in the right location
  37354. $this->_packageInfo = $this->_insertBefore($this->_packageInfo, $testarr,
  37355. array(), $role);
  37356. }
  37357. $this->_packageInfo[$role] =
  37358. array(
  37359. 'name' => $name,
  37360. 'user' => $handle,
  37361. 'email' => $email,
  37362. 'active' => $active,
  37363. );
  37364. }
  37365. $this->_isValid = 0;
  37366. }
  37367. function updateMaintainer($newrole, $handle, $name, $email, $active = 'yes')
  37368. {
  37369. $found = false;
  37370. foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
  37371. if (!isset($this->_packageInfo[$role])) {
  37372. continue;
  37373. }
  37374. $info = $this->_packageInfo[$role];
  37375. if (!isset($info[0])) {
  37376. if ($info['user'] == $handle) {
  37377. $found = true;
  37378. break;
  37379. }
  37380. }
  37381. foreach ($info as $i => $maintainer) {
  37382. if (is_array($maintainer) && $maintainer['user'] == $handle) {
  37383. $found = $i;
  37384. break 2;
  37385. }
  37386. }
  37387. }
  37388. if ($found === false) {
  37389. return $this->addMaintainer($newrole, $handle, $name, $email, $active);
  37390. }
  37391. if ($found !== false) {
  37392. if ($found === true) {
  37393. unset($this->_packageInfo[$role]);
  37394. } else {
  37395. unset($this->_packageInfo[$role][$found]);
  37396. $this->_packageInfo[$role] = array_values($this->_packageInfo[$role]);
  37397. }
  37398. }
  37399. $this->addMaintainer($newrole, $handle, $name, $email, $active);
  37400. $this->_isValid = 0;
  37401. }
  37402. function deleteMaintainer($handle)
  37403. {
  37404. $found = false;
  37405. foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
  37406. if (!isset($this->_packageInfo[$role])) {
  37407. continue;
  37408. }
  37409. if (!isset($this->_packageInfo[$role][0])) {
  37410. $this->_packageInfo[$role] = array($this->_packageInfo[$role]);
  37411. }
  37412. foreach ($this->_packageInfo[$role] as $i => $maintainer) {
  37413. if ($maintainer['user'] == $handle) {
  37414. $found = $i;
  37415. break;
  37416. }
  37417. }
  37418. if ($found !== false) {
  37419. unset($this->_packageInfo[$role][$found]);
  37420. if (!count($this->_packageInfo[$role]) && $role == 'lead') {
  37421. $this->_isValid = 0;
  37422. }
  37423. if (!count($this->_packageInfo[$role])) {
  37424. unset($this->_packageInfo[$role]);
  37425. return true;
  37426. }
  37427. $this->_packageInfo[$role] =
  37428. array_values($this->_packageInfo[$role]);
  37429. if (count($this->_packageInfo[$role]) == 1) {
  37430. $this->_packageInfo[$role] = $this->_packageInfo[$role][0];
  37431. }
  37432. return true;
  37433. }
  37434. if (count($this->_packageInfo[$role]) == 1) {
  37435. $this->_packageInfo[$role] = $this->_packageInfo[$role][0];
  37436. }
  37437. }
  37438. return false;
  37439. }
  37440. function setReleaseVersion($version)
  37441. {
  37442. if (isset($this->_packageInfo['version']) &&
  37443. isset($this->_packageInfo['version']['release'])) {
  37444. unset($this->_packageInfo['version']['release']);
  37445. }
  37446. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array(
  37447. 'version' => array('stability', 'license', 'notes', 'contents', 'compatible',
  37448. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37449. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37450. 'extbinrelease', 'bundle', 'changelog'),
  37451. 'release' => array('api')));
  37452. $this->_isValid = 0;
  37453. }
  37454. function setAPIVersion($version)
  37455. {
  37456. if (isset($this->_packageInfo['version']) &&
  37457. isset($this->_packageInfo['version']['api'])) {
  37458. unset($this->_packageInfo['version']['api']);
  37459. }
  37460. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array(
  37461. 'version' => array('stability', 'license', 'notes', 'contents', 'compatible',
  37462. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37463. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37464. 'extbinrelease', 'bundle', 'changelog'),
  37465. 'api' => array()));
  37466. $this->_isValid = 0;
  37467. }
  37468. /**
  37469. * snapshot|devel|alpha|beta|stable
  37470. */
  37471. function setReleaseStability($state)
  37472. {
  37473. if (isset($this->_packageInfo['stability']) &&
  37474. isset($this->_packageInfo['stability']['release'])) {
  37475. unset($this->_packageInfo['stability']['release']);
  37476. }
  37477. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array(
  37478. 'stability' => array('license', 'notes', 'contents', 'compatible',
  37479. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37480. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37481. 'extbinrelease', 'bundle', 'changelog'),
  37482. 'release' => array('api')));
  37483. $this->_isValid = 0;
  37484. }
  37485. /**
  37486. * @param devel|alpha|beta|stable
  37487. */
  37488. function setAPIStability($state)
  37489. {
  37490. if (isset($this->_packageInfo['stability']) &&
  37491. isset($this->_packageInfo['stability']['api'])) {
  37492. unset($this->_packageInfo['stability']['api']);
  37493. }
  37494. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array(
  37495. 'stability' => array('license', 'notes', 'contents', 'compatible',
  37496. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37497. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37498. 'extbinrelease', 'bundle', 'changelog'),
  37499. 'api' => array()));
  37500. $this->_isValid = 0;
  37501. }
  37502. function setLicense($license, $uri = false, $filesource = false)
  37503. {
  37504. if (!isset($this->_packageInfo['license'])) {
  37505. // ensure that the license tag is set up in the right location
  37506. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37507. array('notes', 'contents', 'compatible',
  37508. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37509. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37510. 'extbinrelease', 'bundle', 'changelog'), 0, 'license');
  37511. }
  37512. if ($uri || $filesource) {
  37513. $attribs = array();
  37514. if ($uri) {
  37515. $attribs['uri'] = $uri;
  37516. }
  37517. $uri = true; // for test below
  37518. if ($filesource) {
  37519. $attribs['filesource'] = $filesource;
  37520. }
  37521. }
  37522. $license = $uri ? array('attribs' => $attribs, '_content' => $license) : $license;
  37523. $this->_packageInfo['license'] = $license;
  37524. $this->_isValid = 0;
  37525. }
  37526. function setNotes($notes)
  37527. {
  37528. $this->_isValid = 0;
  37529. if (!isset($this->_packageInfo['notes'])) {
  37530. // ensure that the notes tag is set up in the right location
  37531. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37532. array('contents', 'compatible',
  37533. 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
  37534. 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37535. 'extbinrelease', 'bundle', 'changelog'), $notes, 'notes');
  37536. }
  37537. $this->_packageInfo['notes'] = $notes;
  37538. }
  37539. /**
  37540. * This is only used at install-time, after all serialization
  37541. * is over.
  37542. * @param string file name
  37543. * @param string installed path
  37544. */
  37545. function setInstalledAs($file, $path)
  37546. {
  37547. if ($path) {
  37548. return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
  37549. }
  37550. unset($this->_packageInfo['filelist'][$file]['installed_as']);
  37551. }
  37552. /**
  37553. * This is only used at install-time, after all serialization
  37554. * is over.
  37555. */
  37556. function installedFile($file, $atts)
  37557. {
  37558. if (isset($this->_packageInfo['filelist'][$file])) {
  37559. $this->_packageInfo['filelist'][$file] =
  37560. array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
  37561. } else {
  37562. $this->_packageInfo['filelist'][$file] = $atts['attribs'];
  37563. }
  37564. }
  37565. /**
  37566. * Reset the listing of package contents
  37567. * @param string base installation dir for the whole package, if any
  37568. */
  37569. function clearContents($baseinstall = false)
  37570. {
  37571. $this->_filesValid = false;
  37572. $this->_isValid = 0;
  37573. if (!isset($this->_packageInfo['contents'])) {
  37574. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37575. array('compatible',
  37576. 'dependencies', 'providesextension', 'usesrole', 'usestask',
  37577. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
  37578. 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37579. 'bundle', 'changelog'), array(), 'contents');
  37580. }
  37581. if ($this->getPackageType() != 'bundle') {
  37582. $this->_packageInfo['contents'] =
  37583. array('dir' => array('attribs' => array('name' => '/')));
  37584. if ($baseinstall) {
  37585. $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'] = $baseinstall;
  37586. }
  37587. } else {
  37588. $this->_packageInfo['contents'] = array('bundledpackage' => array());
  37589. }
  37590. }
  37591. /**
  37592. * @param string relative path of the bundled package.
  37593. */
  37594. function addBundledPackage($path)
  37595. {
  37596. if ($this->getPackageType() != 'bundle') {
  37597. return false;
  37598. }
  37599. $this->_filesValid = false;
  37600. $this->_isValid = 0;
  37601. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $path, array(
  37602. 'contents' => array('compatible', 'dependencies', 'providesextension',
  37603. 'usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease',
  37604. 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37605. 'bundle', 'changelog'),
  37606. 'bundledpackage' => array()));
  37607. }
  37608. /**
  37609. * @param string file name
  37610. * @param PEAR_Task_Common a read/write task
  37611. */
  37612. function addTaskToFile($filename, $task)
  37613. {
  37614. if (!method_exists($task, 'getXml')) {
  37615. return false;
  37616. }
  37617. if (!method_exists($task, 'getName')) {
  37618. return false;
  37619. }
  37620. if (!method_exists($task, 'validate')) {
  37621. return false;
  37622. }
  37623. if (!$task->validate()) {
  37624. return false;
  37625. }
  37626. if (!isset($this->_packageInfo['contents']['dir']['file'])) {
  37627. return false;
  37628. }
  37629. $this->getTasksNs(); // discover the tasks namespace if not done already
  37630. $files = $this->_packageInfo['contents']['dir']['file'];
  37631. if (!isset($files[0])) {
  37632. $files = array($files);
  37633. $ind = false;
  37634. } else {
  37635. $ind = true;
  37636. }
  37637. foreach ($files as $i => $file) {
  37638. if (isset($file['attribs'])) {
  37639. if ($file['attribs']['name'] == $filename) {
  37640. if ($ind) {
  37641. $t = isset($this->_packageInfo['contents']['dir']['file'][$i]
  37642. ['attribs'][$this->_tasksNs .
  37643. ':' . $task->getName()]) ?
  37644. $this->_packageInfo['contents']['dir']['file'][$i]
  37645. ['attribs'][$this->_tasksNs .
  37646. ':' . $task->getName()] : false;
  37647. if ($t && !isset($t[0])) {
  37648. $this->_packageInfo['contents']['dir']['file'][$i]
  37649. [$this->_tasksNs . ':' . $task->getName()] = array($t);
  37650. }
  37651. $this->_packageInfo['contents']['dir']['file'][$i][$this->_tasksNs .
  37652. ':' . $task->getName()][] = $task->getXml();
  37653. } else {
  37654. $t = isset($this->_packageInfo['contents']['dir']['file']
  37655. ['attribs'][$this->_tasksNs .
  37656. ':' . $task->getName()]) ? $this->_packageInfo['contents']['dir']['file']
  37657. ['attribs'][$this->_tasksNs .
  37658. ':' . $task->getName()] : false;
  37659. if ($t && !isset($t[0])) {
  37660. $this->_packageInfo['contents']['dir']['file']
  37661. [$this->_tasksNs . ':' . $task->getName()] = array($t);
  37662. }
  37663. $this->_packageInfo['contents']['dir']['file'][$this->_tasksNs .
  37664. ':' . $task->getName()][] = $task->getXml();
  37665. }
  37666. return true;
  37667. }
  37668. }
  37669. }
  37670. return false;
  37671. }
  37672. /**
  37673. * @param string path to the file
  37674. * @param string filename
  37675. * @param array extra attributes
  37676. */
  37677. function addFile($dir, $file, $attrs)
  37678. {
  37679. if ($this->getPackageType() == 'bundle') {
  37680. return false;
  37681. }
  37682. $this->_filesValid = false;
  37683. $this->_isValid = 0;
  37684. $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
  37685. if ($dir == '/' || $dir == '') {
  37686. $dir = '';
  37687. } else {
  37688. $dir .= '/';
  37689. }
  37690. $attrs['name'] = $dir . $file;
  37691. if (!isset($this->_packageInfo['contents'])) {
  37692. // ensure that the contents tag is set up
  37693. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  37694. array('compatible', 'dependencies', 'providesextension', 'usesrole', 'usestask',
  37695. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
  37696. 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
  37697. 'bundle', 'changelog'), array(), 'contents');
  37698. }
  37699. if (isset($this->_packageInfo['contents']['dir']['file'])) {
  37700. if (!isset($this->_packageInfo['contents']['dir']['file'][0])) {
  37701. $this->_packageInfo['contents']['dir']['file'] =
  37702. array($this->_packageInfo['contents']['dir']['file']);
  37703. }
  37704. $this->_packageInfo['contents']['dir']['file'][]['attribs'] = $attrs;
  37705. } else {
  37706. $this->_packageInfo['contents']['dir']['file']['attribs'] = $attrs;
  37707. }
  37708. }
  37709. /**
  37710. * @param string Dependent package name
  37711. * @param string Dependent package's channel name
  37712. * @param string minimum version of specified package that this release is guaranteed to be
  37713. * compatible with
  37714. * @param string maximum version of specified package that this release is guaranteed to be
  37715. * compatible with
  37716. * @param string versions of specified package that this release is not compatible with
  37717. */
  37718. function addCompatiblePackage($name, $channel, $min, $max, $exclude = false)
  37719. {
  37720. $this->_isValid = 0;
  37721. $set = array(
  37722. 'name' => $name,
  37723. 'channel' => $channel,
  37724. 'min' => $min,
  37725. 'max' => $max,
  37726. );
  37727. if ($exclude) {
  37728. $set['exclude'] = $exclude;
  37729. }
  37730. $this->_isValid = 0;
  37731. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
  37732. 'compatible' => array('dependencies', 'providesextension', 'usesrole', 'usestask',
  37733. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37734. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')
  37735. ));
  37736. }
  37737. /**
  37738. * Removes the <usesrole> tag entirely
  37739. */
  37740. function resetUsesrole()
  37741. {
  37742. if (isset($this->_packageInfo['usesrole'])) {
  37743. unset($this->_packageInfo['usesrole']);
  37744. }
  37745. }
  37746. /**
  37747. * @param string
  37748. * @param string package name or uri
  37749. * @param string channel name if non-uri
  37750. */
  37751. function addUsesrole($role, $packageOrUri, $channel = false) {
  37752. $set = array('role' => $role);
  37753. if ($channel) {
  37754. $set['package'] = $packageOrUri;
  37755. $set['channel'] = $channel;
  37756. } else {
  37757. $set['uri'] = $packageOrUri;
  37758. }
  37759. $this->_isValid = 0;
  37760. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
  37761. 'usesrole' => array('usestask', 'srcpackage', 'srcuri',
  37762. 'phprelease', 'extsrcrelease', 'extbinrelease',
  37763. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')
  37764. ));
  37765. }
  37766. /**
  37767. * Removes the <usestask> tag entirely
  37768. */
  37769. function resetUsestask()
  37770. {
  37771. if (isset($this->_packageInfo['usestask'])) {
  37772. unset($this->_packageInfo['usestask']);
  37773. }
  37774. }
  37775. /**
  37776. * @param string
  37777. * @param string package name or uri
  37778. * @param string channel name if non-uri
  37779. */
  37780. function addUsestask($task, $packageOrUri, $channel = false) {
  37781. $set = array('task' => $task);
  37782. if ($channel) {
  37783. $set['package'] = $packageOrUri;
  37784. $set['channel'] = $channel;
  37785. } else {
  37786. $set['uri'] = $packageOrUri;
  37787. }
  37788. $this->_isValid = 0;
  37789. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
  37790. 'usestask' => array('srcpackage', 'srcuri',
  37791. 'phprelease', 'extsrcrelease', 'extbinrelease',
  37792. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')
  37793. ));
  37794. }
  37795. /**
  37796. * Remove all compatible tags
  37797. */
  37798. function clearCompatible()
  37799. {
  37800. unset($this->_packageInfo['compatible']);
  37801. }
  37802. /**
  37803. * Reset dependencies prior to adding new ones
  37804. */
  37805. function clearDeps()
  37806. {
  37807. if (!isset($this->_packageInfo['dependencies'])) {
  37808. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(),
  37809. array(
  37810. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  37811. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37812. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')));
  37813. }
  37814. $this->_packageInfo['dependencies'] = array();
  37815. }
  37816. /**
  37817. * @param string minimum PHP version allowed
  37818. * @param string maximum PHP version allowed
  37819. * @param array $exclude incompatible PHP versions
  37820. */
  37821. function setPhpDep($min, $max = false, $exclude = false)
  37822. {
  37823. $this->_isValid = 0;
  37824. $dep =
  37825. array(
  37826. 'min' => $min,
  37827. );
  37828. if ($max) {
  37829. $dep['max'] = $max;
  37830. }
  37831. if ($exclude) {
  37832. if (count($exclude) == 1) {
  37833. $exclude = $exclude[0];
  37834. }
  37835. $dep['exclude'] = $exclude;
  37836. }
  37837. if (isset($this->_packageInfo['dependencies']['required']['php'])) {
  37838. $this->_stack->push(__FUNCTION__, 'warning', array('dep' =>
  37839. $this->_packageInfo['dependencies']['required']['php']),
  37840. 'warning: PHP dependency already exists, overwriting');
  37841. unset($this->_packageInfo['dependencies']['required']['php']);
  37842. }
  37843. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  37844. array(
  37845. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  37846. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37847. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  37848. 'required' => array('optional', 'group'),
  37849. 'php' => array('pearinstaller', 'package', 'subpackage', 'extension', 'os', 'arch')
  37850. ));
  37851. return true;
  37852. }
  37853. /**
  37854. * @param string minimum allowed PEAR installer version
  37855. * @param string maximum allowed PEAR installer version
  37856. * @param string recommended PEAR installer version
  37857. * @param array incompatible version of the PEAR installer
  37858. */
  37859. function setPearinstallerDep($min, $max = false, $recommended = false, $exclude = false)
  37860. {
  37861. $this->_isValid = 0;
  37862. $dep =
  37863. array(
  37864. 'min' => $min,
  37865. );
  37866. if ($max) {
  37867. $dep['max'] = $max;
  37868. }
  37869. if ($recommended) {
  37870. $dep['recommended'] = $recommended;
  37871. }
  37872. if ($exclude) {
  37873. if (count($exclude) == 1) {
  37874. $exclude = $exclude[0];
  37875. }
  37876. $dep['exclude'] = $exclude;
  37877. }
  37878. if (isset($this->_packageInfo['dependencies']['required']['pearinstaller'])) {
  37879. $this->_stack->push(__FUNCTION__, 'warning', array('dep' =>
  37880. $this->_packageInfo['dependencies']['required']['pearinstaller']),
  37881. 'warning: PEAR Installer dependency already exists, overwriting');
  37882. unset($this->_packageInfo['dependencies']['required']['pearinstaller']);
  37883. }
  37884. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  37885. array(
  37886. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  37887. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37888. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  37889. 'required' => array('optional', 'group'),
  37890. 'pearinstaller' => array('package', 'subpackage', 'extension', 'os', 'arch')
  37891. ));
  37892. }
  37893. /**
  37894. * Mark a package as conflicting with this package
  37895. * @param string package name
  37896. * @param string package channel
  37897. * @param string extension this package provides, if any
  37898. * @param string|false minimum version required
  37899. * @param string|false maximum version allowed
  37900. * @param array|false versions to exclude from installation
  37901. */
  37902. function addConflictingPackageDepWithChannel($name, $channel,
  37903. $providesextension = false, $min = false, $max = false, $exclude = false)
  37904. {
  37905. $this->_isValid = 0;
  37906. $dep = $this->_constructDep($name, $channel, false, $min, $max, false,
  37907. $exclude, $providesextension, false, true);
  37908. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  37909. array(
  37910. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  37911. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37912. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  37913. 'required' => array('optional', 'group'),
  37914. 'package' => array('subpackage', 'extension', 'os', 'arch')
  37915. ));
  37916. }
  37917. /**
  37918. * Mark a package as conflicting with this package
  37919. * @param string package name
  37920. * @param string package channel
  37921. * @param string extension this package provides, if any
  37922. */
  37923. function addConflictingPackageDepWithUri($name, $uri, $providesextension = false)
  37924. {
  37925. $this->_isValid = 0;
  37926. $dep =
  37927. array(
  37928. 'name' => $name,
  37929. 'uri' => $uri,
  37930. 'conflicts' => '',
  37931. );
  37932. if ($providesextension) {
  37933. $dep['providesextension'] = $providesextension;
  37934. }
  37935. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  37936. array(
  37937. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  37938. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37939. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  37940. 'required' => array('optional', 'group'),
  37941. 'package' => array('subpackage', 'extension', 'os', 'arch')
  37942. ));
  37943. }
  37944. function addDependencyGroup($name, $hint)
  37945. {
  37946. $this->_isValid = 0;
  37947. $this->_packageInfo = $this->_mergeTag($this->_packageInfo,
  37948. array('attribs' => array('name' => $name, 'hint' => $hint)),
  37949. array(
  37950. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  37951. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  37952. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  37953. 'group' => array(),
  37954. ));
  37955. }
  37956. /**
  37957. * @param string package name
  37958. * @param string|false channel name, false if this is a uri
  37959. * @param string|false uri name, false if this is a channel
  37960. * @param string|false minimum version required
  37961. * @param string|false maximum version allowed
  37962. * @param string|false recommended installation version
  37963. * @param array|false versions to exclude from installation
  37964. * @param string extension this package provides, if any
  37965. * @param bool if true, tells the installer to ignore the default optional dependency group
  37966. * when installing this package
  37967. * @param bool if true, tells the installer to negate this dependency (conflicts)
  37968. * @return array
  37969. * @access private
  37970. */
  37971. function _constructDep($name, $channel, $uri, $min, $max, $recommended, $exclude,
  37972. $providesextension = false, $nodefault = false,
  37973. $conflicts = false)
  37974. {
  37975. $dep =
  37976. array(
  37977. 'name' => $name,
  37978. );
  37979. if ($channel) {
  37980. $dep['channel'] = $channel;
  37981. } elseif ($uri) {
  37982. $dep['uri'] = $uri;
  37983. }
  37984. if ($min) {
  37985. $dep['min'] = $min;
  37986. }
  37987. if ($max) {
  37988. $dep['max'] = $max;
  37989. }
  37990. if ($recommended) {
  37991. $dep['recommended'] = $recommended;
  37992. }
  37993. if ($exclude) {
  37994. if (is_array($exclude) && count($exclude) == 1) {
  37995. $exclude = $exclude[0];
  37996. }
  37997. $dep['exclude'] = $exclude;
  37998. }
  37999. if ($conflicts) {
  38000. $dep['conflicts'] = '';
  38001. }
  38002. if ($nodefault) {
  38003. $dep['nodefault'] = '';
  38004. }
  38005. if ($providesextension) {
  38006. $dep['providesextension'] = $providesextension;
  38007. }
  38008. return $dep;
  38009. }
  38010. /**
  38011. * @param package|subpackage
  38012. * @param string group name
  38013. * @param string package name
  38014. * @param string package channel
  38015. * @param string minimum version
  38016. * @param string maximum version
  38017. * @param string recommended version
  38018. * @param array|false optional excluded versions
  38019. * @param string extension this package provides, if any
  38020. * @param bool if true, tells the installer to ignore the default optional dependency group
  38021. * when installing this package
  38022. * @return bool false if the dependency group has not been initialized with
  38023. * {@link addDependencyGroup()}, or a subpackage is added with
  38024. * a providesextension
  38025. */
  38026. function addGroupPackageDepWithChannel($type, $groupname, $name, $channel, $min = false,
  38027. $max = false, $recommended = false, $exclude = false,
  38028. $providesextension = false, $nodefault = false)
  38029. {
  38030. if ($type == 'subpackage' && $providesextension) {
  38031. return false; // subpackages must be php packages
  38032. }
  38033. $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
  38034. $providesextension, $nodefault);
  38035. return $this->_addGroupDependency($type, $dep, $groupname);
  38036. }
  38037. /**
  38038. * @param package|subpackage
  38039. * @param string group name
  38040. * @param string package name
  38041. * @param string package uri
  38042. * @param string extension this package provides, if any
  38043. * @param bool if true, tells the installer to ignore the default optional dependency group
  38044. * when installing this package
  38045. * @return bool false if the dependency group has not been initialized with
  38046. * {@link addDependencyGroup()}
  38047. */
  38048. function addGroupPackageDepWithURI($type, $groupname, $name, $uri, $providesextension = false,
  38049. $nodefault = false)
  38050. {
  38051. if ($type == 'subpackage' && $providesextension) {
  38052. return false; // subpackages must be php packages
  38053. }
  38054. $dep = $this->_constructDep($name, false, $uri, false, false, false, false,
  38055. $providesextension, $nodefault);
  38056. return $this->_addGroupDependency($type, $dep, $groupname);
  38057. }
  38058. /**
  38059. * @param string group name (must be pre-existing)
  38060. * @param string extension name
  38061. * @param string minimum version allowed
  38062. * @param string maximum version allowed
  38063. * @param string recommended version
  38064. * @param array incompatible versions
  38065. */
  38066. function addGroupExtensionDep($groupname, $name, $min = false, $max = false,
  38067. $recommended = false, $exclude = false)
  38068. {
  38069. $this->_isValid = 0;
  38070. $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
  38071. return $this->_addGroupDependency('extension', $dep, $groupname);
  38072. }
  38073. /**
  38074. * @param package|subpackage|extension
  38075. * @param array dependency contents
  38076. * @param string name of the dependency group to add this to
  38077. * @return boolean
  38078. * @access private
  38079. */
  38080. function _addGroupDependency($type, $dep, $groupname)
  38081. {
  38082. $arr = array('subpackage', 'extension');
  38083. if ($type != 'package') {
  38084. array_shift($arr);
  38085. }
  38086. if ($type == 'extension') {
  38087. array_shift($arr);
  38088. }
  38089. if (!isset($this->_packageInfo['dependencies']['group'])) {
  38090. return false;
  38091. } else {
  38092. if (!isset($this->_packageInfo['dependencies']['group'][0])) {
  38093. if ($this->_packageInfo['dependencies']['group']['attribs']['name'] == $groupname) {
  38094. $this->_packageInfo['dependencies']['group'] = $this->_mergeTag(
  38095. $this->_packageInfo['dependencies']['group'], $dep,
  38096. array(
  38097. $type => $arr
  38098. ));
  38099. $this->_isValid = 0;
  38100. return true;
  38101. } else {
  38102. return false;
  38103. }
  38104. } else {
  38105. foreach ($this->_packageInfo['dependencies']['group'] as $i => $group) {
  38106. if ($group['attribs']['name'] == $groupname) {
  38107. $this->_packageInfo['dependencies']['group'][$i] = $this->_mergeTag(
  38108. $this->_packageInfo['dependencies']['group'][$i], $dep,
  38109. array(
  38110. $type => $arr
  38111. ));
  38112. $this->_isValid = 0;
  38113. return true;
  38114. }
  38115. }
  38116. return false;
  38117. }
  38118. }
  38119. }
  38120. /**
  38121. * @param optional|required
  38122. * @param string package name
  38123. * @param string package channel
  38124. * @param string minimum version
  38125. * @param string maximum version
  38126. * @param string recommended version
  38127. * @param string extension this package provides, if any
  38128. * @param bool if true, tells the installer to ignore the default optional dependency group
  38129. * when installing this package
  38130. * @param array|false optional excluded versions
  38131. */
  38132. function addPackageDepWithChannel($type, $name, $channel, $min = false, $max = false,
  38133. $recommended = false, $exclude = false,
  38134. $providesextension = false, $nodefault = false)
  38135. {
  38136. if (!in_array($type, array('optional', 'required'), true)) {
  38137. $type = 'required';
  38138. }
  38139. $this->_isValid = 0;
  38140. $arr = array('optional', 'group');
  38141. if ($type != 'required') {
  38142. array_shift($arr);
  38143. }
  38144. $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
  38145. $providesextension, $nodefault);
  38146. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38147. array(
  38148. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38149. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38150. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38151. $type => $arr,
  38152. 'package' => array('subpackage', 'extension', 'os', 'arch')
  38153. ));
  38154. }
  38155. /**
  38156. * @param optional|required
  38157. * @param string name of the package
  38158. * @param string uri of the package
  38159. * @param string extension this package provides, if any
  38160. * @param bool if true, tells the installer to ignore the default optional dependency group
  38161. * when installing this package
  38162. */
  38163. function addPackageDepWithUri($type, $name, $uri, $providesextension = false,
  38164. $nodefault = false)
  38165. {
  38166. $this->_isValid = 0;
  38167. $arr = array('optional', 'group');
  38168. if ($type != 'required') {
  38169. array_shift($arr);
  38170. }
  38171. $dep = $this->_constructDep($name, false, $uri, false, false, false, false,
  38172. $providesextension, $nodefault);
  38173. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38174. array(
  38175. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38176. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38177. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38178. $type => $arr,
  38179. 'package' => array('subpackage', 'extension', 'os', 'arch')
  38180. ));
  38181. }
  38182. /**
  38183. * @param optional|required optional, required
  38184. * @param string package name
  38185. * @param string package channel
  38186. * @param string minimum version
  38187. * @param string maximum version
  38188. * @param string recommended version
  38189. * @param array incompatible versions
  38190. * @param bool if true, tells the installer to ignore the default optional dependency group
  38191. * when installing this package
  38192. */
  38193. function addSubpackageDepWithChannel($type, $name, $channel, $min = false, $max = false,
  38194. $recommended = false, $exclude = false,
  38195. $nodefault = false)
  38196. {
  38197. $this->_isValid = 0;
  38198. $arr = array('optional', 'group');
  38199. if ($type != 'required') {
  38200. array_shift($arr);
  38201. }
  38202. $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
  38203. $nodefault);
  38204. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38205. array(
  38206. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38207. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38208. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38209. $type => $arr,
  38210. 'subpackage' => array('extension', 'os', 'arch')
  38211. ));
  38212. }
  38213. /**
  38214. * @param optional|required optional, required
  38215. * @param string package name
  38216. * @param string package uri for download
  38217. * @param bool if true, tells the installer to ignore the default optional dependency group
  38218. * when installing this package
  38219. */
  38220. function addSubpackageDepWithUri($type, $name, $uri, $nodefault = false)
  38221. {
  38222. $this->_isValid = 0;
  38223. $arr = array('optional', 'group');
  38224. if ($type != 'required') {
  38225. array_shift($arr);
  38226. }
  38227. $dep = $this->_constructDep($name, false, $uri, false, false, false, false, $nodefault);
  38228. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38229. array(
  38230. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38231. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38232. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38233. $type => $arr,
  38234. 'subpackage' => array('extension', 'os', 'arch')
  38235. ));
  38236. }
  38237. /**
  38238. * @param optional|required optional, required
  38239. * @param string extension name
  38240. * @param string minimum version
  38241. * @param string maximum version
  38242. * @param string recommended version
  38243. * @param array incompatible versions
  38244. */
  38245. function addExtensionDep($type, $name, $min = false, $max = false, $recommended = false,
  38246. $exclude = false)
  38247. {
  38248. $this->_isValid = 0;
  38249. $arr = array('optional', 'group');
  38250. if ($type != 'required') {
  38251. array_shift($arr);
  38252. }
  38253. $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
  38254. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38255. array(
  38256. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38257. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38258. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38259. $type => $arr,
  38260. 'extension' => array('os', 'arch')
  38261. ));
  38262. }
  38263. /**
  38264. * @param string Operating system name
  38265. * @param boolean true if this package cannot be installed on this OS
  38266. */
  38267. function addOsDep($name, $conflicts = false)
  38268. {
  38269. $this->_isValid = 0;
  38270. $dep = array('name' => $name);
  38271. if ($conflicts) {
  38272. $dep['conflicts'] = '';
  38273. }
  38274. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38275. array(
  38276. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38277. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38278. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38279. 'required' => array('optional', 'group'),
  38280. 'os' => array('arch')
  38281. ));
  38282. }
  38283. /**
  38284. * @param string Architecture matching pattern
  38285. * @param boolean true if this package cannot be installed on this architecture
  38286. */
  38287. function addArchDep($pattern, $conflicts = false)
  38288. {
  38289. $this->_isValid = 0;
  38290. $dep = array('pattern' => $pattern);
  38291. if ($conflicts) {
  38292. $dep['conflicts'] = '';
  38293. }
  38294. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
  38295. array(
  38296. 'dependencies' => array('providesextension', 'usesrole', 'usestask',
  38297. 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
  38298. 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
  38299. 'required' => array('optional', 'group'),
  38300. 'arch' => array()
  38301. ));
  38302. }
  38303. /**
  38304. * Set the kind of package, and erase all release tags
  38305. *
  38306. * - a php package is a PEAR-style package
  38307. * - an extbin package is a PECL-style extension binary
  38308. * - an extsrc package is a PECL-style source for a binary
  38309. * - an zendextbin package is a PECL-style zend extension binary
  38310. * - an zendextsrc package is a PECL-style source for a zend extension binary
  38311. * - a bundle package is a collection of other pre-packaged packages
  38312. * @param php|extbin|extsrc|zendextsrc|zendextbin|bundle
  38313. * @return bool success
  38314. */
  38315. function setPackageType($type)
  38316. {
  38317. $this->_isValid = 0;
  38318. if (!in_array($type, array('php', 'extbin', 'extsrc', 'zendextsrc',
  38319. 'zendextbin', 'bundle'))) {
  38320. return false;
  38321. }
  38322. if (in_array($type, array('zendextsrc', 'zendextbin'))) {
  38323. $this->_setPackageVersion2_1();
  38324. }
  38325. if ($type != 'bundle') {
  38326. $type .= 'release';
  38327. }
  38328. foreach (array('phprelease', 'extbinrelease', 'extsrcrelease',
  38329. 'zendextsrcrelease', 'zendextbinrelease', 'bundle') as $test) {
  38330. unset($this->_packageInfo[$test]);
  38331. }
  38332. if (!isset($this->_packageInfo[$type])) {
  38333. // ensure that the release tag is set up
  38334. $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('changelog'),
  38335. array(), $type);
  38336. }
  38337. $this->_packageInfo[$type] = array();
  38338. return true;
  38339. }
  38340. /**
  38341. * @return bool true if package type is set up
  38342. */
  38343. function addRelease()
  38344. {
  38345. if ($type = $this->getPackageType()) {
  38346. if ($type != 'bundle') {
  38347. $type .= 'release';
  38348. }
  38349. $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(),
  38350. array($type => array('changelog')));
  38351. return true;
  38352. }
  38353. return false;
  38354. }
  38355. /**
  38356. * Get the current release tag in order to add to it
  38357. * @param bool returns only releases that have installcondition if true
  38358. * @return array|null
  38359. */
  38360. function &_getCurrentRelease($strict = true)
  38361. {
  38362. if ($p = $this->getPackageType()) {
  38363. if ($strict) {
  38364. if ($p == 'extsrc' || $p == 'zendextsrc') {
  38365. $a = null;
  38366. return $a;
  38367. }
  38368. }
  38369. if ($p != 'bundle') {
  38370. $p .= 'release';
  38371. }
  38372. if (isset($this->_packageInfo[$p][0])) {
  38373. return $this->_packageInfo[$p][count($this->_packageInfo[$p]) - 1];
  38374. } else {
  38375. return $this->_packageInfo[$p];
  38376. }
  38377. } else {
  38378. $a = null;
  38379. return $a;
  38380. }
  38381. }
  38382. /**
  38383. * Add a file to the current release that should be installed under a different name
  38384. * @param string <contents> path to file
  38385. * @param string name the file should be installed as
  38386. */
  38387. function addInstallAs($path, $as)
  38388. {
  38389. $r = &$this->_getCurrentRelease();
  38390. if ($r === null) {
  38391. return false;
  38392. }
  38393. $this->_isValid = 0;
  38394. $r = $this->_mergeTag($r, array('attribs' => array('name' => $path, 'as' => $as)),
  38395. array(
  38396. 'filelist' => array(),
  38397. 'install' => array('ignore')
  38398. ));
  38399. }
  38400. /**
  38401. * Add a file to the current release that should be ignored
  38402. * @param string <contents> path to file
  38403. * @return bool success of operation
  38404. */
  38405. function addIgnore($path)
  38406. {
  38407. $r = &$this->_getCurrentRelease();
  38408. if ($r === null) {
  38409. return false;
  38410. }
  38411. $this->_isValid = 0;
  38412. $r = $this->_mergeTag($r, array('attribs' => array('name' => $path)),
  38413. array(
  38414. 'filelist' => array(),
  38415. 'ignore' => array()
  38416. ));
  38417. }
  38418. /**
  38419. * Add an extension binary package for this extension source code release
  38420. *
  38421. * Note that the package must be from the same channel as the extension source package
  38422. * @param string
  38423. */
  38424. function addBinarypackage($package)
  38425. {
  38426. if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
  38427. return false;
  38428. }
  38429. $r = &$this->_getCurrentRelease(false);
  38430. if ($r === null) {
  38431. return false;
  38432. }
  38433. $this->_isValid = 0;
  38434. $r = $this->_mergeTag($r, $package,
  38435. array(
  38436. 'binarypackage' => array('filelist'),
  38437. ));
  38438. }
  38439. /**
  38440. * Add a configureoption to an extension source package
  38441. * @param string
  38442. * @param string
  38443. * @param string
  38444. */
  38445. function addConfigureOption($name, $prompt, $default = null)
  38446. {
  38447. if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
  38448. return false;
  38449. }
  38450. $r = &$this->_getCurrentRelease(false);
  38451. if ($r === null) {
  38452. return false;
  38453. }
  38454. $opt = array('attribs' => array('name' => $name, 'prompt' => $prompt));
  38455. if ($default !== null) {
  38456. $opt['attribs']['default'] = $default;
  38457. }
  38458. $this->_isValid = 0;
  38459. $r = $this->_mergeTag($r, $opt,
  38460. array(
  38461. 'configureoption' => array('binarypackage', 'filelist'),
  38462. ));
  38463. }
  38464. /**
  38465. * Set an installation condition based on php version for the current release set
  38466. * @param string minimum version
  38467. * @param string maximum version
  38468. * @param false|array incompatible versions of PHP
  38469. */
  38470. function setPhpInstallCondition($min, $max, $exclude = false)
  38471. {
  38472. $r = &$this->_getCurrentRelease();
  38473. if ($r === null) {
  38474. return false;
  38475. }
  38476. $this->_isValid = 0;
  38477. if (isset($r['installconditions']['php'])) {
  38478. unset($r['installconditions']['php']);
  38479. }
  38480. $dep = array('min' => $min, 'max' => $max);
  38481. if ($exclude) {
  38482. if (is_array($exclude) && count($exclude) == 1) {
  38483. $exclude = $exclude[0];
  38484. }
  38485. $dep['exclude'] = $exclude;
  38486. }
  38487. if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
  38488. $r = $this->_mergeTag($r, $dep,
  38489. array(
  38490. 'installconditions' => array('configureoption', 'binarypackage',
  38491. 'filelist'),
  38492. 'php' => array('extension', 'os', 'arch')
  38493. ));
  38494. } else {
  38495. $r = $this->_mergeTag($r, $dep,
  38496. array(
  38497. 'installconditions' => array('filelist'),
  38498. 'php' => array('extension', 'os', 'arch')
  38499. ));
  38500. }
  38501. }
  38502. /**
  38503. * @param optional|required optional, required
  38504. * @param string extension name
  38505. * @param string minimum version
  38506. * @param string maximum version
  38507. * @param string recommended version
  38508. * @param array incompatible versions
  38509. */
  38510. function addExtensionInstallCondition($name, $min = false, $max = false, $recommended = false,
  38511. $exclude = false)
  38512. {
  38513. $r = &$this->_getCurrentRelease();
  38514. if ($r === null) {
  38515. return false;
  38516. }
  38517. $this->_isValid = 0;
  38518. $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
  38519. if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
  38520. $r = $this->_mergeTag($r, $dep,
  38521. array(
  38522. 'installconditions' => array('configureoption', 'binarypackage',
  38523. 'filelist'),
  38524. 'extension' => array('os', 'arch')
  38525. ));
  38526. } else {
  38527. $r = $this->_mergeTag($r, $dep,
  38528. array(
  38529. 'installconditions' => array('filelist'),
  38530. 'extension' => array('os', 'arch')
  38531. ));
  38532. }
  38533. }
  38534. /**
  38535. * Set an installation condition based on operating system for the current release set
  38536. * @param string OS name
  38537. * @param bool whether this OS is incompatible with the current release
  38538. */
  38539. function setOsInstallCondition($name, $conflicts = false)
  38540. {
  38541. $r = &$this->_getCurrentRelease();
  38542. if ($r === null) {
  38543. return false;
  38544. }
  38545. $this->_isValid = 0;
  38546. if (isset($r['installconditions']['os'])) {
  38547. unset($r['installconditions']['os']);
  38548. }
  38549. $dep = array('name' => $name);
  38550. if ($conflicts) {
  38551. $dep['conflicts'] = '';
  38552. }
  38553. if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
  38554. $r = $this->_mergeTag($r, $dep,
  38555. array(
  38556. 'installconditions' => array('configureoption', 'binarypackage',
  38557. 'filelist'),
  38558. 'os' => array('arch')
  38559. ));
  38560. } else {
  38561. $r = $this->_mergeTag($r, $dep,
  38562. array(
  38563. 'installconditions' => array('filelist'),
  38564. 'os' => array('arch')
  38565. ));
  38566. }
  38567. }
  38568. /**
  38569. * Set an installation condition based on architecture for the current release set
  38570. * @param string architecture pattern
  38571. * @param bool whether this arch is incompatible with the current release
  38572. */
  38573. function setArchInstallCondition($pattern, $conflicts = false)
  38574. {
  38575. $r = &$this->_getCurrentRelease();
  38576. if ($r === null) {
  38577. return false;
  38578. }
  38579. $this->_isValid = 0;
  38580. if (isset($r['installconditions']['arch'])) {
  38581. unset($r['installconditions']['arch']);
  38582. }
  38583. $dep = array('pattern' => $pattern);
  38584. if ($conflicts) {
  38585. $dep['conflicts'] = '';
  38586. }
  38587. if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
  38588. $r = $this->_mergeTag($r, $dep,
  38589. array(
  38590. 'installconditions' => array('configureoption', 'binarypackage',
  38591. 'filelist'),
  38592. 'arch' => array()
  38593. ));
  38594. } else {
  38595. $r = $this->_mergeTag($r, $dep,
  38596. array(
  38597. 'installconditions' => array('filelist'),
  38598. 'arch' => array()
  38599. ));
  38600. }
  38601. }
  38602. /**
  38603. * For extension binary releases, this is used to specify either the
  38604. * static URI to a source package, or the package name and channel of the extsrc/zendextsrc
  38605. * package it is based on.
  38606. * @param string Package name, or full URI to source package (extsrc/zendextsrc type)
  38607. */
  38608. function setSourcePackage($packageOrUri)
  38609. {
  38610. $this->_isValid = 0;
  38611. if (isset($this->_packageInfo['channel'])) {
  38612. $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease',
  38613. 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
  38614. 'bundle', 'changelog'),
  38615. $packageOrUri, 'srcpackage');
  38616. } else {
  38617. $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease',
  38618. 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
  38619. 'bundle', 'changelog'), $packageOrUri, 'srcuri');
  38620. }
  38621. }
  38622. /**
  38623. * Generate a valid change log entry from the current package.xml
  38624. * @param string|false
  38625. */
  38626. function generateChangeLogEntry($notes = false)
  38627. {
  38628. return array(
  38629. 'version' =>
  38630. array(
  38631. 'release' => $this->getVersion('release'),
  38632. 'api' => $this->getVersion('api'),
  38633. ),
  38634. 'stability' =>
  38635. $this->getStability(),
  38636. 'date' => $this->getDate(),
  38637. 'license' => $this->getLicense(true),
  38638. 'notes' => $notes ? $notes : $this->getNotes()
  38639. );
  38640. }
  38641. /**
  38642. * @param string release version to set change log notes for
  38643. * @param array output of {@link generateChangeLogEntry()}
  38644. */
  38645. function setChangelogEntry($releaseversion, $contents)
  38646. {
  38647. if (!isset($this->_packageInfo['changelog'])) {
  38648. $this->_packageInfo['changelog']['release'] = $contents;
  38649. return;
  38650. }
  38651. if (!isset($this->_packageInfo['changelog']['release'][0])) {
  38652. if ($this->_packageInfo['changelog']['release']['version']['release'] == $releaseversion) {
  38653. $this->_packageInfo['changelog']['release'] = array(
  38654. $this->_packageInfo['changelog']['release']);
  38655. } else {
  38656. $this->_packageInfo['changelog']['release'] = array(
  38657. $this->_packageInfo['changelog']['release']);
  38658. return $this->_packageInfo['changelog']['release'][] = $contents;
  38659. }
  38660. }
  38661. foreach($this->_packageInfo['changelog']['release'] as $index => $changelog) {
  38662. if (isset($changelog['version']) &&
  38663. strnatcasecmp($changelog['version']['release'], $releaseversion) == 0) {
  38664. $curlog = $index;
  38665. }
  38666. }
  38667. if (isset($curlog)) {
  38668. $this->_packageInfo['changelog']['release'][$curlog] = $contents;
  38669. } else {
  38670. $this->_packageInfo['changelog']['release'][] = $contents;
  38671. }
  38672. }
  38673. /**
  38674. * Remove the changelog entirely
  38675. */
  38676. function clearChangeLog()
  38677. {
  38678. unset($this->_packageInfo['changelog']);
  38679. }
  38680. }���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/v2/Validator.php������������������������������������������������������0000644�0001750�0001750�00000246200�13565304531�020131� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  38681. /**
  38682. * PEAR_PackageFile_v2, package.xml version 2.0, read/write version
  38683. *
  38684. * PHP versions 4 and 5
  38685. *
  38686. * @category pear
  38687. * @package PEAR
  38688. * @author Greg Beaver <cellog@php.net>
  38689. * @copyright 1997-2009 The Authors
  38690. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  38691. * @link http://pear.php.net/package/PEAR
  38692. * @since File available since Release 1.4.0a8
  38693. */
  38694. /**
  38695. * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its
  38696. * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller
  38697. * @category pear
  38698. * @package PEAR
  38699. * @author Greg Beaver <cellog@php.net>
  38700. * @copyright 1997-2009 The Authors
  38701. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  38702. * @version Release: 1.10.10
  38703. * @link http://pear.php.net/package/PEAR
  38704. * @since Class available since Release 1.4.0a8
  38705. * @access private
  38706. */
  38707. class PEAR_PackageFile_v2_Validator
  38708. {
  38709. /**
  38710. * @var array
  38711. */
  38712. var $_packageInfo;
  38713. /**
  38714. * @var PEAR_PackageFile_v2
  38715. */
  38716. var $_pf;
  38717. /**
  38718. * @var PEAR_ErrorStack
  38719. */
  38720. var $_stack;
  38721. /**
  38722. * @var int
  38723. */
  38724. var $_isValid = 0;
  38725. /**
  38726. * @var int
  38727. */
  38728. var $_filesValid = 0;
  38729. /**
  38730. * @var int
  38731. */
  38732. var $_curState = 0;
  38733. /**
  38734. * @param PEAR_PackageFile_v2
  38735. * @param int
  38736. */
  38737. function validate(&$pf, $state = PEAR_VALIDATE_NORMAL)
  38738. {
  38739. $this->_pf = &$pf;
  38740. $this->_curState = $state;
  38741. $this->_packageInfo = $this->_pf->getArray();
  38742. $this->_isValid = $this->_pf->_isValid;
  38743. $this->_filesValid = $this->_pf->_filesValid;
  38744. $this->_stack = &$pf->_stack;
  38745. $this->_stack->getErrors(true);
  38746. if (($this->_isValid & $state) == $state) {
  38747. return true;
  38748. }
  38749. if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
  38750. return false;
  38751. }
  38752. if (!isset($this->_packageInfo['attribs']['version']) ||
  38753. ($this->_packageInfo['attribs']['version'] != '2.0' &&
  38754. $this->_packageInfo['attribs']['version'] != '2.1')
  38755. ) {
  38756. $this->_noPackageVersion();
  38757. }
  38758. $structure =
  38759. array(
  38760. 'name',
  38761. 'channel|uri',
  38762. '*extends', // can't be multiple, but this works fine
  38763. 'summary',
  38764. 'description',
  38765. '+lead', // these all need content checks
  38766. '*developer',
  38767. '*contributor',
  38768. '*helper',
  38769. 'date',
  38770. '*time',
  38771. 'version',
  38772. 'stability',
  38773. 'license->?uri->?filesource',
  38774. 'notes',
  38775. 'contents', //special validation needed
  38776. '*compatible',
  38777. 'dependencies', //special validation needed
  38778. '*usesrole',
  38779. '*usestask', // reserve these for 1.4.0a1 to implement
  38780. // this will allow a package.xml to gracefully say it
  38781. // needs a certain package installed in order to implement a role or task
  38782. '*providesextension',
  38783. '*srcpackage|*srcuri',
  38784. '+phprelease|+extsrcrelease|+extbinrelease|' .
  38785. '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed
  38786. '*changelog',
  38787. );
  38788. $test = $this->_packageInfo;
  38789. if (isset($test['dependencies']) &&
  38790. isset($test['dependencies']['required']) &&
  38791. isset($test['dependencies']['required']['pearinstaller']) &&
  38792. isset($test['dependencies']['required']['pearinstaller']['min']) &&
  38793. '1.10.10' != '@package' . '_version@' &&
  38794. version_compare('1.10.10',
  38795. $test['dependencies']['required']['pearinstaller']['min'], '<')
  38796. ) {
  38797. $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']);
  38798. return false;
  38799. }
  38800. // ignore post-installation array fields
  38801. if (array_key_exists('filelist', $test)) {
  38802. unset($test['filelist']);
  38803. }
  38804. if (array_key_exists('_lastmodified', $test)) {
  38805. unset($test['_lastmodified']);
  38806. }
  38807. if (array_key_exists('#binarypackage', $test)) {
  38808. unset($test['#binarypackage']);
  38809. }
  38810. if (array_key_exists('old', $test)) {
  38811. unset($test['old']);
  38812. }
  38813. if (array_key_exists('_lastversion', $test)) {
  38814. unset($test['_lastversion']);
  38815. }
  38816. if (!$this->_stupidSchemaValidate($structure, $test, '<package>')) {
  38817. return false;
  38818. }
  38819. if (empty($this->_packageInfo['name'])) {
  38820. $this->_tagCannotBeEmpty('name');
  38821. }
  38822. $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel';
  38823. if (empty($this->_packageInfo[$test])) {
  38824. $this->_tagCannotBeEmpty($test);
  38825. }
  38826. if (is_array($this->_packageInfo['license']) &&
  38827. (!isset($this->_packageInfo['license']['_content']) ||
  38828. empty($this->_packageInfo['license']['_content']))) {
  38829. $this->_tagCannotBeEmpty('license');
  38830. } elseif (empty($this->_packageInfo['license'])) {
  38831. $this->_tagCannotBeEmpty('license');
  38832. }
  38833. if (empty($this->_packageInfo['summary'])) {
  38834. $this->_tagCannotBeEmpty('summary');
  38835. }
  38836. if (empty($this->_packageInfo['description'])) {
  38837. $this->_tagCannotBeEmpty('description');
  38838. }
  38839. if (empty($this->_packageInfo['date'])) {
  38840. $this->_tagCannotBeEmpty('date');
  38841. }
  38842. if (empty($this->_packageInfo['notes'])) {
  38843. $this->_tagCannotBeEmpty('notes');
  38844. }
  38845. if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) {
  38846. $this->_tagCannotBeEmpty('time');
  38847. }
  38848. if (isset($this->_packageInfo['dependencies'])) {
  38849. $this->_validateDependencies();
  38850. }
  38851. if (isset($this->_packageInfo['compatible'])) {
  38852. $this->_validateCompatible();
  38853. }
  38854. if (!isset($this->_packageInfo['bundle'])) {
  38855. if (empty($this->_packageInfo['contents'])) {
  38856. $this->_tagCannotBeEmpty('contents');
  38857. }
  38858. if (!isset($this->_packageInfo['contents']['dir'])) {
  38859. $this->_filelistMustContainDir('contents');
  38860. return false;
  38861. }
  38862. if (isset($this->_packageInfo['contents']['file'])) {
  38863. $this->_filelistCannotContainFile('contents');
  38864. return false;
  38865. }
  38866. }
  38867. $this->_validateMaintainers();
  38868. $this->_validateStabilityVersion();
  38869. $fail = false;
  38870. if (array_key_exists('usesrole', $this->_packageInfo)) {
  38871. $roles = $this->_packageInfo['usesrole'];
  38872. if (!is_array($roles) || !isset($roles[0])) {
  38873. $roles = array($roles);
  38874. }
  38875. foreach ($roles as $role) {
  38876. if (!isset($role['role'])) {
  38877. $this->_usesroletaskMustHaveRoleTask('usesrole', 'role');
  38878. $fail = true;
  38879. } else {
  38880. if (!isset($role['channel'])) {
  38881. if (!isset($role['uri'])) {
  38882. $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole');
  38883. $fail = true;
  38884. }
  38885. } elseif (!isset($role['package'])) {
  38886. $this->_usesroletaskMustHavePackage($role['role'], 'usesrole');
  38887. $fail = true;
  38888. }
  38889. }
  38890. }
  38891. }
  38892. if (array_key_exists('usestask', $this->_packageInfo)) {
  38893. $roles = $this->_packageInfo['usestask'];
  38894. if (!is_array($roles) || !isset($roles[0])) {
  38895. $roles = array($roles);
  38896. }
  38897. foreach ($roles as $role) {
  38898. if (!isset($role['task'])) {
  38899. $this->_usesroletaskMustHaveRoleTask('usestask', 'task');
  38900. $fail = true;
  38901. } else {
  38902. if (!isset($role['channel'])) {
  38903. if (!isset($role['uri'])) {
  38904. $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask');
  38905. $fail = true;
  38906. }
  38907. } elseif (!isset($role['package'])) {
  38908. $this->_usesroletaskMustHavePackage($role['task'], 'usestask');
  38909. $fail = true;
  38910. }
  38911. }
  38912. }
  38913. }
  38914. if ($fail) {
  38915. return false;
  38916. }
  38917. $list = $this->_packageInfo['contents'];
  38918. if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) {
  38919. $this->_multipleToplevelDirNotAllowed();
  38920. return $this->_isValid = 0;
  38921. }
  38922. $this->_validateFilelist();
  38923. $this->_validateRelease();
  38924. if (!$this->_stack->hasErrors()) {
  38925. $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true);
  38926. if (PEAR::isError($chan)) {
  38927. $this->_unknownChannel($this->_pf->getChannel());
  38928. } else {
  38929. $valpack = $chan->getValidationPackage();
  38930. // for channel validator packages, always use the default PEAR validator.
  38931. // otherwise, they can't be installed or packaged
  38932. $validator = $chan->getValidationObject($this->_pf->getPackage());
  38933. if (!$validator) {
  38934. $this->_stack->push(__FUNCTION__, 'error',
  38935. array('channel' => $chan->getName(),
  38936. 'package' => $this->_pf->getPackage(),
  38937. 'name' => $valpack['_content'],
  38938. 'version' => $valpack['attribs']['version']),
  38939. 'package "%channel%/%package%" cannot be properly validated without ' .
  38940. 'validation package "%channel%/%name%-%version%"');
  38941. return $this->_isValid = 0;
  38942. }
  38943. $validator->setPackageFile($this->_pf);
  38944. $validator->validate($state);
  38945. $failures = $validator->getFailures();
  38946. foreach ($failures['errors'] as $error) {
  38947. $this->_stack->push(__FUNCTION__, 'error', $error,
  38948. 'Channel validator error: field "%field%" - %reason%');
  38949. }
  38950. foreach ($failures['warnings'] as $warning) {
  38951. $this->_stack->push(__FUNCTION__, 'warning', $warning,
  38952. 'Channel validator warning: field "%field%" - %reason%');
  38953. }
  38954. }
  38955. }
  38956. $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error');
  38957. if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) {
  38958. if ($this->_pf->getPackageType() == 'bundle') {
  38959. if ($this->_analyzeBundledPackages()) {
  38960. $this->_filesValid = $this->_pf->_filesValid = true;
  38961. } else {
  38962. $this->_pf->_isValid = $this->_isValid = 0;
  38963. }
  38964. } else {
  38965. if (!$this->_analyzePhpFiles()) {
  38966. $this->_pf->_isValid = $this->_isValid = 0;
  38967. } else {
  38968. $this->_filesValid = $this->_pf->_filesValid = true;
  38969. }
  38970. }
  38971. }
  38972. if ($this->_isValid) {
  38973. return $this->_pf->_isValid = $this->_isValid = $state;
  38974. }
  38975. return $this->_pf->_isValid = $this->_isValid = 0;
  38976. }
  38977. function _stupidSchemaValidate($structure, $xml, $root)
  38978. {
  38979. if (!is_array($xml)) {
  38980. $xml = array();
  38981. }
  38982. $keys = array_keys($xml);
  38983. reset($keys);
  38984. $key = current($keys);
  38985. while ($key == 'attribs' || $key == '_contents') {
  38986. $key = next($keys);
  38987. }
  38988. $unfoundtags = $optionaltags = array();
  38989. $ret = true;
  38990. $mismatch = false;
  38991. foreach ($structure as $struc) {
  38992. if ($key) {
  38993. $tag = $xml[$key];
  38994. }
  38995. $test = $this->_processStructure($struc);
  38996. if (isset($test['choices'])) {
  38997. $loose = true;
  38998. foreach ($test['choices'] as $choice) {
  38999. if ($key == $choice['tag']) {
  39000. $key = next($keys);
  39001. while ($key == 'attribs' || $key == '_contents') {
  39002. $key = next($keys);
  39003. }
  39004. $unfoundtags = $optionaltags = array();
  39005. $mismatch = false;
  39006. if ($key && $key != $choice['tag'] && isset($choice['multiple'])) {
  39007. $unfoundtags[] = $choice['tag'];
  39008. $optionaltags[] = $choice['tag'];
  39009. if ($key) {
  39010. $mismatch = true;
  39011. }
  39012. }
  39013. $ret &= $this->_processAttribs($choice, $tag, $root);
  39014. continue 2;
  39015. } else {
  39016. $unfoundtags[] = $choice['tag'];
  39017. $mismatch = true;
  39018. }
  39019. if (!isset($choice['multiple']) || $choice['multiple'] != '*') {
  39020. $loose = false;
  39021. } else {
  39022. $optionaltags[] = $choice['tag'];
  39023. }
  39024. }
  39025. if (!$loose) {
  39026. $this->_invalidTagOrder($unfoundtags, $key, $root);
  39027. return false;
  39028. }
  39029. } else {
  39030. if ($key != $test['tag']) {
  39031. if (isset($test['multiple']) && $test['multiple'] != '*') {
  39032. $unfoundtags[] = $test['tag'];
  39033. $this->_invalidTagOrder($unfoundtags, $key, $root);
  39034. return false;
  39035. } else {
  39036. if ($key) {
  39037. $mismatch = true;
  39038. }
  39039. $unfoundtags[] = $test['tag'];
  39040. $optionaltags[] = $test['tag'];
  39041. }
  39042. if (!isset($test['multiple'])) {
  39043. $this->_invalidTagOrder($unfoundtags, $key, $root);
  39044. return false;
  39045. }
  39046. continue;
  39047. } else {
  39048. $unfoundtags = $optionaltags = array();
  39049. $mismatch = false;
  39050. }
  39051. $key = next($keys);
  39052. while ($key == 'attribs' || $key == '_contents') {
  39053. $key = next($keys);
  39054. }
  39055. if ($key && $key != $test['tag'] && isset($test['multiple'])) {
  39056. $unfoundtags[] = $test['tag'];
  39057. $optionaltags[] = $test['tag'];
  39058. $mismatch = true;
  39059. }
  39060. $ret &= $this->_processAttribs($test, $tag, $root);
  39061. continue;
  39062. }
  39063. }
  39064. if (!$mismatch && count($optionaltags)) {
  39065. // don't error out on any optional tags
  39066. $unfoundtags = array_diff($unfoundtags, $optionaltags);
  39067. }
  39068. if (count($unfoundtags)) {
  39069. $this->_invalidTagOrder($unfoundtags, $key, $root);
  39070. } elseif ($key) {
  39071. // unknown tags
  39072. $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
  39073. while ($key = next($keys)) {
  39074. $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
  39075. }
  39076. }
  39077. return $ret;
  39078. }
  39079. function _processAttribs($choice, $tag, $context)
  39080. {
  39081. if (isset($choice['attribs'])) {
  39082. if (!is_array($tag)) {
  39083. $tag = array($tag);
  39084. }
  39085. $tags = $tag;
  39086. if (!isset($tags[0])) {
  39087. $tags = array($tags);
  39088. }
  39089. $ret = true;
  39090. foreach ($tags as $i => $tag) {
  39091. if (!is_array($tag) || !isset($tag['attribs'])) {
  39092. foreach ($choice['attribs'] as $attrib) {
  39093. if ($attrib[0] != '?') {
  39094. $ret &= $this->_tagHasNoAttribs($choice['tag'],
  39095. $context);
  39096. continue 2;
  39097. }
  39098. }
  39099. }
  39100. foreach ($choice['attribs'] as $attrib) {
  39101. if ($attrib[0] != '?') {
  39102. if (!isset($tag['attribs'][$attrib])) {
  39103. $ret &= $this->_tagMissingAttribute($choice['tag'],
  39104. $attrib, $context);
  39105. }
  39106. }
  39107. }
  39108. }
  39109. return $ret;
  39110. }
  39111. return true;
  39112. }
  39113. function _processStructure($key)
  39114. {
  39115. $ret = array();
  39116. if (count($pieces = explode('|', $key)) > 1) {
  39117. $ret['choices'] = array();
  39118. foreach ($pieces as $piece) {
  39119. $ret['choices'][] = $this->_processStructure($piece);
  39120. }
  39121. return $ret;
  39122. }
  39123. $multi = $key[0];
  39124. if ($multi == '+' || $multi == '*') {
  39125. $ret['multiple'] = $key[0];
  39126. $key = substr($key, 1);
  39127. }
  39128. if (count($attrs = explode('->', $key)) > 1) {
  39129. $ret['tag'] = array_shift($attrs);
  39130. $ret['attribs'] = $attrs;
  39131. } else {
  39132. $ret['tag'] = $key;
  39133. }
  39134. return $ret;
  39135. }
  39136. function _validateStabilityVersion()
  39137. {
  39138. $structure = array('release', 'api');
  39139. $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], '<version>');
  39140. $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '<stability>');
  39141. if ($a) {
  39142. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39143. $this->_packageInfo['version']['release'])) {
  39144. $this->_invalidVersion('release', $this->_packageInfo['version']['release']);
  39145. }
  39146. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39147. $this->_packageInfo['version']['api'])) {
  39148. $this->_invalidVersion('api', $this->_packageInfo['version']['api']);
  39149. }
  39150. if (!in_array($this->_packageInfo['stability']['release'],
  39151. array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) {
  39152. $this->_invalidState('release', $this->_packageInfo['stability']['release']);
  39153. }
  39154. if (!in_array($this->_packageInfo['stability']['api'],
  39155. array('devel', 'alpha', 'beta', 'stable'))) {
  39156. $this->_invalidState('api', $this->_packageInfo['stability']['api']);
  39157. }
  39158. }
  39159. }
  39160. function _validateMaintainers()
  39161. {
  39162. $structure =
  39163. array(
  39164. 'name',
  39165. 'user',
  39166. 'email',
  39167. 'active',
  39168. );
  39169. foreach (array('lead', 'developer', 'contributor', 'helper') as $type) {
  39170. if (!isset($this->_packageInfo[$type])) {
  39171. continue;
  39172. }
  39173. if (isset($this->_packageInfo[$type][0])) {
  39174. foreach ($this->_packageInfo[$type] as $lead) {
  39175. $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>');
  39176. }
  39177. } else {
  39178. $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type],
  39179. '<' . $type . '>');
  39180. }
  39181. }
  39182. }
  39183. function _validatePhpDep($dep, $installcondition = false)
  39184. {
  39185. $structure = array(
  39186. 'min',
  39187. '*max',
  39188. '*exclude',
  39189. );
  39190. $type = $installcondition ? '<installcondition><php>' : '<dependencies><required><php>';
  39191. $this->_stupidSchemaValidate($structure, $dep, $type);
  39192. if (isset($dep['min'])) {
  39193. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
  39194. $dep['min'])) {
  39195. $this->_invalidVersion($type . '<min>', $dep['min']);
  39196. }
  39197. }
  39198. if (isset($dep['max'])) {
  39199. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
  39200. $dep['max'])) {
  39201. $this->_invalidVersion($type . '<max>', $dep['max']);
  39202. }
  39203. }
  39204. if (isset($dep['exclude'])) {
  39205. if (!is_array($dep['exclude'])) {
  39206. $dep['exclude'] = array($dep['exclude']);
  39207. }
  39208. foreach ($dep['exclude'] as $exclude) {
  39209. if (!preg_match(
  39210. '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
  39211. $exclude)) {
  39212. $this->_invalidVersion($type . '<exclude>', $exclude);
  39213. }
  39214. }
  39215. }
  39216. }
  39217. function _validatePearinstallerDep($dep)
  39218. {
  39219. $structure = array(
  39220. 'min',
  39221. '*max',
  39222. '*recommended',
  39223. '*exclude',
  39224. );
  39225. $this->_stupidSchemaValidate($structure, $dep, '<dependencies><required><pearinstaller>');
  39226. if (isset($dep['min'])) {
  39227. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39228. $dep['min'])) {
  39229. $this->_invalidVersion('<dependencies><required><pearinstaller><min>',
  39230. $dep['min']);
  39231. }
  39232. }
  39233. if (isset($dep['max'])) {
  39234. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39235. $dep['max'])) {
  39236. $this->_invalidVersion('<dependencies><required><pearinstaller><max>',
  39237. $dep['max']);
  39238. }
  39239. }
  39240. if (isset($dep['recommended'])) {
  39241. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39242. $dep['recommended'])) {
  39243. $this->_invalidVersion('<dependencies><required><pearinstaller><recommended>',
  39244. $dep['recommended']);
  39245. }
  39246. }
  39247. if (isset($dep['exclude'])) {
  39248. if (!is_array($dep['exclude'])) {
  39249. $dep['exclude'] = array($dep['exclude']);
  39250. }
  39251. foreach ($dep['exclude'] as $exclude) {
  39252. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39253. $exclude)) {
  39254. $this->_invalidVersion('<dependencies><required><pearinstaller><exclude>',
  39255. $exclude);
  39256. }
  39257. }
  39258. }
  39259. }
  39260. function _validatePackageDep($dep, $group, $type = '<package>')
  39261. {
  39262. if (isset($dep['uri'])) {
  39263. if (isset($dep['conflicts'])) {
  39264. $structure = array(
  39265. 'name',
  39266. 'uri',
  39267. 'conflicts',
  39268. '*providesextension',
  39269. );
  39270. } else {
  39271. $structure = array(
  39272. 'name',
  39273. 'uri',
  39274. '*providesextension',
  39275. );
  39276. }
  39277. } else {
  39278. if (isset($dep['conflicts'])) {
  39279. $structure = array(
  39280. 'name',
  39281. 'channel',
  39282. '*min',
  39283. '*max',
  39284. '*exclude',
  39285. 'conflicts',
  39286. '*providesextension',
  39287. );
  39288. } else {
  39289. $structure = array(
  39290. 'name',
  39291. 'channel',
  39292. '*min',
  39293. '*max',
  39294. '*recommended',
  39295. '*exclude',
  39296. '*nodefault',
  39297. '*providesextension',
  39298. );
  39299. }
  39300. }
  39301. if (isset($dep['name'])) {
  39302. $type .= '<name>' . $dep['name'] . '</name>';
  39303. }
  39304. $this->_stupidSchemaValidate($structure, $dep, '<dependencies>' . $group . $type);
  39305. if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) ||
  39306. isset($dep['recommended']) || isset($dep['exclude']))) {
  39307. $this->_uriDepsCannotHaveVersioning('<dependencies>' . $group . $type);
  39308. }
  39309. if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') {
  39310. $this->_DepchannelCannotBeUri('<dependencies>' . $group . $type);
  39311. }
  39312. if (isset($dep['min'])) {
  39313. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39314. $dep['min'])) {
  39315. $this->_invalidVersion('<dependencies>' . $group . $type . '<min>', $dep['min']);
  39316. }
  39317. }
  39318. if (isset($dep['max'])) {
  39319. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39320. $dep['max'])) {
  39321. $this->_invalidVersion('<dependencies>' . $group . $type . '<max>', $dep['max']);
  39322. }
  39323. }
  39324. if (isset($dep['recommended'])) {
  39325. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39326. $dep['recommended'])) {
  39327. $this->_invalidVersion('<dependencies>' . $group . $type . '<recommended>',
  39328. $dep['recommended']);
  39329. }
  39330. }
  39331. if (isset($dep['exclude'])) {
  39332. if (!is_array($dep['exclude'])) {
  39333. $dep['exclude'] = array($dep['exclude']);
  39334. }
  39335. foreach ($dep['exclude'] as $exclude) {
  39336. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39337. $exclude)) {
  39338. $this->_invalidVersion('<dependencies>' . $group . $type . '<exclude>',
  39339. $exclude);
  39340. }
  39341. }
  39342. }
  39343. }
  39344. function _validateSubpackageDep($dep, $group)
  39345. {
  39346. $this->_validatePackageDep($dep, $group, '<subpackage>');
  39347. if (isset($dep['providesextension'])) {
  39348. $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : '');
  39349. }
  39350. if (isset($dep['conflicts'])) {
  39351. $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : '');
  39352. }
  39353. }
  39354. function _validateExtensionDep($dep, $group = false, $installcondition = false)
  39355. {
  39356. if (isset($dep['conflicts'])) {
  39357. $structure = array(
  39358. 'name',
  39359. '*min',
  39360. '*max',
  39361. '*exclude',
  39362. 'conflicts',
  39363. );
  39364. } else {
  39365. $structure = array(
  39366. 'name',
  39367. '*min',
  39368. '*max',
  39369. '*recommended',
  39370. '*exclude',
  39371. );
  39372. }
  39373. if ($installcondition) {
  39374. $type = '<installcondition><extension>';
  39375. } else {
  39376. $type = '<dependencies>' . $group . '<extension>';
  39377. }
  39378. if (isset($dep['name'])) {
  39379. $type .= '<name>' . $dep['name'] . '</name>';
  39380. }
  39381. $this->_stupidSchemaValidate($structure, $dep, $type);
  39382. if (isset($dep['min'])) {
  39383. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39384. $dep['min'])) {
  39385. $this->_invalidVersion(substr($type, 1) . '<min', $dep['min']);
  39386. }
  39387. }
  39388. if (isset($dep['max'])) {
  39389. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39390. $dep['max'])) {
  39391. $this->_invalidVersion(substr($type, 1) . '<max', $dep['max']);
  39392. }
  39393. }
  39394. if (isset($dep['recommended'])) {
  39395. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39396. $dep['recommended'])) {
  39397. $this->_invalidVersion(substr($type, 1) . '<recommended', $dep['recommended']);
  39398. }
  39399. }
  39400. if (isset($dep['exclude'])) {
  39401. if (!is_array($dep['exclude'])) {
  39402. $dep['exclude'] = array($dep['exclude']);
  39403. }
  39404. foreach ($dep['exclude'] as $exclude) {
  39405. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39406. $exclude)) {
  39407. $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
  39408. }
  39409. }
  39410. }
  39411. }
  39412. function _validateOsDep($dep, $installcondition = false)
  39413. {
  39414. $structure = array(
  39415. 'name',
  39416. '*conflicts',
  39417. );
  39418. $type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>';
  39419. if ($this->_stupidSchemaValidate($structure, $dep, $type)) {
  39420. if ($dep['name'] == '*') {
  39421. if (array_key_exists('conflicts', $dep)) {
  39422. $this->_cannotConflictWithAllOs($type);
  39423. }
  39424. }
  39425. }
  39426. }
  39427. function _validateArchDep($dep, $installcondition = false)
  39428. {
  39429. $structure = array(
  39430. 'pattern',
  39431. '*conflicts',
  39432. );
  39433. $type = $installcondition ? '<installcondition><arch>' : '<dependencies><required><arch>';
  39434. $this->_stupidSchemaValidate($structure, $dep, $type);
  39435. }
  39436. function _validateInstallConditions($cond, $release)
  39437. {
  39438. $structure = array(
  39439. '*php',
  39440. '*extension',
  39441. '*os',
  39442. '*arch',
  39443. );
  39444. if (!$this->_stupidSchemaValidate($structure,
  39445. $cond, $release)) {
  39446. return false;
  39447. }
  39448. foreach (array('php', 'extension', 'os', 'arch') as $type) {
  39449. if (isset($cond[$type])) {
  39450. $iter = $cond[$type];
  39451. if (!is_array($iter) || !isset($iter[0])) {
  39452. $iter = array($iter);
  39453. }
  39454. foreach ($iter as $package) {
  39455. if ($type == 'extension') {
  39456. $this->{"_validate{$type}Dep"}($package, false, true);
  39457. } else {
  39458. $this->{"_validate{$type}Dep"}($package, true);
  39459. }
  39460. }
  39461. }
  39462. }
  39463. }
  39464. function _validateDependencies()
  39465. {
  39466. $structure = array(
  39467. 'required',
  39468. '*optional',
  39469. '*group->name->hint'
  39470. );
  39471. if (!$this->_stupidSchemaValidate($structure,
  39472. $this->_packageInfo['dependencies'], '<dependencies>')) {
  39473. return false;
  39474. }
  39475. foreach (array('required', 'optional') as $simpledep) {
  39476. if (isset($this->_packageInfo['dependencies'][$simpledep])) {
  39477. if ($simpledep == 'optional') {
  39478. $structure = array(
  39479. '*package',
  39480. '*subpackage',
  39481. '*extension',
  39482. );
  39483. } else {
  39484. $structure = array(
  39485. 'php',
  39486. 'pearinstaller',
  39487. '*package',
  39488. '*subpackage',
  39489. '*extension',
  39490. '*os',
  39491. '*arch',
  39492. );
  39493. }
  39494. if ($this->_stupidSchemaValidate($structure,
  39495. $this->_packageInfo['dependencies'][$simpledep],
  39496. "<dependencies><$simpledep>")) {
  39497. foreach (array('package', 'subpackage', 'extension') as $type) {
  39498. if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
  39499. $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
  39500. if (!isset($iter[0])) {
  39501. $iter = array($iter);
  39502. }
  39503. foreach ($iter as $package) {
  39504. if ($type != 'extension') {
  39505. if (isset($package['uri'])) {
  39506. if (isset($package['channel'])) {
  39507. $this->_UrlOrChannel($type,
  39508. $package['name']);
  39509. }
  39510. } else {
  39511. if (!isset($package['channel'])) {
  39512. $this->_NoChannel($type, $package['name']);
  39513. }
  39514. }
  39515. }
  39516. $this->{"_validate{$type}Dep"}($package, "<$simpledep>");
  39517. }
  39518. }
  39519. }
  39520. if ($simpledep == 'optional') {
  39521. continue;
  39522. }
  39523. foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) {
  39524. if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
  39525. $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
  39526. if (!isset($iter[0])) {
  39527. $iter = array($iter);
  39528. }
  39529. foreach ($iter as $package) {
  39530. $this->{"_validate{$type}Dep"}($package);
  39531. }
  39532. }
  39533. }
  39534. }
  39535. }
  39536. }
  39537. if (isset($this->_packageInfo['dependencies']['group'])) {
  39538. $groups = $this->_packageInfo['dependencies']['group'];
  39539. if (!isset($groups[0])) {
  39540. $groups = array($groups);
  39541. }
  39542. $structure = array(
  39543. '*package',
  39544. '*subpackage',
  39545. '*extension',
  39546. );
  39547. foreach ($groups as $group) {
  39548. if ($this->_stupidSchemaValidate($structure, $group, '<group>')) {
  39549. if (!PEAR_Validate::validGroupName($group['attribs']['name'])) {
  39550. $this->_invalidDepGroupName($group['attribs']['name']);
  39551. }
  39552. foreach (array('package', 'subpackage', 'extension') as $type) {
  39553. if (isset($group[$type])) {
  39554. $iter = $group[$type];
  39555. if (!isset($iter[0])) {
  39556. $iter = array($iter);
  39557. }
  39558. foreach ($iter as $package) {
  39559. if ($type != 'extension') {
  39560. if (isset($package['uri'])) {
  39561. if (isset($package['channel'])) {
  39562. $this->_UrlOrChannelGroup($type,
  39563. $package['name'],
  39564. $group['name']);
  39565. }
  39566. } else {
  39567. if (!isset($package['channel'])) {
  39568. $this->_NoChannelGroup($type,
  39569. $package['name'],
  39570. $group['name']);
  39571. }
  39572. }
  39573. }
  39574. $this->{"_validate{$type}Dep"}($package, '<group name="' .
  39575. $group['attribs']['name'] . '">');
  39576. }
  39577. }
  39578. }
  39579. }
  39580. }
  39581. }
  39582. }
  39583. function _validateCompatible()
  39584. {
  39585. $compat = $this->_packageInfo['compatible'];
  39586. if (!isset($compat[0])) {
  39587. $compat = array($compat);
  39588. }
  39589. $required = array('name', 'channel', 'min', 'max', '*exclude');
  39590. foreach ($compat as $package) {
  39591. $type = '<compatible>';
  39592. if (is_array($package) && array_key_exists('name', $package)) {
  39593. $type .= '<name>' . $package['name'] . '</name>';
  39594. }
  39595. $this->_stupidSchemaValidate($required, $package, $type);
  39596. if (is_array($package) && array_key_exists('min', $package)) {
  39597. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39598. $package['min'])) {
  39599. $this->_invalidVersion(substr($type, 1) . '<min', $package['min']);
  39600. }
  39601. }
  39602. if (is_array($package) && array_key_exists('max', $package)) {
  39603. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39604. $package['max'])) {
  39605. $this->_invalidVersion(substr($type, 1) . '<max', $package['max']);
  39606. }
  39607. }
  39608. if (is_array($package) && array_key_exists('exclude', $package)) {
  39609. if (!is_array($package['exclude'])) {
  39610. $package['exclude'] = array($package['exclude']);
  39611. }
  39612. foreach ($package['exclude'] as $exclude) {
  39613. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  39614. $exclude)) {
  39615. $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
  39616. }
  39617. }
  39618. }
  39619. }
  39620. }
  39621. function _validateBundle($list)
  39622. {
  39623. if (!is_array($list) || !isset($list['bundledpackage'])) {
  39624. return $this->_NoBundledPackages();
  39625. }
  39626. if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) {
  39627. return $this->_AtLeast2BundledPackages();
  39628. }
  39629. foreach ($list['bundledpackage'] as $package) {
  39630. if (!is_string($package)) {
  39631. $this->_bundledPackagesMustBeFilename();
  39632. }
  39633. }
  39634. }
  39635. function _validateFilelist($list = false, $allowignore = false, $dirs = '')
  39636. {
  39637. $iscontents = false;
  39638. if (!$list) {
  39639. $iscontents = true;
  39640. $list = $this->_packageInfo['contents'];
  39641. if (isset($this->_packageInfo['bundle'])) {
  39642. return $this->_validateBundle($list);
  39643. }
  39644. }
  39645. if ($allowignore) {
  39646. $struc = array(
  39647. '*install->name->as',
  39648. '*ignore->name'
  39649. );
  39650. } else {
  39651. $struc = array(
  39652. '*dir->name->?baseinstalldir',
  39653. '*file->name->role->?baseinstalldir->?md5sum'
  39654. );
  39655. if (isset($list['dir']) && isset($list['file'])) {
  39656. // stave off validation errors without requiring a set order.
  39657. $_old = $list;
  39658. if (isset($list['attribs'])) {
  39659. $list = array('attribs' => $_old['attribs']);
  39660. }
  39661. $list['dir'] = $_old['dir'];
  39662. $list['file'] = $_old['file'];
  39663. }
  39664. }
  39665. if (!isset($list['attribs']) || !isset($list['attribs']['name'])) {
  39666. $unknown = $allowignore ? '<filelist>' : '<dir name="*unknown*">';
  39667. $dirname = $iscontents ? '<contents>' : $unknown;
  39668. } else {
  39669. $dirname = '<dir name="' . $list['attribs']['name'] . '">';
  39670. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  39671. str_replace('\\', '/', $list['attribs']['name']))) {
  39672. // file contains .. parent directory or . cur directory
  39673. $this->_invalidDirName($list['attribs']['name']);
  39674. }
  39675. }
  39676. $res = $this->_stupidSchemaValidate($struc, $list, $dirname);
  39677. if ($allowignore && $res) {
  39678. $ignored_or_installed = array();
  39679. $this->_pf->getFilelist();
  39680. $fcontents = $this->_pf->getContents();
  39681. $filelist = array();
  39682. if (!isset($fcontents['dir']['file'][0])) {
  39683. $fcontents['dir']['file'] = array($fcontents['dir']['file']);
  39684. }
  39685. foreach ($fcontents['dir']['file'] as $file) {
  39686. $filelist[$file['attribs']['name']] = true;
  39687. }
  39688. if (isset($list['install'])) {
  39689. if (!isset($list['install'][0])) {
  39690. $list['install'] = array($list['install']);
  39691. }
  39692. foreach ($list['install'] as $file) {
  39693. if (!isset($filelist[$file['attribs']['name']])) {
  39694. $this->_notInContents($file['attribs']['name'], 'install');
  39695. continue;
  39696. }
  39697. if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {
  39698. $this->_multipleInstallAs($file['attribs']['name']);
  39699. }
  39700. if (!isset($ignored_or_installed[$file['attribs']['name']])) {
  39701. $ignored_or_installed[$file['attribs']['name']] = array();
  39702. }
  39703. $ignored_or_installed[$file['attribs']['name']][] = 1;
  39704. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  39705. str_replace('\\', '/', $file['attribs']['as']))) {
  39706. // file contains .. parent directory or . cur directory references
  39707. $this->_invalidFileInstallAs($file['attribs']['name'],
  39708. $file['attribs']['as']);
  39709. }
  39710. }
  39711. }
  39712. if (isset($list['ignore'])) {
  39713. if (!isset($list['ignore'][0])) {
  39714. $list['ignore'] = array($list['ignore']);
  39715. }
  39716. foreach ($list['ignore'] as $file) {
  39717. if (!isset($filelist[$file['attribs']['name']])) {
  39718. $this->_notInContents($file['attribs']['name'], 'ignore');
  39719. continue;
  39720. }
  39721. if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {
  39722. $this->_ignoreAndInstallAs($file['attribs']['name']);
  39723. }
  39724. }
  39725. }
  39726. }
  39727. if (!$allowignore && isset($list['file'])) {
  39728. if (is_string($list['file'])) {
  39729. $this->_oldStyleFileNotAllowed();
  39730. return false;
  39731. }
  39732. if (!isset($list['file'][0])) {
  39733. // single file
  39734. $list['file'] = array($list['file']);
  39735. }
  39736. foreach ($list['file'] as $i => $file)
  39737. {
  39738. if (isset($file['attribs']) && isset($file['attribs']['name'])) {
  39739. if ($file['attribs']['name'][0] == '.' &&
  39740. $file['attribs']['name'][1] == '/') {
  39741. // name is something like "./doc/whatever.txt"
  39742. $this->_invalidFileName($file['attribs']['name'], $dirname);
  39743. }
  39744. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  39745. str_replace('\\', '/', $file['attribs']['name']))) {
  39746. // file contains .. parent directory or . cur directory
  39747. $this->_invalidFileName($file['attribs']['name'], $dirname);
  39748. }
  39749. }
  39750. if (isset($file['attribs']) && isset($file['attribs']['role'])) {
  39751. if (!$this->_validateRole($file['attribs']['role'])) {
  39752. if (isset($this->_packageInfo['usesrole'])) {
  39753. $roles = $this->_packageInfo['usesrole'];
  39754. if (!isset($roles[0])) {
  39755. $roles = array($roles);
  39756. }
  39757. foreach ($roles as $role) {
  39758. if ($role['role'] = $file['attribs']['role']) {
  39759. $msg = 'This package contains role "%role%" and requires ' .
  39760. 'package "%package%" to be used';
  39761. if (isset($role['uri'])) {
  39762. $params = array('role' => $role['role'],
  39763. 'package' => $role['uri']);
  39764. } else {
  39765. $params = array('role' => $role['role'],
  39766. 'package' => $this->_pf->_registry->
  39767. parsedPackageNameToString(array('package' =>
  39768. $role['package'], 'channel' => $role['channel']),
  39769. true));
  39770. }
  39771. $this->_stack->push('_mustInstallRole', 'error', $params, $msg);
  39772. }
  39773. }
  39774. }
  39775. $this->_invalidFileRole($file['attribs']['name'],
  39776. $dirname, $file['attribs']['role']);
  39777. }
  39778. }
  39779. if (!isset($file['attribs'])) {
  39780. continue;
  39781. }
  39782. $save = $file['attribs'];
  39783. if ($dirs) {
  39784. $save['name'] = $dirs . '/' . $save['name'];
  39785. }
  39786. unset($file['attribs']);
  39787. if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks
  39788. foreach ($file as $task => $value) {
  39789. if ($tagClass = $this->_pf->getTask($task)) {
  39790. if (!is_array($value) || !isset($value[0])) {
  39791. $value = array($value);
  39792. }
  39793. foreach ($value as $v) {
  39794. $ret = call_user_func(array($tagClass, 'validateXml'),
  39795. $this->_pf, $v, $this->_pf->_config, $save);
  39796. if (is_array($ret)) {
  39797. $this->_invalidTask($task, $ret, isset($save['name']) ?
  39798. $save['name'] : '');
  39799. }
  39800. }
  39801. } else {
  39802. if (isset($this->_packageInfo['usestask'])) {
  39803. $roles = $this->_packageInfo['usestask'];
  39804. if (!isset($roles[0])) {
  39805. $roles = array($roles);
  39806. }
  39807. foreach ($roles as $role) {
  39808. if ($role['task'] = $task) {
  39809. $msg = 'This package contains task "%task%" and requires ' .
  39810. 'package "%package%" to be used';
  39811. if (isset($role['uri'])) {
  39812. $params = array('task' => $role['task'],
  39813. 'package' => $role['uri']);
  39814. } else {
  39815. $params = array('task' => $role['task'],
  39816. 'package' => $this->_pf->_registry->
  39817. parsedPackageNameToString(array('package' =>
  39818. $role['package'], 'channel' => $role['channel']),
  39819. true));
  39820. }
  39821. $this->_stack->push('_mustInstallTask', 'error',
  39822. $params, $msg);
  39823. }
  39824. }
  39825. }
  39826. $this->_unknownTask($task, $save['name']);
  39827. }
  39828. }
  39829. }
  39830. }
  39831. }
  39832. if (isset($list['ignore'])) {
  39833. if (!$allowignore) {
  39834. $this->_ignoreNotAllowed('ignore');
  39835. }
  39836. }
  39837. if (isset($list['install'])) {
  39838. if (!$allowignore) {
  39839. $this->_ignoreNotAllowed('install');
  39840. }
  39841. }
  39842. if (isset($list['file'])) {
  39843. if ($allowignore) {
  39844. $this->_fileNotAllowed('file');
  39845. }
  39846. }
  39847. if (isset($list['dir'])) {
  39848. if ($allowignore) {
  39849. $this->_fileNotAllowed('dir');
  39850. } else {
  39851. if (!isset($list['dir'][0])) {
  39852. $list['dir'] = array($list['dir']);
  39853. }
  39854. foreach ($list['dir'] as $dir) {
  39855. if (isset($dir['attribs']) && isset($dir['attribs']['name'])) {
  39856. if ($dir['attribs']['name'] == '/' ||
  39857. !isset($this->_packageInfo['contents']['dir']['dir'])) {
  39858. // always use nothing if the filelist has already been flattened
  39859. $newdirs = '';
  39860. } elseif ($dirs == '') {
  39861. $newdirs = $dir['attribs']['name'];
  39862. } else {
  39863. $newdirs = $dirs . '/' . $dir['attribs']['name'];
  39864. }
  39865. } else {
  39866. $newdirs = $dirs;
  39867. }
  39868. $this->_validateFilelist($dir, $allowignore, $newdirs);
  39869. }
  39870. }
  39871. }
  39872. }
  39873. function _validateRelease()
  39874. {
  39875. if (isset($this->_packageInfo['phprelease'])) {
  39876. $release = 'phprelease';
  39877. if (isset($this->_packageInfo['providesextension'])) {
  39878. $this->_cannotProvideExtension($release);
  39879. }
  39880. if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
  39881. $this->_cannotHaveSrcpackage($release);
  39882. }
  39883. $releases = $this->_packageInfo['phprelease'];
  39884. if (!is_array($releases)) {
  39885. return true;
  39886. }
  39887. if (!isset($releases[0])) {
  39888. $releases = array($releases);
  39889. }
  39890. foreach ($releases as $rel) {
  39891. $this->_stupidSchemaValidate(array(
  39892. '*installconditions',
  39893. '*filelist',
  39894. ), $rel, '<phprelease>');
  39895. }
  39896. }
  39897. foreach (array('', 'zend') as $prefix) {
  39898. $releasetype = $prefix . 'extsrcrelease';
  39899. if (isset($this->_packageInfo[$releasetype])) {
  39900. $release = $releasetype;
  39901. if (!isset($this->_packageInfo['providesextension'])) {
  39902. $this->_mustProvideExtension($release);
  39903. }
  39904. if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
  39905. $this->_cannotHaveSrcpackage($release);
  39906. }
  39907. $releases = $this->_packageInfo[$releasetype];
  39908. if (!is_array($releases)) {
  39909. return true;
  39910. }
  39911. if (!isset($releases[0])) {
  39912. $releases = array($releases);
  39913. }
  39914. foreach ($releases as $rel) {
  39915. $this->_stupidSchemaValidate(array(
  39916. '*installconditions',
  39917. '*configureoption->name->prompt->?default',
  39918. '*binarypackage',
  39919. '*filelist',
  39920. ), $rel, '<' . $releasetype . '>');
  39921. if (isset($rel['binarypackage'])) {
  39922. if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) {
  39923. $rel['binarypackage'] = array($rel['binarypackage']);
  39924. }
  39925. foreach ($rel['binarypackage'] as $bin) {
  39926. if (!is_string($bin)) {
  39927. $this->_binaryPackageMustBePackagename();
  39928. }
  39929. }
  39930. }
  39931. }
  39932. }
  39933. $releasetype = 'extbinrelease';
  39934. if (isset($this->_packageInfo[$releasetype])) {
  39935. $release = $releasetype;
  39936. if (!isset($this->_packageInfo['providesextension'])) {
  39937. $this->_mustProvideExtension($release);
  39938. }
  39939. if (isset($this->_packageInfo['channel']) &&
  39940. !isset($this->_packageInfo['srcpackage'])) {
  39941. $this->_mustSrcPackage($release);
  39942. }
  39943. if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) {
  39944. $this->_mustSrcuri($release);
  39945. }
  39946. $releases = $this->_packageInfo[$releasetype];
  39947. if (!is_array($releases)) {
  39948. return true;
  39949. }
  39950. if (!isset($releases[0])) {
  39951. $releases = array($releases);
  39952. }
  39953. foreach ($releases as $rel) {
  39954. $this->_stupidSchemaValidate(array(
  39955. '*installconditions',
  39956. '*filelist',
  39957. ), $rel, '<' . $releasetype . '>');
  39958. }
  39959. }
  39960. }
  39961. if (isset($this->_packageInfo['bundle'])) {
  39962. $release = 'bundle';
  39963. if (isset($this->_packageInfo['providesextension'])) {
  39964. $this->_cannotProvideExtension($release);
  39965. }
  39966. if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
  39967. $this->_cannotHaveSrcpackage($release);
  39968. }
  39969. $releases = $this->_packageInfo['bundle'];
  39970. if (!is_array($releases) || !isset($releases[0])) {
  39971. $releases = array($releases);
  39972. }
  39973. foreach ($releases as $rel) {
  39974. $this->_stupidSchemaValidate(array(
  39975. '*installconditions',
  39976. '*filelist',
  39977. ), $rel, '<bundle>');
  39978. }
  39979. }
  39980. foreach ($releases as $rel) {
  39981. if (is_array($rel) && array_key_exists('installconditions', $rel)) {
  39982. $this->_validateInstallConditions($rel['installconditions'],
  39983. "<$release><installconditions>");
  39984. }
  39985. if (is_array($rel) && array_key_exists('filelist', $rel)) {
  39986. if ($rel['filelist']) {
  39987. $this->_validateFilelist($rel['filelist'], true);
  39988. }
  39989. }
  39990. }
  39991. }
  39992. /**
  39993. * This is here to allow role extension through plugins
  39994. * @param string
  39995. */
  39996. function _validateRole($role)
  39997. {
  39998. return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType()));
  39999. }
  40000. function _pearVersionTooLow($version)
  40001. {
  40002. $this->_stack->push(__FUNCTION__, 'error',
  40003. array('version' => $version),
  40004. 'This package.xml requires PEAR version %version% to parse properly, we are ' .
  40005. 'version 1.10.10');
  40006. }
  40007. function _invalidTagOrder($oktags, $actual, $root)
  40008. {
  40009. $this->_stack->push(__FUNCTION__, 'error',
  40010. array('oktags' => $oktags, 'actual' => $actual, 'root' => $root),
  40011. 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"');
  40012. }
  40013. function _ignoreNotAllowed($type)
  40014. {
  40015. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  40016. '<%type%> is not allowed inside global <contents>, only inside ' .
  40017. '<phprelease>/<extbinrelease>/<zendextbinrelease>, use <dir> and <file> only');
  40018. }
  40019. function _fileNotAllowed($type)
  40020. {
  40021. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  40022. '<%type%> is not allowed inside release <filelist>, only inside ' .
  40023. '<contents>, use <ignore> and <install> only');
  40024. }
  40025. function _oldStyleFileNotAllowed()
  40026. {
  40027. $this->_stack->push(__FUNCTION__, 'error', array(),
  40028. 'Old-style <file>name</file> is not allowed. Use' .
  40029. '<file name="name" role="role"/>');
  40030. }
  40031. function _tagMissingAttribute($tag, $attr, $context)
  40032. {
  40033. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
  40034. 'attribute' => $attr, 'context' => $context),
  40035. 'tag <%tag%> in context "%context%" has no attribute "%attribute%"');
  40036. }
  40037. function _tagHasNoAttribs($tag, $context)
  40038. {
  40039. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
  40040. 'context' => $context),
  40041. 'tag <%tag%> has no attributes in context "%context%"');
  40042. }
  40043. function _invalidInternalStructure()
  40044. {
  40045. $this->_stack->push(__FUNCTION__, 'exception', array(),
  40046. 'internal array was not generated by compatible parser, or extreme parser error, cannot continue');
  40047. }
  40048. function _invalidFileRole($file, $dir, $role)
  40049. {
  40050. $this->_stack->push(__FUNCTION__, 'error', array(
  40051. 'file' => $file, 'dir' => $dir, 'role' => $role,
  40052. 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())),
  40053. 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%');
  40054. }
  40055. function _invalidFileName($file, $dir)
  40056. {
  40057. $this->_stack->push(__FUNCTION__, 'error', array(
  40058. 'file' => $file),
  40059. 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."');
  40060. }
  40061. function _invalidFileInstallAs($file, $as)
  40062. {
  40063. $this->_stack->push(__FUNCTION__, 'error', array(
  40064. 'file' => $file, 'as' => $as),
  40065. 'File "%file%" <install as="%as%"/> cannot contain "./" or contain ".."');
  40066. }
  40067. function _invalidDirName($dir)
  40068. {
  40069. $this->_stack->push(__FUNCTION__, 'error', array(
  40070. 'dir' => $file),
  40071. 'Directory "%dir%" cannot begin with "./" or contain ".."');
  40072. }
  40073. function _filelistCannotContainFile($filelist)
  40074. {
  40075. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
  40076. '<%tag%> can only contain <dir>, contains <file>. Use ' .
  40077. '<dir name="/"> as the first dir element');
  40078. }
  40079. function _filelistMustContainDir($filelist)
  40080. {
  40081. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
  40082. '<%tag%> must contain <dir>. Use <dir name="/"> as the ' .
  40083. 'first dir element');
  40084. }
  40085. function _tagCannotBeEmpty($tag)
  40086. {
  40087. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
  40088. '<%tag%> cannot be empty (<%tag%/>)');
  40089. }
  40090. function _UrlOrChannel($type, $name)
  40091. {
  40092. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  40093. 'name' => $name),
  40094. 'Required dependency <%type%> "%name%" can have either url OR ' .
  40095. 'channel attributes, and not both');
  40096. }
  40097. function _NoChannel($type, $name)
  40098. {
  40099. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  40100. 'name' => $name),
  40101. 'Required dependency <%type%> "%name%" must have either url OR ' .
  40102. 'channel attributes');
  40103. }
  40104. function _UrlOrChannelGroup($type, $name, $group)
  40105. {
  40106. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  40107. 'name' => $name, 'group' => $group),
  40108. 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .
  40109. 'channel attributes, and not both');
  40110. }
  40111. function _NoChannelGroup($type, $name, $group)
  40112. {
  40113. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  40114. 'name' => $name, 'group' => $group),
  40115. 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .
  40116. 'channel attributes');
  40117. }
  40118. function _unknownChannel($channel)
  40119. {
  40120. $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel),
  40121. 'Unknown channel "%channel%"');
  40122. }
  40123. function _noPackageVersion()
  40124. {
  40125. $this->_stack->push(__FUNCTION__, 'error', array(),
  40126. 'package.xml <package> tag has no version attribute, or version is not 2.0');
  40127. }
  40128. function _NoBundledPackages()
  40129. {
  40130. $this->_stack->push(__FUNCTION__, 'error', array(),
  40131. 'No <bundledpackage> tag was found in <contents>, required for bundle packages');
  40132. }
  40133. function _AtLeast2BundledPackages()
  40134. {
  40135. $this->_stack->push(__FUNCTION__, 'error', array(),
  40136. 'At least 2 packages must be bundled in a bundle package');
  40137. }
  40138. function _ChannelOrUri($name)
  40139. {
  40140. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  40141. 'Bundled package "%name%" can have either a uri or a channel, not both');
  40142. }
  40143. function _noChildTag($child, $tag)
  40144. {
  40145. $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag),
  40146. 'Tag <%tag%> is missing child tag <%child%>');
  40147. }
  40148. function _invalidVersion($type, $value)
  40149. {
  40150. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value),
  40151. 'Version type <%type%> is not a valid version (%value%)');
  40152. }
  40153. function _invalidState($type, $value)
  40154. {
  40155. $states = array('stable', 'beta', 'alpha', 'devel');
  40156. if ($type != 'api') {
  40157. $states[] = 'snapshot';
  40158. }
  40159. if (strtolower($value) == 'rc') {
  40160. $this->_stack->push(__FUNCTION__, 'error',
  40161. array('version' => $this->_packageInfo['version']['release']),
  40162. 'RC is not a state, it is a version postfix, try %version%RC1, stability beta');
  40163. }
  40164. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value,
  40165. 'types' => $states),
  40166. 'Stability type <%type%> is not a valid stability (%value%), must be one of ' .
  40167. '%types%');
  40168. }
  40169. function _invalidTask($task, $ret, $file)
  40170. {
  40171. switch ($ret[0]) {
  40172. case PEAR_TASK_ERROR_MISSING_ATTRIB :
  40173. $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file);
  40174. $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%';
  40175. break;
  40176. case PEAR_TASK_ERROR_NOATTRIBS :
  40177. $info = array('task' => $task, 'file' => $file);
  40178. $msg = 'task <%task%> has no attributes in file %file%';
  40179. break;
  40180. case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :
  40181. $info = array('attrib' => $ret[1], 'values' => $ret[3],
  40182. 'was' => $ret[2], 'task' => $task, 'file' => $file);
  40183. $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '.
  40184. 'in file %file%, expecting one of "%values%"';
  40185. break;
  40186. case PEAR_TASK_ERROR_INVALID :
  40187. $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file);
  40188. $msg = 'task <%task%> in file %file% is invalid because of "%reason%"';
  40189. break;
  40190. }
  40191. $this->_stack->push(__FUNCTION__, 'error', $info, $msg);
  40192. }
  40193. function _unknownTask($task, $file)
  40194. {
  40195. $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file),
  40196. 'Unknown task "%task%" passed in file <file name="%file%">');
  40197. }
  40198. function _subpackageCannotProvideExtension($name)
  40199. {
  40200. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  40201. 'Subpackage dependency "%name%" cannot use <providesextension>, ' .
  40202. 'only package dependencies can use this tag');
  40203. }
  40204. function _subpackagesCannotConflict($name)
  40205. {
  40206. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  40207. 'Subpackage dependency "%name%" cannot use <conflicts/>, ' .
  40208. 'only package dependencies can use this tag');
  40209. }
  40210. function _cannotProvideExtension($release)
  40211. {
  40212. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  40213. '<%release%> packages cannot use <providesextension>, only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension');
  40214. }
  40215. function _mustProvideExtension($release)
  40216. {
  40217. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  40218. '<%release%> packages must use <providesextension> to indicate which PHP extension is provided');
  40219. }
  40220. function _cannotHaveSrcpackage($release)
  40221. {
  40222. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  40223. '<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag');
  40224. }
  40225. function _mustSrcPackage($release)
  40226. {
  40227. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  40228. '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcpackage>');
  40229. }
  40230. function _mustSrcuri($release)
  40231. {
  40232. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  40233. '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcuri>');
  40234. }
  40235. function _uriDepsCannotHaveVersioning($type)
  40236. {
  40237. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  40238. '%type%: dependencies with a <uri> tag cannot have any versioning information');
  40239. }
  40240. function _conflictingDepsCannotHaveVersioning($type)
  40241. {
  40242. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  40243. '%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' .
  40244. 'exclude specific versions of a dependency');
  40245. }
  40246. function _DepchannelCannotBeUri($type)
  40247. {
  40248. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  40249. '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .
  40250. 'dependencies only');
  40251. }
  40252. function _bundledPackagesMustBeFilename()
  40253. {
  40254. $this->_stack->push(__FUNCTION__, 'error', array(),
  40255. '<bundledpackage> tags must contain only the filename of a package release ' .
  40256. 'in the bundle');
  40257. }
  40258. function _binaryPackageMustBePackagename()
  40259. {
  40260. $this->_stack->push(__FUNCTION__, 'error', array(),
  40261. '<binarypackage> tags must contain the name of a package that is ' .
  40262. 'a compiled version of this extsrc/zendextsrc package');
  40263. }
  40264. function _fileNotFound($file)
  40265. {
  40266. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  40267. 'File "%file%" in package.xml does not exist');
  40268. }
  40269. function _notInContents($file, $tag)
  40270. {
  40271. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag),
  40272. '<%tag% name="%file%"> is invalid, file is not in <contents>');
  40273. }
  40274. function _cannotValidateNoPathSet()
  40275. {
  40276. $this->_stack->push(__FUNCTION__, 'error', array(),
  40277. 'Cannot validate files, no path to package file is set (use setPackageFile())');
  40278. }
  40279. function _usesroletaskMustHaveChannelOrUri($role, $tag)
  40280. {
  40281. $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
  40282. '<%tag%> for role "%role%" must contain either <uri>, or <channel> and <package>');
  40283. }
  40284. function _usesroletaskMustHavePackage($role, $tag)
  40285. {
  40286. $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
  40287. '<%tag%> for role "%role%" must contain <package>');
  40288. }
  40289. function _usesroletaskMustHaveRoleTask($tag, $type)
  40290. {
  40291. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type),
  40292. '<%tag%> must contain <%type%> defining the %type% to be used');
  40293. }
  40294. function _cannotConflictWithAllOs($type)
  40295. {
  40296. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
  40297. '%tag% cannot conflict with all OSes');
  40298. }
  40299. function _invalidDepGroupName($name)
  40300. {
  40301. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  40302. 'Invalid dependency group name "%name%"');
  40303. }
  40304. function _multipleToplevelDirNotAllowed()
  40305. {
  40306. $this->_stack->push(__FUNCTION__, 'error', array(),
  40307. 'Multiple top-level <dir> tags are not allowed. Enclose them ' .
  40308. 'in a <dir name="/">');
  40309. }
  40310. function _multipleInstallAs($file)
  40311. {
  40312. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  40313. 'Only one <install> tag is allowed for file "%file%"');
  40314. }
  40315. function _ignoreAndInstallAs($file)
  40316. {
  40317. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  40318. 'Cannot have both <ignore> and <install> tags for file "%file%"');
  40319. }
  40320. function _analyzeBundledPackages()
  40321. {
  40322. if (!$this->_isValid) {
  40323. return false;
  40324. }
  40325. if (!$this->_pf->getPackageType() == 'bundle') {
  40326. return false;
  40327. }
  40328. if (!isset($this->_pf->_packageFile)) {
  40329. return false;
  40330. }
  40331. $dir_prefix = dirname($this->_pf->_packageFile);
  40332. $common = new PEAR_Common;
  40333. $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
  40334. array($common, 'log');
  40335. $info = $this->_pf->getContents();
  40336. $info = $info['bundledpackage'];
  40337. if (!is_array($info)) {
  40338. $info = array($info);
  40339. }
  40340. $pkg = new PEAR_PackageFile($this->_pf->_config);
  40341. foreach ($info as $package) {
  40342. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) {
  40343. $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package);
  40344. $this->_isValid = 0;
  40345. continue;
  40346. }
  40347. call_user_func_array($log, array(1, "Analyzing bundled package $package"));
  40348. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  40349. $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package,
  40350. PEAR_VALIDATE_NORMAL);
  40351. PEAR::popErrorHandling();
  40352. if (PEAR::isError($ret)) {
  40353. call_user_func_array($log, array(0, "ERROR: package $package is not a valid " .
  40354. 'package'));
  40355. $inf = $ret->getUserInfo();
  40356. if (is_array($inf)) {
  40357. foreach ($inf as $err) {
  40358. call_user_func_array($log, array(1, $err['message']));
  40359. }
  40360. }
  40361. return false;
  40362. }
  40363. }
  40364. return true;
  40365. }
  40366. function _analyzePhpFiles()
  40367. {
  40368. if (!$this->_isValid) {
  40369. return false;
  40370. }
  40371. if (!isset($this->_pf->_packageFile)) {
  40372. $this->_cannotValidateNoPathSet();
  40373. return false;
  40374. }
  40375. $dir_prefix = dirname($this->_pf->_packageFile);
  40376. $common = new PEAR_Common;
  40377. $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
  40378. array(&$common, 'log');
  40379. $info = $this->_pf->getContents();
  40380. if (!$info || !isset($info['dir']['file'])) {
  40381. $this->_tagCannotBeEmpty('contents><dir');
  40382. return false;
  40383. }
  40384. $info = $info['dir']['file'];
  40385. if (isset($info['attribs'])) {
  40386. $info = array($info);
  40387. }
  40388. $provides = array();
  40389. foreach ($info as $fa) {
  40390. $fa = $fa['attribs'];
  40391. $file = $fa['name'];
  40392. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
  40393. $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file);
  40394. $this->_isValid = 0;
  40395. continue;
  40396. }
  40397. if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) {
  40398. call_user_func_array($log, array(1, "Analyzing $file"));
  40399. $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
  40400. if ($srcinfo) {
  40401. $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo));
  40402. }
  40403. }
  40404. }
  40405. $this->_packageName = $pn = $this->_pf->getPackage();
  40406. $pnl = strlen($pn);
  40407. foreach ($provides as $key => $what) {
  40408. if (isset($what['explicit']) || !$what) {
  40409. // skip conformance checks if the provides entry is
  40410. // specified in the package.xml file
  40411. continue;
  40412. }
  40413. extract($what);
  40414. if ($type == 'class') {
  40415. if (!strncasecmp($name, $pn, $pnl)) {
  40416. continue;
  40417. }
  40418. $this->_stack->push(__FUNCTION__, 'warning',
  40419. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
  40420. 'in %file%: %type% "%name%" not prefixed with package name "%package%"');
  40421. } elseif ($type == 'function') {
  40422. if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
  40423. continue;
  40424. }
  40425. $this->_stack->push(__FUNCTION__, 'warning',
  40426. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
  40427. 'in %file%: %type% "%name%" not prefixed with package name "%package%"');
  40428. }
  40429. }
  40430. return $this->_isValid;
  40431. }
  40432. /**
  40433. * Analyze the source code of the given PHP file
  40434. *
  40435. * @param string Filename of the PHP file
  40436. * @param boolean whether to analyze $file as the file contents
  40437. * @return mixed
  40438. */
  40439. function analyzeSourceCode($file, $string = false)
  40440. {
  40441. if (!function_exists("token_get_all")) {
  40442. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  40443. 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer');
  40444. return false;
  40445. }
  40446. if (!defined('T_DOC_COMMENT')) {
  40447. define('T_DOC_COMMENT', T_COMMENT);
  40448. }
  40449. if (!defined('T_INTERFACE')) {
  40450. define('T_INTERFACE', -1);
  40451. }
  40452. if (!defined('T_IMPLEMENTS')) {
  40453. define('T_IMPLEMENTS', -1);
  40454. }
  40455. if ($string) {
  40456. $contents = $file;
  40457. } else {
  40458. if (!$fp = @fopen($file, "r")) {
  40459. return false;
  40460. }
  40461. fclose($fp);
  40462. $contents = file_get_contents($file);
  40463. }
  40464. // Silence this function so we can catch PHP Warnings and show our own custom message
  40465. $tokens = @token_get_all($contents);
  40466. if (isset($php_errormsg)) {
  40467. if (isset($this->_stack)) {
  40468. $pn = $this->_pf->getPackage();
  40469. $this->_stack->push(__FUNCTION__, 'warning',
  40470. array('file' => $file, 'package' => $pn),
  40471. 'in %file%: Could not process file for unknown reasons,' .
  40472. ' possibly a PHP parse error in %file% from %package%');
  40473. }
  40474. }
  40475. /*
  40476. for ($i = 0; $i < sizeof($tokens); $i++) {
  40477. @list($token, $data) = $tokens[$i];
  40478. if (is_string($token)) {
  40479. var_dump($token);
  40480. } else {
  40481. print token_name($token) . ' ';
  40482. var_dump(rtrim($data));
  40483. }
  40484. }
  40485. */
  40486. $look_for = 0;
  40487. $paren_level = 0;
  40488. $bracket_level = 0;
  40489. $brace_level = 0;
  40490. $lastphpdoc = '';
  40491. $current_class = '';
  40492. $current_interface = '';
  40493. $current_class_level = -1;
  40494. $current_function = '';
  40495. $current_function_level = -1;
  40496. $declared_classes = array();
  40497. $declared_interfaces = array();
  40498. $declared_functions = array();
  40499. $declared_methods = array();
  40500. $used_classes = array();
  40501. $used_functions = array();
  40502. $extends = array();
  40503. $implements = array();
  40504. $nodeps = array();
  40505. $inquote = false;
  40506. $interface = false;
  40507. for ($i = 0; $i < sizeof($tokens); $i++) {
  40508. if (is_array($tokens[$i])) {
  40509. list($token, $data) = $tokens[$i];
  40510. } else {
  40511. $token = $tokens[$i];
  40512. $data = '';
  40513. }
  40514. if ($inquote) {
  40515. if ($token != '"' && $token != T_END_HEREDOC) {
  40516. continue;
  40517. } else {
  40518. $inquote = false;
  40519. continue;
  40520. }
  40521. }
  40522. switch ($token) {
  40523. case T_WHITESPACE :
  40524. continue 2;
  40525. case ';':
  40526. if ($interface) {
  40527. $current_function = '';
  40528. $current_function_level = -1;
  40529. }
  40530. break;
  40531. case '"':
  40532. case T_START_HEREDOC:
  40533. $inquote = true;
  40534. break;
  40535. case T_CURLY_OPEN:
  40536. case T_DOLLAR_OPEN_CURLY_BRACES:
  40537. case '{': $brace_level++; continue 2;
  40538. case '}':
  40539. $brace_level--;
  40540. if ($current_class_level == $brace_level) {
  40541. $current_class = '';
  40542. $current_class_level = -1;
  40543. }
  40544. if ($current_function_level == $brace_level) {
  40545. $current_function = '';
  40546. $current_function_level = -1;
  40547. }
  40548. continue 2;
  40549. case '[': $bracket_level++; continue 2;
  40550. case ']': $bracket_level--; continue 2;
  40551. case '(': $paren_level++; continue 2;
  40552. case ')': $paren_level--; continue 2;
  40553. case T_INTERFACE:
  40554. $interface = true;
  40555. case T_CLASS:
  40556. if (($current_class_level != -1) || ($current_function_level != -1)) {
  40557. if (isset($this->_stack)) {
  40558. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  40559. 'Parser error: invalid PHP found in file "%file%"');
  40560. } else {
  40561. PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  40562. PEAR_COMMON_ERROR_INVALIDPHP);
  40563. }
  40564. return false;
  40565. }
  40566. case T_FUNCTION:
  40567. case T_NEW:
  40568. case T_EXTENDS:
  40569. case T_IMPLEMENTS:
  40570. $look_for = $token;
  40571. continue 2;
  40572. case T_STRING:
  40573. if ($look_for == T_CLASS) {
  40574. $current_class = $data;
  40575. $current_class_level = $brace_level;
  40576. $declared_classes[] = $current_class;
  40577. } elseif ($look_for == T_INTERFACE) {
  40578. $current_interface = $data;
  40579. $current_class_level = $brace_level;
  40580. $declared_interfaces[] = $current_interface;
  40581. } elseif ($look_for == T_IMPLEMENTS) {
  40582. $implements[$current_class] = $data;
  40583. } elseif ($look_for == T_EXTENDS) {
  40584. $extends[$current_class] = $data;
  40585. } elseif ($look_for == T_FUNCTION) {
  40586. if ($current_class) {
  40587. $current_function = "$current_class::$data";
  40588. $declared_methods[$current_class][] = $data;
  40589. } elseif ($current_interface) {
  40590. $current_function = "$current_interface::$data";
  40591. $declared_methods[$current_interface][] = $data;
  40592. } else {
  40593. $current_function = $data;
  40594. $declared_functions[] = $current_function;
  40595. }
  40596. $current_function_level = $brace_level;
  40597. $m = array();
  40598. } elseif ($look_for == T_NEW) {
  40599. $used_classes[$data] = true;
  40600. }
  40601. $look_for = 0;
  40602. continue 2;
  40603. case T_VARIABLE:
  40604. $look_for = 0;
  40605. continue 2;
  40606. case T_DOC_COMMENT:
  40607. case T_COMMENT:
  40608. if (preg_match('!^/\*\*\s!', $data)) {
  40609. $lastphpdoc = $data;
  40610. if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  40611. $nodeps = array_merge($nodeps, $m[1]);
  40612. }
  40613. }
  40614. continue 2;
  40615. case T_DOUBLE_COLON:
  40616. $token = $tokens[$i - 1][0];
  40617. if (!($token == T_WHITESPACE || $token == T_STRING || $token == T_STATIC || $token == T_VARIABLE)) {
  40618. if (isset($this->_stack)) {
  40619. $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file),
  40620. 'Parser error: invalid PHP found in file "%file%"');
  40621. } else {
  40622. PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  40623. PEAR_COMMON_ERROR_INVALIDPHP);
  40624. }
  40625. return false;
  40626. }
  40627. $class = $tokens[$i - 1][1];
  40628. if (strtolower($class) != 'parent') {
  40629. $used_classes[$class] = true;
  40630. }
  40631. continue 2;
  40632. }
  40633. }
  40634. return array(
  40635. "source_file" => $file,
  40636. "declared_classes" => $declared_classes,
  40637. "declared_interfaces" => $declared_interfaces,
  40638. "declared_methods" => $declared_methods,
  40639. "declared_functions" => $declared_functions,
  40640. "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  40641. "inheritance" => $extends,
  40642. "implements" => $implements,
  40643. );
  40644. }
  40645. /**
  40646. * Build a "provides" array from data returned by
  40647. * analyzeSourceCode(). The format of the built array is like
  40648. * this:
  40649. *
  40650. * array(
  40651. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  40652. * ...
  40653. * )
  40654. *
  40655. *
  40656. * @param array $srcinfo array with information about a source file
  40657. * as returned by the analyzeSourceCode() method.
  40658. *
  40659. * @return void
  40660. *
  40661. * @access private
  40662. *
  40663. */
  40664. function _buildProvidesArray($srcinfo)
  40665. {
  40666. if (!$this->_isValid) {
  40667. return array();
  40668. }
  40669. $providesret = array();
  40670. $file = basename($srcinfo['source_file']);
  40671. $pn = isset($this->_pf) ? $this->_pf->getPackage() : '';
  40672. $pnl = strlen($pn);
  40673. foreach ($srcinfo['declared_classes'] as $class) {
  40674. $key = "class;$class";
  40675. if (isset($providesret[$key])) {
  40676. continue;
  40677. }
  40678. $providesret[$key] =
  40679. array('file'=> $file, 'type' => 'class', 'name' => $class);
  40680. if (isset($srcinfo['inheritance'][$class])) {
  40681. $providesret[$key]['extends'] =
  40682. $srcinfo['inheritance'][$class];
  40683. }
  40684. }
  40685. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  40686. foreach ($methods as $method) {
  40687. $function = "$class::$method";
  40688. $key = "function;$function";
  40689. if ($method[0] == '_' || !strcasecmp($method, $class) ||
  40690. isset($providesret[$key])) {
  40691. continue;
  40692. }
  40693. $providesret[$key] =
  40694. array('file'=> $file, 'type' => 'function', 'name' => $function);
  40695. }
  40696. }
  40697. foreach ($srcinfo['declared_functions'] as $function) {
  40698. $key = "function;$function";
  40699. if ($function[0] == '_' || isset($providesret[$key])) {
  40700. continue;
  40701. }
  40702. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  40703. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  40704. }
  40705. $providesret[$key] =
  40706. array('file'=> $file, 'type' => 'function', 'name' => $function);
  40707. }
  40708. return $providesret;
  40709. }
  40710. }
  40711. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/v1.php����������������������������������������������������������������0000644�0001750�0001750�00000142663�13565304531�016213� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  40712. /**
  40713. * PEAR_PackageFile_v1, package.xml version 1.0
  40714. *
  40715. * PHP versions 4 and 5
  40716. *
  40717. * @category pear
  40718. * @package PEAR
  40719. * @author Greg Beaver <cellog@php.net>
  40720. * @copyright 1997-2009 The Authors
  40721. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  40722. * @link http://pear.php.net/package/PEAR
  40723. * @since File available since Release 1.4.0a1
  40724. */
  40725. /**
  40726. * For error handling
  40727. */
  40728. require_once 'PEAR/ErrorStack.php';
  40729. /**
  40730. * Error code if parsing is attempted with no xml extension
  40731. */
  40732. define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
  40733. /**
  40734. * Error code if creating the xml parser resource fails
  40735. */
  40736. define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
  40737. /**
  40738. * Error code used for all sax xml parsing errors
  40739. */
  40740. define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
  40741. /**
  40742. * Error code used when there is no name
  40743. */
  40744. define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
  40745. /**
  40746. * Error code when a package name is not valid
  40747. */
  40748. define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
  40749. /**
  40750. * Error code used when no summary is parsed
  40751. */
  40752. define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
  40753. /**
  40754. * Error code for summaries that are more than 1 line
  40755. */
  40756. define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
  40757. /**
  40758. * Error code used when no description is present
  40759. */
  40760. define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
  40761. /**
  40762. * Error code used when no license is present
  40763. */
  40764. define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
  40765. /**
  40766. * Error code used when a <version> version number is not present
  40767. */
  40768. define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
  40769. /**
  40770. * Error code used when a <version> version number is invalid
  40771. */
  40772. define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
  40773. /**
  40774. * Error code when release state is missing
  40775. */
  40776. define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
  40777. /**
  40778. * Error code when release state is invalid
  40779. */
  40780. define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
  40781. /**
  40782. * Error code when release state is missing
  40783. */
  40784. define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
  40785. /**
  40786. * Error code when release state is invalid
  40787. */
  40788. define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
  40789. /**
  40790. * Error code when no release notes are found
  40791. */
  40792. define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
  40793. /**
  40794. * Error code when no maintainers are found
  40795. */
  40796. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
  40797. /**
  40798. * Error code when a maintainer has no handle
  40799. */
  40800. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
  40801. /**
  40802. * Error code when a maintainer has no handle
  40803. */
  40804. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
  40805. /**
  40806. * Error code when a maintainer has no name
  40807. */
  40808. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
  40809. /**
  40810. * Error code when a maintainer has no email
  40811. */
  40812. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
  40813. /**
  40814. * Error code when a maintainer has no handle
  40815. */
  40816. define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
  40817. /**
  40818. * Error code when a dependency is not a PHP dependency, but has no name
  40819. */
  40820. define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
  40821. /**
  40822. * Error code when a dependency has no type (pkg, php, etc.)
  40823. */
  40824. define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
  40825. /**
  40826. * Error code when a dependency has no relation (lt, ge, has, etc.)
  40827. */
  40828. define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
  40829. /**
  40830. * Error code when a dependency is not a 'has' relation, but has no version
  40831. */
  40832. define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
  40833. /**
  40834. * Error code when a dependency has an invalid relation
  40835. */
  40836. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
  40837. /**
  40838. * Error code when a dependency has an invalid type
  40839. */
  40840. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
  40841. /**
  40842. * Error code when a dependency has an invalid optional option
  40843. */
  40844. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
  40845. /**
  40846. * Error code when a dependency is a pkg dependency, and has an invalid package name
  40847. */
  40848. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
  40849. /**
  40850. * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
  40851. */
  40852. define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
  40853. /**
  40854. * Error code when rel="has" and version attribute is present.
  40855. */
  40856. define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
  40857. /**
  40858. * Error code when type="php" and dependency name is present
  40859. */
  40860. define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
  40861. /**
  40862. * Error code when a configure option has no name
  40863. */
  40864. define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
  40865. /**
  40866. * Error code when a configure option has no name
  40867. */
  40868. define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
  40869. /**
  40870. * Error code when a file in the filelist has an invalid role
  40871. */
  40872. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
  40873. /**
  40874. * Error code when a file in the filelist has no role
  40875. */
  40876. define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
  40877. /**
  40878. * Error code when analyzing a php source file that has parse errors
  40879. */
  40880. define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
  40881. /**
  40882. * Error code when analyzing a php source file reveals a source element
  40883. * without a package name prefix
  40884. */
  40885. define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
  40886. /**
  40887. * Error code when an unknown channel is specified
  40888. */
  40889. define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
  40890. /**
  40891. * Error code when no files are found in the filelist
  40892. */
  40893. define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
  40894. /**
  40895. * Error code when a file is not valid php according to _analyzeSourceCode()
  40896. */
  40897. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
  40898. /**
  40899. * Error code when the channel validator returns an error or warning
  40900. */
  40901. define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
  40902. /**
  40903. * Error code when a php5 package is packaged in php4 (analysis doesn't work)
  40904. */
  40905. define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
  40906. /**
  40907. * Error code when a file is listed in package.xml but does not exist
  40908. */
  40909. define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
  40910. /**
  40911. * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
  40912. */
  40913. define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
  40914. /**
  40915. * Error code when a package.xml contains non-ISO-8859-1 characters
  40916. */
  40917. define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49);
  40918. /**
  40919. * Error code when a dependency is not a 'has' relation, but has no version
  40920. */
  40921. define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
  40922. /**
  40923. * Error code when a package has no lead developer
  40924. */
  40925. define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
  40926. /**
  40927. * Error code when a filename begins with "."
  40928. */
  40929. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52);
  40930. /**
  40931. * package.xml encapsulator
  40932. * @category pear
  40933. * @package PEAR
  40934. * @author Greg Beaver <cellog@php.net>
  40935. * @copyright 1997-2009 The Authors
  40936. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  40937. * @version Release: 1.10.10
  40938. * @link http://pear.php.net/package/PEAR
  40939. * @since Class available since Release 1.4.0a1
  40940. */
  40941. class PEAR_PackageFile_v1
  40942. {
  40943. /**
  40944. * @access private
  40945. * @var PEAR_ErrorStack
  40946. * @access private
  40947. */
  40948. var $_stack;
  40949. /**
  40950. * A registry object, used to access the package name validation regex for non-standard channels
  40951. * @var PEAR_Registry
  40952. * @access private
  40953. */
  40954. var $_registry;
  40955. /**
  40956. * An object that contains a log method that matches PEAR_Common::log's signature
  40957. * @var object
  40958. * @access private
  40959. */
  40960. var $_logger;
  40961. /**
  40962. * Parsed package information
  40963. * @var array
  40964. * @access private
  40965. */
  40966. var $_packageInfo;
  40967. /**
  40968. * path to package.xml
  40969. * @var string
  40970. * @access private
  40971. */
  40972. var $_packageFile;
  40973. /**
  40974. * path to package .tgz or false if this is a local/extracted package.xml
  40975. * @var string
  40976. * @access private
  40977. */
  40978. var $_archiveFile;
  40979. /**
  40980. * @var int
  40981. * @access private
  40982. */
  40983. var $_isValid = 0;
  40984. /**
  40985. * Determines whether this packagefile was initialized only with partial package info
  40986. *
  40987. * If this package file was constructed via parsing REST, it will only contain
  40988. *
  40989. * - package name
  40990. * - channel name
  40991. * - dependencies
  40992. * @var boolean
  40993. * @access private
  40994. */
  40995. var $_incomplete = true;
  40996. /**
  40997. * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
  40998. * @param string Name of Error Stack class to use.
  40999. */
  41000. function __construct()
  41001. {
  41002. $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v1');
  41003. $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  41004. $this->_isValid = 0;
  41005. }
  41006. function installBinary($installer)
  41007. {
  41008. return false;
  41009. }
  41010. function isExtension($name)
  41011. {
  41012. return false;
  41013. }
  41014. function setConfig(&$config)
  41015. {
  41016. $this->_config = &$config;
  41017. $this->_registry = &$config->getRegistry();
  41018. }
  41019. function setRequestedGroup()
  41020. {
  41021. // placeholder
  41022. }
  41023. /**
  41024. * For saving in the registry.
  41025. *
  41026. * Set the last version that was installed
  41027. * @param string
  41028. */
  41029. function setLastInstalledVersion($version)
  41030. {
  41031. $this->_packageInfo['_lastversion'] = $version;
  41032. }
  41033. /**
  41034. * @return string|false
  41035. */
  41036. function getLastInstalledVersion()
  41037. {
  41038. if (isset($this->_packageInfo['_lastversion'])) {
  41039. return $this->_packageInfo['_lastversion'];
  41040. }
  41041. return false;
  41042. }
  41043. function getInstalledBinary()
  41044. {
  41045. return false;
  41046. }
  41047. function listPostinstallScripts()
  41048. {
  41049. return false;
  41050. }
  41051. function initPostinstallScripts()
  41052. {
  41053. return false;
  41054. }
  41055. function setLogger(&$logger)
  41056. {
  41057. if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
  41058. return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
  41059. }
  41060. $this->_logger = &$logger;
  41061. }
  41062. function setPackagefile($file, $archive = false)
  41063. {
  41064. $this->_packageFile = $file;
  41065. $this->_archiveFile = $archive ? $archive : $file;
  41066. }
  41067. function getPackageFile()
  41068. {
  41069. return isset($this->_packageFile) ? $this->_packageFile : false;
  41070. }
  41071. function getPackageType()
  41072. {
  41073. return 'php';
  41074. }
  41075. function getArchiveFile()
  41076. {
  41077. return $this->_archiveFile;
  41078. }
  41079. function packageInfo($field)
  41080. {
  41081. if (!is_string($field) || empty($field) ||
  41082. !isset($this->_packageInfo[$field])) {
  41083. return false;
  41084. }
  41085. return $this->_packageInfo[$field];
  41086. }
  41087. function setDirtree($path)
  41088. {
  41089. if (!isset($this->_packageInfo['dirtree'])) {
  41090. $this->_packageInfo['dirtree'] = array();
  41091. }
  41092. $this->_packageInfo['dirtree'][$path] = true;
  41093. }
  41094. function getDirtree()
  41095. {
  41096. if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
  41097. return $this->_packageInfo['dirtree'];
  41098. }
  41099. return false;
  41100. }
  41101. function resetDirtree()
  41102. {
  41103. unset($this->_packageInfo['dirtree']);
  41104. }
  41105. function fromArray($pinfo)
  41106. {
  41107. $this->_incomplete = false;
  41108. $this->_packageInfo = $pinfo;
  41109. }
  41110. function isIncomplete()
  41111. {
  41112. return $this->_incomplete;
  41113. }
  41114. function getChannel()
  41115. {
  41116. return 'pear.php.net';
  41117. }
  41118. function getUri()
  41119. {
  41120. return false;
  41121. }
  41122. function getTime()
  41123. {
  41124. return false;
  41125. }
  41126. function getExtends()
  41127. {
  41128. if (isset($this->_packageInfo['extends'])) {
  41129. return $this->_packageInfo['extends'];
  41130. }
  41131. return false;
  41132. }
  41133. /**
  41134. * @return array
  41135. */
  41136. function toArray()
  41137. {
  41138. if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
  41139. return false;
  41140. }
  41141. return $this->getArray();
  41142. }
  41143. function getArray()
  41144. {
  41145. return $this->_packageInfo;
  41146. }
  41147. function getName()
  41148. {
  41149. return $this->getPackage();
  41150. }
  41151. function getPackage()
  41152. {
  41153. if (isset($this->_packageInfo['package'])) {
  41154. return $this->_packageInfo['package'];
  41155. }
  41156. return false;
  41157. }
  41158. /**
  41159. * WARNING - don't use this unless you know what you are doing
  41160. */
  41161. function setRawPackage($package)
  41162. {
  41163. $this->_packageInfo['package'] = $package;
  41164. }
  41165. function setPackage($package)
  41166. {
  41167. $this->_packageInfo['package'] = $package;
  41168. $this->_isValid = false;
  41169. }
  41170. function getVersion()
  41171. {
  41172. if (isset($this->_packageInfo['version'])) {
  41173. return $this->_packageInfo['version'];
  41174. }
  41175. return false;
  41176. }
  41177. function setVersion($version)
  41178. {
  41179. $this->_packageInfo['version'] = $version;
  41180. $this->_isValid = false;
  41181. }
  41182. function clearMaintainers()
  41183. {
  41184. unset($this->_packageInfo['maintainers']);
  41185. }
  41186. function getMaintainers()
  41187. {
  41188. if (isset($this->_packageInfo['maintainers'])) {
  41189. return $this->_packageInfo['maintainers'];
  41190. }
  41191. return false;
  41192. }
  41193. /**
  41194. * Adds a new maintainer - no checking of duplicates is performed, use
  41195. * updatemaintainer for that purpose.
  41196. */
  41197. function addMaintainer($role, $handle, $name, $email)
  41198. {
  41199. $this->_packageInfo['maintainers'][] =
  41200. array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
  41201. $this->_isValid = false;
  41202. }
  41203. function updateMaintainer($role, $handle, $name, $email)
  41204. {
  41205. $found = false;
  41206. if (!isset($this->_packageInfo['maintainers']) ||
  41207. !is_array($this->_packageInfo['maintainers'])) {
  41208. return $this->addMaintainer($role, $handle, $name, $email);
  41209. }
  41210. foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
  41211. if ($maintainer['handle'] == $handle) {
  41212. $found = $i;
  41213. break;
  41214. }
  41215. }
  41216. if ($found !== false) {
  41217. unset($this->_packageInfo['maintainers'][$found]);
  41218. $this->_packageInfo['maintainers'] =
  41219. array_values($this->_packageInfo['maintainers']);
  41220. }
  41221. $this->addMaintainer($role, $handle, $name, $email);
  41222. }
  41223. function deleteMaintainer($handle)
  41224. {
  41225. $found = false;
  41226. foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
  41227. if ($maintainer['handle'] == $handle) {
  41228. $found = $i;
  41229. break;
  41230. }
  41231. }
  41232. if ($found !== false) {
  41233. unset($this->_packageInfo['maintainers'][$found]);
  41234. $this->_packageInfo['maintainers'] =
  41235. array_values($this->_packageInfo['maintainers']);
  41236. return true;
  41237. }
  41238. return false;
  41239. }
  41240. function getState()
  41241. {
  41242. if (isset($this->_packageInfo['release_state'])) {
  41243. return $this->_packageInfo['release_state'];
  41244. }
  41245. return false;
  41246. }
  41247. function setRawState($state)
  41248. {
  41249. $this->_packageInfo['release_state'] = $state;
  41250. }
  41251. function setState($state)
  41252. {
  41253. $this->_packageInfo['release_state'] = $state;
  41254. $this->_isValid = false;
  41255. }
  41256. function getDate()
  41257. {
  41258. if (isset($this->_packageInfo['release_date'])) {
  41259. return $this->_packageInfo['release_date'];
  41260. }
  41261. return false;
  41262. }
  41263. function setDate($date)
  41264. {
  41265. $this->_packageInfo['release_date'] = $date;
  41266. $this->_isValid = false;
  41267. }
  41268. function getLicense()
  41269. {
  41270. if (isset($this->_packageInfo['release_license'])) {
  41271. return $this->_packageInfo['release_license'];
  41272. }
  41273. return false;
  41274. }
  41275. function setLicense($date)
  41276. {
  41277. $this->_packageInfo['release_license'] = $date;
  41278. $this->_isValid = false;
  41279. }
  41280. function getSummary()
  41281. {
  41282. if (isset($this->_packageInfo['summary'])) {
  41283. return $this->_packageInfo['summary'];
  41284. }
  41285. return false;
  41286. }
  41287. function setSummary($summary)
  41288. {
  41289. $this->_packageInfo['summary'] = $summary;
  41290. $this->_isValid = false;
  41291. }
  41292. function getDescription()
  41293. {
  41294. if (isset($this->_packageInfo['description'])) {
  41295. return $this->_packageInfo['description'];
  41296. }
  41297. return false;
  41298. }
  41299. function setDescription($desc)
  41300. {
  41301. $this->_packageInfo['description'] = $desc;
  41302. $this->_isValid = false;
  41303. }
  41304. function getNotes()
  41305. {
  41306. if (isset($this->_packageInfo['release_notes'])) {
  41307. return $this->_packageInfo['release_notes'];
  41308. }
  41309. return false;
  41310. }
  41311. function setNotes($notes)
  41312. {
  41313. $this->_packageInfo['release_notes'] = $notes;
  41314. $this->_isValid = false;
  41315. }
  41316. function getDeps()
  41317. {
  41318. if (isset($this->_packageInfo['release_deps'])) {
  41319. return $this->_packageInfo['release_deps'];
  41320. }
  41321. return false;
  41322. }
  41323. /**
  41324. * Reset dependencies prior to adding new ones
  41325. */
  41326. function clearDeps()
  41327. {
  41328. unset($this->_packageInfo['release_deps']);
  41329. }
  41330. function addPhpDep($version, $rel)
  41331. {
  41332. $this->_isValid = false;
  41333. $this->_packageInfo['release_deps'][] =
  41334. array('type' => 'php',
  41335. 'rel' => $rel,
  41336. 'version' => $version);
  41337. }
  41338. function addPackageDep($name, $version, $rel, $optional = 'no')
  41339. {
  41340. $this->_isValid = false;
  41341. $dep =
  41342. array('type' => 'pkg',
  41343. 'name' => $name,
  41344. 'rel' => $rel,
  41345. 'optional' => $optional);
  41346. if ($rel != 'has' && $rel != 'not') {
  41347. $dep['version'] = $version;
  41348. }
  41349. $this->_packageInfo['release_deps'][] = $dep;
  41350. }
  41351. function addExtensionDep($name, $version, $rel, $optional = 'no')
  41352. {
  41353. $this->_isValid = false;
  41354. $this->_packageInfo['release_deps'][] =
  41355. array('type' => 'ext',
  41356. 'name' => $name,
  41357. 'rel' => $rel,
  41358. 'version' => $version,
  41359. 'optional' => $optional);
  41360. }
  41361. /**
  41362. * WARNING - do not use this function directly unless you know what you're doing
  41363. */
  41364. function setDeps($deps)
  41365. {
  41366. $this->_packageInfo['release_deps'] = $deps;
  41367. }
  41368. function hasDeps()
  41369. {
  41370. return isset($this->_packageInfo['release_deps']) &&
  41371. count($this->_packageInfo['release_deps']);
  41372. }
  41373. function getDependencyGroup($group)
  41374. {
  41375. return false;
  41376. }
  41377. function isCompatible($pf)
  41378. {
  41379. return false;
  41380. }
  41381. function isSubpackageOf($p)
  41382. {
  41383. return $p->isSubpackage($this);
  41384. }
  41385. function isSubpackage($p)
  41386. {
  41387. return false;
  41388. }
  41389. function dependsOn($package, $channel)
  41390. {
  41391. if (strtolower($channel) != 'pear.php.net') {
  41392. return false;
  41393. }
  41394. if (!($deps = $this->getDeps())) {
  41395. return false;
  41396. }
  41397. foreach ($deps as $dep) {
  41398. if ($dep['type'] != 'pkg') {
  41399. continue;
  41400. }
  41401. if (strtolower($dep['name']) == strtolower($package)) {
  41402. return true;
  41403. }
  41404. }
  41405. return false;
  41406. }
  41407. function getConfigureOptions()
  41408. {
  41409. if (isset($this->_packageInfo['configure_options'])) {
  41410. return $this->_packageInfo['configure_options'];
  41411. }
  41412. return false;
  41413. }
  41414. function hasConfigureOptions()
  41415. {
  41416. return isset($this->_packageInfo['configure_options']) &&
  41417. count($this->_packageInfo['configure_options']);
  41418. }
  41419. function addConfigureOption($name, $prompt, $default = false)
  41420. {
  41421. $o = array('name' => $name, 'prompt' => $prompt);
  41422. if ($default !== false) {
  41423. $o['default'] = $default;
  41424. }
  41425. if (!isset($this->_packageInfo['configure_options'])) {
  41426. $this->_packageInfo['configure_options'] = array();
  41427. }
  41428. $this->_packageInfo['configure_options'][] = $o;
  41429. }
  41430. function clearConfigureOptions()
  41431. {
  41432. unset($this->_packageInfo['configure_options']);
  41433. }
  41434. function getProvides()
  41435. {
  41436. if (isset($this->_packageInfo['provides'])) {
  41437. return $this->_packageInfo['provides'];
  41438. }
  41439. return false;
  41440. }
  41441. function getProvidesExtension()
  41442. {
  41443. return false;
  41444. }
  41445. function addFile($dir, $file, $attrs)
  41446. {
  41447. $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
  41448. if ($dir == '/' || $dir == '') {
  41449. $dir = '';
  41450. } else {
  41451. $dir .= '/';
  41452. }
  41453. $file = $dir . $file;
  41454. $file = preg_replace('![\\/]+!', '/', $file);
  41455. $this->_packageInfo['filelist'][$file] = $attrs;
  41456. }
  41457. function getInstallationFilelist()
  41458. {
  41459. return $this->getFilelist();
  41460. }
  41461. function getFilelist()
  41462. {
  41463. if (isset($this->_packageInfo['filelist'])) {
  41464. return $this->_packageInfo['filelist'];
  41465. }
  41466. return false;
  41467. }
  41468. function setFileAttribute($file, $attr, $value)
  41469. {
  41470. $this->_packageInfo['filelist'][$file][$attr] = $value;
  41471. }
  41472. function resetFilelist()
  41473. {
  41474. $this->_packageInfo['filelist'] = array();
  41475. }
  41476. function setInstalledAs($file, $path)
  41477. {
  41478. if ($path) {
  41479. return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
  41480. }
  41481. unset($this->_packageInfo['filelist'][$file]['installed_as']);
  41482. }
  41483. function installedFile($file, $atts)
  41484. {
  41485. if (isset($this->_packageInfo['filelist'][$file])) {
  41486. $this->_packageInfo['filelist'][$file] =
  41487. array_merge($this->_packageInfo['filelist'][$file], $atts);
  41488. } else {
  41489. $this->_packageInfo['filelist'][$file] = $atts;
  41490. }
  41491. }
  41492. function getChangelog()
  41493. {
  41494. if (isset($this->_packageInfo['changelog'])) {
  41495. return $this->_packageInfo['changelog'];
  41496. }
  41497. return false;
  41498. }
  41499. function getPackagexmlVersion()
  41500. {
  41501. return '1.0';
  41502. }
  41503. /**
  41504. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  41505. * @param boolean determines whether to purge the error stack after retrieving
  41506. * @return array
  41507. */
  41508. function getValidationWarnings($purge = true)
  41509. {
  41510. return $this->_stack->getErrors($purge);
  41511. }
  41512. // }}}
  41513. /**
  41514. * Validation error. Also marks the object contents as invalid
  41515. * @param error code
  41516. * @param array error information
  41517. * @access private
  41518. */
  41519. function _validateError($code, $params = array())
  41520. {
  41521. $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
  41522. $this->_isValid = false;
  41523. }
  41524. /**
  41525. * Validation warning. Does not mark the object contents invalid.
  41526. * @param error code
  41527. * @param array error information
  41528. * @access private
  41529. */
  41530. function _validateWarning($code, $params = array())
  41531. {
  41532. $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
  41533. }
  41534. /**
  41535. * @param integer error code
  41536. * @access protected
  41537. */
  41538. function _getErrorMessage()
  41539. {
  41540. return array(
  41541. PEAR_PACKAGEFILE_ERROR_NO_NAME =>
  41542. 'Missing Package Name',
  41543. PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
  41544. 'No summary found',
  41545. PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
  41546. 'Summary should be on one line',
  41547. PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
  41548. 'Missing description',
  41549. PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
  41550. 'Missing license',
  41551. PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
  41552. 'No release version found',
  41553. PEAR_PACKAGEFILE_ERROR_NO_STATE =>
  41554. 'No release state found',
  41555. PEAR_PACKAGEFILE_ERROR_NO_DATE =>
  41556. 'No release date found',
  41557. PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
  41558. 'No release notes found',
  41559. PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
  41560. 'Package must have at least one lead maintainer',
  41561. PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
  41562. 'No maintainers found, at least one must be defined',
  41563. PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
  41564. 'Maintainer %index% has no handle (user ID at channel server)',
  41565. PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
  41566. 'Maintainer %index% has no role',
  41567. PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
  41568. 'Maintainer %index% has no name',
  41569. PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
  41570. 'Maintainer %index% has no email',
  41571. PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
  41572. 'Dependency %index% is not a php dependency, and has no name',
  41573. PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
  41574. 'Dependency %index% has no relation (rel)',
  41575. PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
  41576. 'Dependency %index% has no type',
  41577. PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
  41578. 'PHP Dependency %index% has a name attribute of "%name%" which will be' .
  41579. ' ignored!',
  41580. PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
  41581. 'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
  41582. 'and has no version',
  41583. PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
  41584. 'Dependency %index% is a type="php" dependency, ' .
  41585. 'and has no version',
  41586. PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
  41587. 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
  41588. PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
  41589. 'Dependency %index% has invalid optional value "%opt%", should be yes or no',
  41590. PEAR_PACKAGEFILE_PHP_NO_NOT =>
  41591. 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
  41592. ' to exclude specific versions',
  41593. PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
  41594. 'Configure Option %index% has no name',
  41595. PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
  41596. 'Configure Option %index% has no prompt',
  41597. PEAR_PACKAGEFILE_ERROR_NO_FILES =>
  41598. 'No files in <filelist> section of package.xml',
  41599. PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
  41600. 'File "%file%" has no role, expecting one of "%roles%"',
  41601. PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
  41602. 'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
  41603. PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
  41604. 'File "%file%" cannot start with ".", cannot package or install',
  41605. PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
  41606. 'Parser error: invalid PHP found in file "%file%"',
  41607. PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
  41608. 'in %file%: %type% "%name%" not prefixed with package name "%package%"',
  41609. PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
  41610. 'Parser error: invalid PHP file "%file%"',
  41611. PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
  41612. 'Channel validator error: field "%field%" - %reason%',
  41613. PEAR_PACKAGEFILE_ERROR_PHP5 =>
  41614. 'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
  41615. PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
  41616. 'File "%file%" in package.xml does not exist',
  41617. PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
  41618. 'Package.xml contains non-ISO-8859-1 characters, and may not validate',
  41619. );
  41620. }
  41621. /**
  41622. * Validate XML package definition file.
  41623. *
  41624. * @access public
  41625. * @return boolean
  41626. */
  41627. function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
  41628. {
  41629. if (($this->_isValid & $state) == $state) {
  41630. return true;
  41631. }
  41632. $this->_isValid = true;
  41633. $info = $this->_packageInfo;
  41634. if (empty($info['package'])) {
  41635. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
  41636. $this->_packageName = $pn = 'unknown';
  41637. } else {
  41638. $this->_packageName = $pn = $info['package'];
  41639. }
  41640. if (empty($info['summary'])) {
  41641. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
  41642. } elseif (strpos(trim($info['summary']), "\n") !== false) {
  41643. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
  41644. array('summary' => $info['summary']));
  41645. }
  41646. if (empty($info['description'])) {
  41647. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
  41648. }
  41649. if (empty($info['release_license'])) {
  41650. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
  41651. }
  41652. if (empty($info['version'])) {
  41653. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
  41654. }
  41655. if (empty($info['release_state'])) {
  41656. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
  41657. }
  41658. if (empty($info['release_date'])) {
  41659. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
  41660. }
  41661. if (empty($info['release_notes'])) {
  41662. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
  41663. }
  41664. if (empty($info['maintainers'])) {
  41665. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
  41666. } else {
  41667. $haslead = false;
  41668. $i = 1;
  41669. foreach ($info['maintainers'] as $m) {
  41670. if (empty($m['handle'])) {
  41671. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
  41672. array('index' => $i));
  41673. }
  41674. if (empty($m['role'])) {
  41675. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
  41676. array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
  41677. } elseif ($m['role'] == 'lead') {
  41678. $haslead = true;
  41679. }
  41680. if (empty($m['name'])) {
  41681. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
  41682. array('index' => $i));
  41683. }
  41684. if (empty($m['email'])) {
  41685. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
  41686. array('index' => $i));
  41687. }
  41688. $i++;
  41689. }
  41690. if (!$haslead) {
  41691. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
  41692. }
  41693. }
  41694. if (!empty($info['release_deps'])) {
  41695. $i = 1;
  41696. foreach ($info['release_deps'] as $d) {
  41697. if (!isset($d['type']) || empty($d['type'])) {
  41698. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
  41699. array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
  41700. continue;
  41701. }
  41702. if (!isset($d['rel']) || empty($d['rel'])) {
  41703. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
  41704. array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
  41705. continue;
  41706. }
  41707. if (!empty($d['optional'])) {
  41708. if (!in_array($d['optional'], array('yes', 'no'))) {
  41709. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
  41710. array('index' => $i, 'opt' => $d['optional']));
  41711. }
  41712. }
  41713. if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
  41714. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
  41715. array('index' => $i));
  41716. } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
  41717. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
  41718. array('index' => $i, 'rel' => $d['rel']));
  41719. }
  41720. if ($d['type'] == 'php' && !empty($d['name'])) {
  41721. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
  41722. array('index' => $i, 'name' => $d['name']));
  41723. } elseif ($d['type'] != 'php' && empty($d['name'])) {
  41724. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
  41725. array('index' => $i));
  41726. }
  41727. if ($d['type'] == 'php' && empty($d['version'])) {
  41728. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
  41729. array('index' => $i));
  41730. }
  41731. if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
  41732. $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
  41733. array('index' => $i));
  41734. }
  41735. $i++;
  41736. }
  41737. }
  41738. if (!empty($info['configure_options'])) {
  41739. $i = 1;
  41740. foreach ($info['configure_options'] as $c) {
  41741. if (empty($c['name'])) {
  41742. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
  41743. array('index' => $i));
  41744. }
  41745. if (empty($c['prompt'])) {
  41746. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
  41747. array('index' => $i));
  41748. }
  41749. $i++;
  41750. }
  41751. }
  41752. if (empty($info['filelist'])) {
  41753. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
  41754. $errors[] = 'no files';
  41755. } else {
  41756. foreach ($info['filelist'] as $file => $fa) {
  41757. if (empty($fa['role'])) {
  41758. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
  41759. array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
  41760. continue;
  41761. } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
  41762. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
  41763. array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
  41764. }
  41765. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) {
  41766. // file contains .. parent directory or . cur directory references
  41767. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  41768. array('file' => $file));
  41769. }
  41770. if (isset($fa['install-as']) &&
  41771. preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  41772. str_replace('\\', '/', $fa['install-as']))) {
  41773. // install-as contains .. parent directory or . cur directory references
  41774. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  41775. array('file' => $file . ' [installed as ' . $fa['install-as'] . ']'));
  41776. }
  41777. if (isset($fa['baseinstalldir']) &&
  41778. preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  41779. str_replace('\\', '/', $fa['baseinstalldir']))) {
  41780. // install-as contains .. parent directory or . cur directory references
  41781. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  41782. array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']'));
  41783. }
  41784. }
  41785. }
  41786. if (isset($this->_registry) && $this->_isValid) {
  41787. $chan = $this->_registry->getChannel('pear.php.net');
  41788. if (PEAR::isError($chan)) {
  41789. $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage());
  41790. return $this->_isValid = 0;
  41791. }
  41792. $validator = $chan->getValidationObject();
  41793. $validator->setPackageFile($this);
  41794. $validator->validate($state);
  41795. $failures = $validator->getFailures();
  41796. foreach ($failures['errors'] as $error) {
  41797. $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
  41798. }
  41799. foreach ($failures['warnings'] as $warning) {
  41800. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
  41801. }
  41802. }
  41803. if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
  41804. if ($this->_analyzePhpFiles()) {
  41805. $this->_isValid = true;
  41806. }
  41807. }
  41808. if ($this->_isValid) {
  41809. return $this->_isValid = $state;
  41810. }
  41811. return $this->_isValid = 0;
  41812. }
  41813. function _analyzePhpFiles()
  41814. {
  41815. if (!$this->_isValid) {
  41816. return false;
  41817. }
  41818. if (!isset($this->_packageFile)) {
  41819. return false;
  41820. }
  41821. $dir_prefix = dirname($this->_packageFile);
  41822. $common = new PEAR_Common;
  41823. $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
  41824. array($common, 'log');
  41825. $info = $this->getFilelist();
  41826. foreach ($info as $file => $fa) {
  41827. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
  41828. $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
  41829. array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
  41830. continue;
  41831. }
  41832. if ($fa['role'] == 'php' && $dir_prefix) {
  41833. call_user_func_array($log, array(1, "Analyzing $file"));
  41834. $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
  41835. if ($srcinfo) {
  41836. $this->_buildProvidesArray($srcinfo);
  41837. }
  41838. }
  41839. }
  41840. $this->_packageName = $pn = $this->getPackage();
  41841. $pnl = strlen($pn);
  41842. if (isset($this->_packageInfo['provides'])) {
  41843. foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
  41844. if (isset($what['explicit'])) {
  41845. // skip conformance checks if the provides entry is
  41846. // specified in the package.xml file
  41847. continue;
  41848. }
  41849. extract($what);
  41850. if ($type == 'class') {
  41851. if (!strncasecmp($name, $pn, $pnl)) {
  41852. continue;
  41853. }
  41854. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
  41855. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
  41856. } elseif ($type == 'function') {
  41857. if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
  41858. continue;
  41859. }
  41860. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
  41861. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
  41862. }
  41863. }
  41864. }
  41865. return $this->_isValid;
  41866. }
  41867. /**
  41868. * Get the default xml generator object
  41869. *
  41870. * @return PEAR_PackageFile_Generator_v1
  41871. */
  41872. function &getDefaultGenerator()
  41873. {
  41874. if (!class_exists('PEAR_PackageFile_Generator_v1')) {
  41875. require_once 'PEAR/PackageFile/Generator/v1.php';
  41876. }
  41877. $a = new PEAR_PackageFile_Generator_v1($this);
  41878. return $a;
  41879. }
  41880. /**
  41881. * Get the contents of a file listed within the package.xml
  41882. * @param string
  41883. * @return string
  41884. */
  41885. function getFileContents($file)
  41886. {
  41887. if ($this->_archiveFile == $this->_packageFile) { // unpacked
  41888. $dir = dirname($this->_packageFile);
  41889. $file = $dir . DIRECTORY_SEPARATOR . $file;
  41890. $file = str_replace(array('/', '\\'),
  41891. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
  41892. if (file_exists($file) && is_readable($file)) {
  41893. return implode('', file($file));
  41894. }
  41895. } else { // tgz
  41896. if (!class_exists('Archive_Tar')) {
  41897. require_once 'Archive/Tar.php';
  41898. }
  41899. $tar = new Archive_Tar($this->_archiveFile);
  41900. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  41901. if ($file != 'package.xml' && $file != 'package2.xml') {
  41902. $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
  41903. }
  41904. $file = $tar->extractInString($file);
  41905. $tar->popErrorHandling();
  41906. if (PEAR::isError($file)) {
  41907. return PEAR::raiseError("Cannot locate file '$file' in archive");
  41908. }
  41909. return $file;
  41910. }
  41911. }
  41912. // {{{ analyzeSourceCode()
  41913. /**
  41914. * Analyze the source code of the given PHP file
  41915. *
  41916. * @param string Filename of the PHP file
  41917. * @return mixed
  41918. * @access private
  41919. */
  41920. function _analyzeSourceCode($file)
  41921. {
  41922. if (!function_exists("token_get_all")) {
  41923. return false;
  41924. }
  41925. if (!defined('T_DOC_COMMENT')) {
  41926. define('T_DOC_COMMENT', T_COMMENT);
  41927. }
  41928. if (!defined('T_INTERFACE')) {
  41929. define('T_INTERFACE', -1);
  41930. }
  41931. if (!defined('T_IMPLEMENTS')) {
  41932. define('T_IMPLEMENTS', -1);
  41933. }
  41934. if (!$fp = @fopen($file, "r")) {
  41935. return false;
  41936. }
  41937. fclose($fp);
  41938. $contents = file_get_contents($file);
  41939. $tokens = token_get_all($contents);
  41940. /*
  41941. for ($i = 0; $i < sizeof($tokens); $i++) {
  41942. @list($token, $data) = $tokens[$i];
  41943. if (is_string($token)) {
  41944. var_dump($token);
  41945. } else {
  41946. print token_name($token) . ' ';
  41947. var_dump(rtrim($data));
  41948. }
  41949. }
  41950. */
  41951. $look_for = 0;
  41952. $paren_level = 0;
  41953. $bracket_level = 0;
  41954. $brace_level = 0;
  41955. $lastphpdoc = '';
  41956. $current_class = '';
  41957. $current_interface = '';
  41958. $current_class_level = -1;
  41959. $current_function = '';
  41960. $current_function_level = -1;
  41961. $declared_classes = array();
  41962. $declared_interfaces = array();
  41963. $declared_functions = array();
  41964. $declared_methods = array();
  41965. $used_classes = array();
  41966. $used_functions = array();
  41967. $extends = array();
  41968. $implements = array();
  41969. $nodeps = array();
  41970. $inquote = false;
  41971. $interface = false;
  41972. for ($i = 0; $i < sizeof($tokens); $i++) {
  41973. if (is_array($tokens[$i])) {
  41974. list($token, $data) = $tokens[$i];
  41975. } else {
  41976. $token = $tokens[$i];
  41977. $data = '';
  41978. }
  41979. if ($inquote) {
  41980. if ($token != '"' && $token != T_END_HEREDOC) {
  41981. continue;
  41982. } else {
  41983. $inquote = false;
  41984. continue;
  41985. }
  41986. }
  41987. switch ($token) {
  41988. case T_WHITESPACE:
  41989. break;
  41990. case ';':
  41991. if ($interface) {
  41992. $current_function = '';
  41993. $current_function_level = -1;
  41994. }
  41995. break;
  41996. case '"':
  41997. case T_START_HEREDOC:
  41998. $inquote = true;
  41999. break;
  42000. case T_CURLY_OPEN:
  42001. case T_DOLLAR_OPEN_CURLY_BRACES:
  42002. case '{': $brace_level++; continue 2;
  42003. case '}':
  42004. $brace_level--;
  42005. if ($current_class_level == $brace_level) {
  42006. $current_class = '';
  42007. $current_class_level = -1;
  42008. }
  42009. if ($current_function_level == $brace_level) {
  42010. $current_function = '';
  42011. $current_function_level = -1;
  42012. }
  42013. continue 2;
  42014. case '[': $bracket_level++; continue 2;
  42015. case ']': $bracket_level--; continue 2;
  42016. case '(': $paren_level++; continue 2;
  42017. case ')': $paren_level--; continue 2;
  42018. case T_INTERFACE:
  42019. $interface = true;
  42020. case T_CLASS:
  42021. if (($current_class_level != -1) || ($current_function_level != -1)) {
  42022. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
  42023. array('file' => $file));
  42024. return false;
  42025. }
  42026. case T_FUNCTION:
  42027. case T_NEW:
  42028. case T_EXTENDS:
  42029. case T_IMPLEMENTS:
  42030. $look_for = $token;
  42031. continue 2;
  42032. case T_STRING:
  42033. if ($look_for == T_CLASS) {
  42034. $current_class = $data;
  42035. $current_class_level = $brace_level;
  42036. $declared_classes[] = $current_class;
  42037. } elseif ($look_for == T_INTERFACE) {
  42038. $current_interface = $data;
  42039. $current_class_level = $brace_level;
  42040. $declared_interfaces[] = $current_interface;
  42041. } elseif ($look_for == T_IMPLEMENTS) {
  42042. $implements[$current_class] = $data;
  42043. } elseif ($look_for == T_EXTENDS) {
  42044. $extends[$current_class] = $data;
  42045. } elseif ($look_for == T_FUNCTION) {
  42046. if ($current_class) {
  42047. $current_function = "$current_class::$data";
  42048. $declared_methods[$current_class][] = $data;
  42049. } elseif ($current_interface) {
  42050. $current_function = "$current_interface::$data";
  42051. $declared_methods[$current_interface][] = $data;
  42052. } else {
  42053. $current_function = $data;
  42054. $declared_functions[] = $current_function;
  42055. }
  42056. $current_function_level = $brace_level;
  42057. $m = array();
  42058. } elseif ($look_for == T_NEW) {
  42059. $used_classes[$data] = true;
  42060. }
  42061. $look_for = 0;
  42062. continue 2;
  42063. case T_VARIABLE:
  42064. $look_for = 0;
  42065. continue 2;
  42066. case T_DOC_COMMENT:
  42067. case T_COMMENT:
  42068. if (preg_match('!^/\*\*\s!', $data)) {
  42069. $lastphpdoc = $data;
  42070. if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  42071. $nodeps = array_merge($nodeps, $m[1]);
  42072. }
  42073. }
  42074. continue 2;
  42075. case T_DOUBLE_COLON:
  42076. if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
  42077. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
  42078. array('file' => $file));
  42079. return false;
  42080. }
  42081. $class = $tokens[$i - 1][1];
  42082. if (strtolower($class) != 'parent') {
  42083. $used_classes[$class] = true;
  42084. }
  42085. continue 2;
  42086. }
  42087. }
  42088. return array(
  42089. "source_file" => $file,
  42090. "declared_classes" => $declared_classes,
  42091. "declared_interfaces" => $declared_interfaces,
  42092. "declared_methods" => $declared_methods,
  42093. "declared_functions" => $declared_functions,
  42094. "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  42095. "inheritance" => $extends,
  42096. "implements" => $implements,
  42097. );
  42098. }
  42099. /**
  42100. * Build a "provides" array from data returned by
  42101. * analyzeSourceCode(). The format of the built array is like
  42102. * this:
  42103. *
  42104. * array(
  42105. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  42106. * ...
  42107. * )
  42108. *
  42109. *
  42110. * @param array $srcinfo array with information about a source file
  42111. * as returned by the analyzeSourceCode() method.
  42112. *
  42113. * @return void
  42114. *
  42115. * @access private
  42116. *
  42117. */
  42118. function _buildProvidesArray($srcinfo)
  42119. {
  42120. if (!$this->_isValid) {
  42121. return false;
  42122. }
  42123. $file = basename($srcinfo['source_file']);
  42124. $pn = $this->getPackage();
  42125. $pnl = strlen($pn);
  42126. foreach ($srcinfo['declared_classes'] as $class) {
  42127. $key = "class;$class";
  42128. if (isset($this->_packageInfo['provides'][$key])) {
  42129. continue;
  42130. }
  42131. $this->_packageInfo['provides'][$key] =
  42132. array('file'=> $file, 'type' => 'class', 'name' => $class);
  42133. if (isset($srcinfo['inheritance'][$class])) {
  42134. $this->_packageInfo['provides'][$key]['extends'] =
  42135. $srcinfo['inheritance'][$class];
  42136. }
  42137. }
  42138. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  42139. foreach ($methods as $method) {
  42140. $function = "$class::$method";
  42141. $key = "function;$function";
  42142. if ($method[0] == '_' || !strcasecmp($method, $class) ||
  42143. isset($this->_packageInfo['provides'][$key])) {
  42144. continue;
  42145. }
  42146. $this->_packageInfo['provides'][$key] =
  42147. array('file'=> $file, 'type' => 'function', 'name' => $function);
  42148. }
  42149. }
  42150. foreach ($srcinfo['declared_functions'] as $function) {
  42151. $key = "function;$function";
  42152. if ($function[0] == '_' || isset($this->_packageInfo['provides'][$key])) {
  42153. continue;
  42154. }
  42155. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  42156. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  42157. }
  42158. $this->_packageInfo['provides'][$key] =
  42159. array('file'=> $file, 'type' => 'function', 'name' => $function);
  42160. }
  42161. }
  42162. // }}}
  42163. }
  42164. ?>
  42165. �����������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile/v2.php����������������������������������������������������������������0000644�0001750�0001750�00000210500�13565304531�016176� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  42166. /**
  42167. * PEAR_PackageFile_v2, package.xml version 2.0
  42168. *
  42169. * PHP versions 4 and 5
  42170. *
  42171. * @category pear
  42172. * @package PEAR
  42173. * @author Greg Beaver <cellog@php.net>
  42174. * @copyright 1997-2009 The Authors
  42175. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  42176. * @link http://pear.php.net/package/PEAR
  42177. * @since File available since Release 1.4.0a1
  42178. */
  42179. /**
  42180. * For error handling
  42181. */
  42182. require_once 'PEAR/ErrorStack.php';
  42183. /**
  42184. * @category pear
  42185. * @package PEAR
  42186. * @author Greg Beaver <cellog@php.net>
  42187. * @copyright 1997-2009 The Authors
  42188. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  42189. * @version Release: 1.10.10
  42190. * @link http://pear.php.net/package/PEAR
  42191. * @since Class available since Release 1.4.0a1
  42192. */
  42193. class PEAR_PackageFile_v2
  42194. {
  42195. /**
  42196. * Parsed package information
  42197. * @var array
  42198. * @access private
  42199. */
  42200. var $_packageInfo = array();
  42201. /**
  42202. * path to package .tgz or false if this is a local/extracted package.xml
  42203. * @var string|false
  42204. * @access private
  42205. */
  42206. var $_archiveFile;
  42207. /**
  42208. * path to package .xml or false if this is an abstract parsed-from-string xml
  42209. * @var string|false
  42210. * @access private
  42211. */
  42212. var $_packageFile;
  42213. /**
  42214. * This is used by file analysis routines to log progress information
  42215. * @var PEAR_Common
  42216. * @access protected
  42217. */
  42218. var $_logger;
  42219. /**
  42220. * This is set to the highest validation level that has been validated
  42221. *
  42222. * If the package.xml is invalid or unknown, this is set to 0. If
  42223. * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If
  42224. * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING
  42225. * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation
  42226. * "caching" to occur, which is particularly important for package validation, so
  42227. * that PHP files are not validated twice
  42228. * @var int
  42229. * @access private
  42230. */
  42231. var $_isValid = 0;
  42232. /**
  42233. * True if the filelist has been validated
  42234. * @param bool
  42235. */
  42236. var $_filesValid = false;
  42237. /**
  42238. * @var PEAR_Registry
  42239. * @access protected
  42240. */
  42241. var $_registry;
  42242. /**
  42243. * @var PEAR_Config
  42244. * @access protected
  42245. */
  42246. var $_config;
  42247. /**
  42248. * Optional Dependency group requested for installation
  42249. * @var string
  42250. * @access private
  42251. */
  42252. var $_requestedGroup = false;
  42253. /**
  42254. * @var PEAR_ErrorStack
  42255. * @access protected
  42256. */
  42257. var $_stack;
  42258. /**
  42259. * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible
  42260. */
  42261. var $_tasksNs;
  42262. /**
  42263. * Determines whether this packagefile was initialized only with partial package info
  42264. *
  42265. * If this package file was constructed via parsing REST, it will only contain
  42266. *
  42267. * - package name
  42268. * - channel name
  42269. * - dependencies
  42270. * @var boolean
  42271. * @access private
  42272. */
  42273. var $_incomplete = true;
  42274. /**
  42275. * @var PEAR_PackageFile_v2_Validator
  42276. */
  42277. var $_v2Validator;
  42278. /**
  42279. * The constructor merely sets up the private error stack
  42280. */
  42281. function __construct()
  42282. {
  42283. $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null);
  42284. $this->_isValid = false;
  42285. }
  42286. /**
  42287. * PHP 4 style constructor for backwards compatibility.
  42288. * Used by PEAR_PackageFileManager2
  42289. */
  42290. public function PEAR_PackageFile_v2()
  42291. {
  42292. $this->__construct();
  42293. }
  42294. /**
  42295. * To make unit-testing easier
  42296. * @param PEAR_Frontend_*
  42297. * @param array options
  42298. * @param PEAR_Config
  42299. * @return PEAR_Downloader
  42300. * @access protected
  42301. */
  42302. function &getPEARDownloader(&$i, $o, &$c)
  42303. {
  42304. $z = new PEAR_Downloader($i, $o, $c);
  42305. return $z;
  42306. }
  42307. /**
  42308. * To make unit-testing easier
  42309. * @param PEAR_Config
  42310. * @param array options
  42311. * @param array package name as returned from {@link PEAR_Registry::parsePackageName()}
  42312. * @param int PEAR_VALIDATE_* constant
  42313. * @return PEAR_Dependency2
  42314. * @access protected
  42315. */
  42316. function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING)
  42317. {
  42318. if (!class_exists('PEAR_Dependency2')) {
  42319. require_once 'PEAR/Dependency2.php';
  42320. }
  42321. $z = new PEAR_Dependency2($c, $o, $p, $s);
  42322. return $z;
  42323. }
  42324. function getInstalledBinary()
  42325. {
  42326. return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] :
  42327. false;
  42328. }
  42329. /**
  42330. * Installation of source package has failed, attempt to download and install the
  42331. * binary version of this package.
  42332. * @param PEAR_Installer
  42333. * @return array|false
  42334. */
  42335. function installBinary(&$installer)
  42336. {
  42337. if (!OS_WINDOWS) {
  42338. $a = false;
  42339. return $a;
  42340. }
  42341. if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
  42342. $releasetype = $this->getPackageType() . 'release';
  42343. if (!is_array($installer->getInstallPackages())) {
  42344. $a = false;
  42345. return $a;
  42346. }
  42347. foreach ($installer->getInstallPackages() as $p) {
  42348. if ($p->isExtension($this->_packageInfo['providesextension'])) {
  42349. if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') {
  42350. $a = false;
  42351. return $a; // the user probably downloaded it separately
  42352. }
  42353. }
  42354. }
  42355. if (isset($this->_packageInfo[$releasetype]['binarypackage'])) {
  42356. $installer->log(0, 'Attempting to download binary version of extension "' .
  42357. $this->_packageInfo['providesextension'] . '"');
  42358. $params = $this->_packageInfo[$releasetype]['binarypackage'];
  42359. if (!is_array($params) || !isset($params[0])) {
  42360. $params = array($params);
  42361. }
  42362. if (isset($this->_packageInfo['channel'])) {
  42363. foreach ($params as $i => $param) {
  42364. $params[$i] = array('channel' => $this->_packageInfo['channel'],
  42365. 'package' => $param, 'version' => $this->getVersion());
  42366. }
  42367. }
  42368. $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(),
  42369. $installer->config);
  42370. $verbose = $dl->config->get('verbose');
  42371. $dl->config->set('verbose', -1);
  42372. foreach ($params as $param) {
  42373. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  42374. $ret = $dl->download(array($param));
  42375. PEAR::popErrorHandling();
  42376. if (is_array($ret) && count($ret)) {
  42377. break;
  42378. }
  42379. }
  42380. $dl->config->set('verbose', $verbose);
  42381. if (is_array($ret)) {
  42382. if (count($ret) == 1) {
  42383. $pf = $ret[0]->getPackageFile();
  42384. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  42385. $err = $installer->install($ret[0]);
  42386. PEAR::popErrorHandling();
  42387. if (is_array($err)) {
  42388. $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage();
  42389. // "install" self, so all dependencies will work transparently
  42390. $this->_registry->addPackage2($this);
  42391. $installer->log(0, 'Download and install of binary extension "' .
  42392. $this->_registry->parsedPackageNameToString(
  42393. array('channel' => $pf->getChannel(),
  42394. 'package' => $pf->getPackage()), true) . '" successful');
  42395. $a = array($ret[0], $err);
  42396. return $a;
  42397. }
  42398. $installer->log(0, 'Download and install of binary extension "' .
  42399. $this->_registry->parsedPackageNameToString(
  42400. array('channel' => $pf->getChannel(),
  42401. 'package' => $pf->getPackage()), true) . '" failed');
  42402. }
  42403. }
  42404. }
  42405. }
  42406. $a = false;
  42407. return $a;
  42408. }
  42409. /**
  42410. * @return string|false Extension name
  42411. */
  42412. function getProvidesExtension()
  42413. {
  42414. if (in_array($this->getPackageType(),
  42415. array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
  42416. if (isset($this->_packageInfo['providesextension'])) {
  42417. return $this->_packageInfo['providesextension'];
  42418. }
  42419. }
  42420. return false;
  42421. }
  42422. /**
  42423. * @param string Extension name
  42424. * @return bool
  42425. */
  42426. function isExtension($extension)
  42427. {
  42428. if (in_array($this->getPackageType(),
  42429. array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
  42430. return $this->_packageInfo['providesextension'] == $extension;
  42431. }
  42432. return false;
  42433. }
  42434. /**
  42435. * Tests whether every part of the package.xml 1.0 is represented in
  42436. * this package.xml 2.0
  42437. * @param PEAR_PackageFile_v1
  42438. * @return bool
  42439. */
  42440. function isEquivalent($pf1)
  42441. {
  42442. if (!$pf1) {
  42443. return true;
  42444. }
  42445. if ($this->getPackageType() == 'bundle') {
  42446. return false;
  42447. }
  42448. $this->_stack->getErrors(true);
  42449. if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) {
  42450. return false;
  42451. }
  42452. $pass = true;
  42453. if ($pf1->getPackage() != $this->getPackage()) {
  42454. $this->_differentPackage($pf1->getPackage());
  42455. $pass = false;
  42456. }
  42457. if ($pf1->getVersion() != $this->getVersion()) {
  42458. $this->_differentVersion($pf1->getVersion());
  42459. $pass = false;
  42460. }
  42461. if (trim($pf1->getSummary()) != $this->getSummary()) {
  42462. $this->_differentSummary($pf1->getSummary());
  42463. $pass = false;
  42464. }
  42465. if (preg_replace('/\s+/', '', $pf1->getDescription()) !=
  42466. preg_replace('/\s+/', '', $this->getDescription())) {
  42467. $this->_differentDescription($pf1->getDescription());
  42468. $pass = false;
  42469. }
  42470. if ($pf1->getState() != $this->getState()) {
  42471. $this->_differentState($pf1->getState());
  42472. $pass = false;
  42473. }
  42474. if (!strstr(preg_replace('/\s+/', '', $this->getNotes()),
  42475. preg_replace('/\s+/', '', $pf1->getNotes()))) {
  42476. $this->_differentNotes($pf1->getNotes());
  42477. $pass = false;
  42478. }
  42479. $mymaintainers = $this->getMaintainers();
  42480. $yourmaintainers = $pf1->getMaintainers();
  42481. for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) {
  42482. $reset = false;
  42483. for ($i2 = 0; $i2 < count($mymaintainers); $i2++) {
  42484. if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) {
  42485. if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) {
  42486. $this->_differentRole($mymaintainers[$i2]['handle'],
  42487. $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']);
  42488. $pass = false;
  42489. }
  42490. if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) {
  42491. $this->_differentEmail($mymaintainers[$i2]['handle'],
  42492. $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']);
  42493. $pass = false;
  42494. }
  42495. if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) {
  42496. $this->_differentName($mymaintainers[$i2]['handle'],
  42497. $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']);
  42498. $pass = false;
  42499. }
  42500. unset($mymaintainers[$i2]);
  42501. $mymaintainers = array_values($mymaintainers);
  42502. unset($yourmaintainers[$i1]);
  42503. $yourmaintainers = array_values($yourmaintainers);
  42504. $reset = true;
  42505. break;
  42506. }
  42507. }
  42508. if ($reset) {
  42509. $i1 = -1;
  42510. }
  42511. }
  42512. $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers);
  42513. $filelist = $this->getFilelist();
  42514. foreach ($pf1->getFilelist() as $file => $atts) {
  42515. if (!isset($filelist[$file])) {
  42516. $this->_missingFile($file);
  42517. $pass = false;
  42518. }
  42519. }
  42520. return $pass;
  42521. }
  42522. function _differentPackage($package)
  42523. {
  42524. $this->_stack->push(__FUNCTION__, 'error', array('package' => $package,
  42525. 'self' => $this->getPackage()),
  42526. 'package.xml 1.0 package "%package%" does not match "%self%"');
  42527. }
  42528. function _differentVersion($version)
  42529. {
  42530. $this->_stack->push(__FUNCTION__, 'error', array('version' => $version,
  42531. 'self' => $this->getVersion()),
  42532. 'package.xml 1.0 version "%version%" does not match "%self%"');
  42533. }
  42534. function _differentState($state)
  42535. {
  42536. $this->_stack->push(__FUNCTION__, 'error', array('state' => $state,
  42537. 'self' => $this->getState()),
  42538. 'package.xml 1.0 state "%state%" does not match "%self%"');
  42539. }
  42540. function _differentRole($handle, $role, $selfrole)
  42541. {
  42542. $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
  42543. 'role' => $role, 'self' => $selfrole),
  42544. 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"');
  42545. }
  42546. function _differentEmail($handle, $email, $selfemail)
  42547. {
  42548. $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
  42549. 'email' => $email, 'self' => $selfemail),
  42550. 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"');
  42551. }
  42552. function _differentName($handle, $name, $selfname)
  42553. {
  42554. $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
  42555. 'name' => $name, 'self' => $selfname),
  42556. 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"');
  42557. }
  42558. function _unmatchedMaintainers($my, $yours)
  42559. {
  42560. if ($my) {
  42561. array_walk($my, function(&$i, $k) { $i = $i["handle"]; });
  42562. $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my),
  42563. 'package.xml 2.0 has unmatched extra maintainers "%handles%"');
  42564. }
  42565. if ($yours) {
  42566. array_walk($yours, function(&$i, $k) { $i = $i["handle"]; });
  42567. $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours),
  42568. 'package.xml 1.0 has unmatched extra maintainers "%handles%"');
  42569. }
  42570. }
  42571. function _differentNotes($notes)
  42572. {
  42573. $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...';
  42574. $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() :
  42575. substr($this->getNotes(), 0, 24) . '...';
  42576. $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes,
  42577. 'self' => $truncmynotes),
  42578. 'package.xml 1.0 release notes "%notes%" do not match "%self%"');
  42579. }
  42580. function _differentSummary($summary)
  42581. {
  42582. $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...';
  42583. $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() :
  42584. substr($this->getsummary(), 0, 24) . '...';
  42585. $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary,
  42586. 'self' => $truncmysummary),
  42587. 'package.xml 1.0 summary "%summary%" does not match "%self%"');
  42588. }
  42589. function _differentDescription($description)
  42590. {
  42591. $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...');
  42592. $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() :
  42593. substr($this->getdescription(), 0, 24) . '...');
  42594. $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription,
  42595. 'self' => $truncmydescription),
  42596. 'package.xml 1.0 description "%description%" does not match "%self%"');
  42597. }
  42598. function _missingFile($file)
  42599. {
  42600. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  42601. 'package.xml 1.0 file "%file%" is not present in <contents>');
  42602. }
  42603. /**
  42604. * WARNING - do not use this function unless you know what you're doing
  42605. */
  42606. function setRawState($state)
  42607. {
  42608. if (!isset($this->_packageInfo['stability'])) {
  42609. $this->_packageInfo['stability'] = array();
  42610. }
  42611. $this->_packageInfo['stability']['release'] = $state;
  42612. }
  42613. /**
  42614. * WARNING - do not use this function unless you know what you're doing
  42615. */
  42616. function setRawCompatible($compatible)
  42617. {
  42618. $this->_packageInfo['compatible'] = $compatible;
  42619. }
  42620. /**
  42621. * WARNING - do not use this function unless you know what you're doing
  42622. */
  42623. function setRawPackage($package)
  42624. {
  42625. $this->_packageInfo['name'] = $package;
  42626. }
  42627. /**
  42628. * WARNING - do not use this function unless you know what you're doing
  42629. */
  42630. function setRawChannel($channel)
  42631. {
  42632. $this->_packageInfo['channel'] = $channel;
  42633. }
  42634. function setRequestedGroup($group)
  42635. {
  42636. $this->_requestedGroup = $group;
  42637. }
  42638. function getRequestedGroup()
  42639. {
  42640. if (isset($this->_requestedGroup)) {
  42641. return $this->_requestedGroup;
  42642. }
  42643. return false;
  42644. }
  42645. /**
  42646. * For saving in the registry.
  42647. *
  42648. * Set the last version that was installed
  42649. * @param string
  42650. */
  42651. function setLastInstalledVersion($version)
  42652. {
  42653. $this->_packageInfo['_lastversion'] = $version;
  42654. }
  42655. /**
  42656. * @return string|false
  42657. */
  42658. function getLastInstalledVersion()
  42659. {
  42660. if (isset($this->_packageInfo['_lastversion'])) {
  42661. return $this->_packageInfo['_lastversion'];
  42662. }
  42663. return false;
  42664. }
  42665. /**
  42666. * Determines whether this package.xml has post-install scripts or not
  42667. * @return array|false
  42668. */
  42669. function listPostinstallScripts()
  42670. {
  42671. $filelist = $this->getFilelist();
  42672. $contents = $this->getContents();
  42673. $contents = $contents['dir']['file'];
  42674. if (!is_array($contents) || !isset($contents[0])) {
  42675. $contents = array($contents);
  42676. }
  42677. $taskfiles = array();
  42678. foreach ($contents as $file) {
  42679. $atts = $file['attribs'];
  42680. unset($file['attribs']);
  42681. if (count($file)) {
  42682. $taskfiles[$atts['name']] = $file;
  42683. }
  42684. }
  42685. $common = new PEAR_Common;
  42686. $common->debug = $this->_config->get('verbose');
  42687. $this->_scripts = array();
  42688. $ret = array();
  42689. foreach ($taskfiles as $name => $tasks) {
  42690. if (!isset($filelist[$name])) {
  42691. // ignored files will not be in the filelist
  42692. continue;
  42693. }
  42694. $atts = $filelist[$name];
  42695. foreach ($tasks as $tag => $raw) {
  42696. $task = $this->getTask($tag);
  42697. $task = new $task($this->_config, $common, PEAR_TASK_INSTALL);
  42698. if ($task->isScript()) {
  42699. $ret[] = $filelist[$name]['installed_as'];
  42700. }
  42701. }
  42702. }
  42703. if (count($ret)) {
  42704. return $ret;
  42705. }
  42706. return false;
  42707. }
  42708. /**
  42709. * Initialize post-install scripts for running
  42710. *
  42711. * This method can be used to detect post-install scripts, as the return value
  42712. * indicates whether any exist
  42713. * @return bool
  42714. */
  42715. function initPostinstallScripts()
  42716. {
  42717. $filelist = $this->getFilelist();
  42718. $contents = $this->getContents();
  42719. $contents = $contents['dir']['file'];
  42720. if (!is_array($contents) || !isset($contents[0])) {
  42721. $contents = array($contents);
  42722. }
  42723. $taskfiles = array();
  42724. foreach ($contents as $file) {
  42725. $atts = $file['attribs'];
  42726. unset($file['attribs']);
  42727. if (count($file)) {
  42728. $taskfiles[$atts['name']] = $file;
  42729. }
  42730. }
  42731. $common = new PEAR_Common;
  42732. $common->debug = $this->_config->get('verbose');
  42733. $this->_scripts = array();
  42734. foreach ($taskfiles as $name => $tasks) {
  42735. if (!isset($filelist[$name])) {
  42736. // file was not installed due to installconditions
  42737. continue;
  42738. }
  42739. $atts = $filelist[$name];
  42740. foreach ($tasks as $tag => $raw) {
  42741. $taskname = $this->getTask($tag);
  42742. $task = new $taskname($this->_config, $common, PEAR_TASK_INSTALL);
  42743. if (!$task->isScript()) {
  42744. continue; // scripts are only handled after installation
  42745. }
  42746. $lastversion = isset($this->_packageInfo['_lastversion']) ?
  42747. $this->_packageInfo['_lastversion'] : null;
  42748. $task->init($raw, $atts, $lastversion);
  42749. $res = $task->startSession($this, $atts['installed_as'], null);
  42750. if (!$res) {
  42751. continue; // skip this file
  42752. }
  42753. if (PEAR::isError($res)) {
  42754. return $res;
  42755. }
  42756. $this->_scripts[] = $task;
  42757. }
  42758. }
  42759. if (count($this->_scripts)) {
  42760. return true;
  42761. }
  42762. return false;
  42763. }
  42764. function runPostinstallScripts()
  42765. {
  42766. if ($this->initPostinstallScripts()) {
  42767. $ui = &PEAR_Frontend::singleton();
  42768. if ($ui) {
  42769. $ui->runPostinstallScripts($this->_scripts, $this);
  42770. }
  42771. }
  42772. }
  42773. /**
  42774. * Convert a recursive set of <dir> and <file> tags into a single <dir> tag with
  42775. * <file> tags.
  42776. */
  42777. function flattenFilelist()
  42778. {
  42779. if (isset($this->_packageInfo['bundle'])) {
  42780. return;
  42781. }
  42782. $filelist = array();
  42783. if (isset($this->_packageInfo['contents']['dir']['dir'])) {
  42784. $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']);
  42785. if (!isset($filelist[1])) {
  42786. $filelist = $filelist[0];
  42787. }
  42788. $this->_packageInfo['contents']['dir']['file'] = $filelist;
  42789. unset($this->_packageInfo['contents']['dir']['dir']);
  42790. } else {
  42791. // else already flattened but check for baseinstalldir propagation
  42792. if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) {
  42793. if (isset($this->_packageInfo['contents']['dir']['file'][0])) {
  42794. foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) {
  42795. if (isset($file['attribs']['baseinstalldir'])) {
  42796. continue;
  42797. }
  42798. $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir']
  42799. = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
  42800. }
  42801. } else {
  42802. if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) {
  42803. $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir']
  42804. = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
  42805. }
  42806. }
  42807. }
  42808. }
  42809. }
  42810. /**
  42811. * @param array the final flattened file list
  42812. * @param array the current directory being processed
  42813. * @param string|false any recursively inherited baeinstalldir attribute
  42814. * @param string private recursion variable
  42815. * @return array
  42816. * @access protected
  42817. */
  42818. function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '')
  42819. {
  42820. if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) {
  42821. $baseinstall = $dir['attribs']['baseinstalldir'];
  42822. }
  42823. if (isset($dir['dir'])) {
  42824. if (!isset($dir['dir'][0])) {
  42825. $dir['dir'] = array($dir['dir']);
  42826. }
  42827. foreach ($dir['dir'] as $subdir) {
  42828. if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) {
  42829. $name = '*unknown*';
  42830. } else {
  42831. $name = $subdir['attribs']['name'];
  42832. }
  42833. $newpath = empty($path) ? $name :
  42834. $path . '/' . $name;
  42835. $this->_getFlattenedFilelist($files, $subdir,
  42836. $baseinstall, $newpath);
  42837. }
  42838. }
  42839. if (isset($dir['file'])) {
  42840. if (!isset($dir['file'][0])) {
  42841. $dir['file'] = array($dir['file']);
  42842. }
  42843. foreach ($dir['file'] as $file) {
  42844. $attrs = $file['attribs'];
  42845. $name = $attrs['name'];
  42846. if ($baseinstall && !isset($attrs['baseinstalldir'])) {
  42847. $attrs['baseinstalldir'] = $baseinstall;
  42848. }
  42849. $attrs['name'] = empty($path) ? $name : $path . '/' . $name;
  42850. $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
  42851. $attrs['name']);
  42852. $file['attribs'] = $attrs;
  42853. $files[] = $file;
  42854. }
  42855. }
  42856. }
  42857. function setConfig(&$config)
  42858. {
  42859. $this->_config = &$config;
  42860. $this->_registry = &$config->getRegistry();
  42861. }
  42862. function setLogger(&$logger)
  42863. {
  42864. if (!is_object($logger) || !method_exists($logger, 'log')) {
  42865. return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
  42866. }
  42867. $this->_logger = &$logger;
  42868. }
  42869. /**
  42870. * WARNING - do not use this function directly unless you know what you're doing
  42871. */
  42872. function setDeps($deps)
  42873. {
  42874. $this->_packageInfo['dependencies'] = $deps;
  42875. }
  42876. /**
  42877. * WARNING - do not use this function directly unless you know what you're doing
  42878. */
  42879. function setCompatible($compat)
  42880. {
  42881. $this->_packageInfo['compatible'] = $compat;
  42882. }
  42883. function setPackagefile($file, $archive = false)
  42884. {
  42885. $this->_packageFile = $file;
  42886. $this->_archiveFile = $archive ? $archive : $file;
  42887. }
  42888. /**
  42889. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  42890. * @param boolean determines whether to purge the error stack after retrieving
  42891. * @return array
  42892. */
  42893. function getValidationWarnings($purge = true)
  42894. {
  42895. return $this->_stack->getErrors($purge);
  42896. }
  42897. function getPackageFile()
  42898. {
  42899. return $this->_packageFile;
  42900. }
  42901. function getArchiveFile()
  42902. {
  42903. return $this->_archiveFile;
  42904. }
  42905. /**
  42906. * Directly set the array that defines this packagefile
  42907. *
  42908. * WARNING: no validation. This should only be performed by internal methods
  42909. * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2
  42910. * @param array
  42911. */
  42912. function fromArray($pinfo)
  42913. {
  42914. unset($pinfo['old']);
  42915. unset($pinfo['xsdversion']);
  42916. // If the changelog isn't an array then it was passed in as an empty tag
  42917. if (isset($pinfo['changelog']) && !is_array($pinfo['changelog'])) {
  42918. unset($pinfo['changelog']);
  42919. }
  42920. $this->_incomplete = false;
  42921. $this->_packageInfo = $pinfo;
  42922. }
  42923. function isIncomplete()
  42924. {
  42925. return $this->_incomplete;
  42926. }
  42927. /**
  42928. * @return array
  42929. */
  42930. function toArray($forreg = false)
  42931. {
  42932. if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
  42933. return false;
  42934. }
  42935. return $this->getArray($forreg);
  42936. }
  42937. function getArray($forReg = false)
  42938. {
  42939. if ($forReg) {
  42940. $arr = $this->_packageInfo;
  42941. $arr['old'] = array();
  42942. $arr['old']['version'] = $this->getVersion();
  42943. $arr['old']['release_date'] = $this->getDate();
  42944. $arr['old']['release_state'] = $this->getState();
  42945. $arr['old']['release_license'] = $this->getLicense();
  42946. $arr['old']['release_notes'] = $this->getNotes();
  42947. $arr['old']['release_deps'] = $this->getDeps();
  42948. $arr['old']['maintainers'] = $this->getMaintainers();
  42949. $arr['xsdversion'] = '2.0';
  42950. return $arr;
  42951. } else {
  42952. $info = $this->_packageInfo;
  42953. unset($info['dirtree']);
  42954. if (isset($info['_lastversion'])) {
  42955. unset($info['_lastversion']);
  42956. }
  42957. if (isset($info['#binarypackage'])) {
  42958. unset($info['#binarypackage']);
  42959. }
  42960. return $info;
  42961. }
  42962. }
  42963. function packageInfo($field)
  42964. {
  42965. $arr = $this->getArray(true);
  42966. if ($field == 'state') {
  42967. return $arr['stability']['release'];
  42968. }
  42969. if ($field == 'api-version') {
  42970. return $arr['version']['api'];
  42971. }
  42972. if ($field == 'api-state') {
  42973. return $arr['stability']['api'];
  42974. }
  42975. if (isset($arr['old'][$field])) {
  42976. if (!is_string($arr['old'][$field])) {
  42977. return null;
  42978. }
  42979. return $arr['old'][$field];
  42980. }
  42981. if (isset($arr[$field])) {
  42982. if (!is_string($arr[$field])) {
  42983. return null;
  42984. }
  42985. return $arr[$field];
  42986. }
  42987. return null;
  42988. }
  42989. function getName()
  42990. {
  42991. return $this->getPackage();
  42992. }
  42993. function getPackage()
  42994. {
  42995. if (isset($this->_packageInfo['name'])) {
  42996. return $this->_packageInfo['name'];
  42997. }
  42998. return false;
  42999. }
  43000. function getChannel()
  43001. {
  43002. if (isset($this->_packageInfo['uri'])) {
  43003. return '__uri';
  43004. }
  43005. if (isset($this->_packageInfo['channel'])) {
  43006. return strtolower($this->_packageInfo['channel']);
  43007. }
  43008. return false;
  43009. }
  43010. function getUri()
  43011. {
  43012. if (isset($this->_packageInfo['uri'])) {
  43013. return $this->_packageInfo['uri'];
  43014. }
  43015. return false;
  43016. }
  43017. function getExtends()
  43018. {
  43019. if (isset($this->_packageInfo['extends'])) {
  43020. return $this->_packageInfo['extends'];
  43021. }
  43022. return false;
  43023. }
  43024. function getSummary()
  43025. {
  43026. if (isset($this->_packageInfo['summary'])) {
  43027. return $this->_packageInfo['summary'];
  43028. }
  43029. return false;
  43030. }
  43031. function getDescription()
  43032. {
  43033. if (isset($this->_packageInfo['description'])) {
  43034. return $this->_packageInfo['description'];
  43035. }
  43036. return false;
  43037. }
  43038. function getMaintainers($raw = false)
  43039. {
  43040. if (!isset($this->_packageInfo['lead'])) {
  43041. return false;
  43042. }
  43043. if ($raw) {
  43044. $ret = array('lead' => $this->_packageInfo['lead']);
  43045. (isset($this->_packageInfo['developer'])) ?
  43046. $ret['developer'] = $this->_packageInfo['developer'] :null;
  43047. (isset($this->_packageInfo['contributor'])) ?
  43048. $ret['contributor'] = $this->_packageInfo['contributor'] :null;
  43049. (isset($this->_packageInfo['helper'])) ?
  43050. $ret['helper'] = $this->_packageInfo['helper'] :null;
  43051. return $ret;
  43052. } else {
  43053. $ret = array();
  43054. $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] :
  43055. array($this->_packageInfo['lead']);
  43056. foreach ($leads as $lead) {
  43057. $s = $lead;
  43058. $s['handle'] = $s['user'];
  43059. unset($s['user']);
  43060. $s['role'] = 'lead';
  43061. $ret[] = $s;
  43062. }
  43063. if (isset($this->_packageInfo['developer'])) {
  43064. $leads = isset($this->_packageInfo['developer'][0]) ?
  43065. $this->_packageInfo['developer'] :
  43066. array($this->_packageInfo['developer']);
  43067. foreach ($leads as $maintainer) {
  43068. $s = $maintainer;
  43069. $s['handle'] = $s['user'];
  43070. unset($s['user']);
  43071. $s['role'] = 'developer';
  43072. $ret[] = $s;
  43073. }
  43074. }
  43075. if (isset($this->_packageInfo['contributor'])) {
  43076. $leads = isset($this->_packageInfo['contributor'][0]) ?
  43077. $this->_packageInfo['contributor'] :
  43078. array($this->_packageInfo['contributor']);
  43079. foreach ($leads as $maintainer) {
  43080. $s = $maintainer;
  43081. $s['handle'] = $s['user'];
  43082. unset($s['user']);
  43083. $s['role'] = 'contributor';
  43084. $ret[] = $s;
  43085. }
  43086. }
  43087. if (isset($this->_packageInfo['helper'])) {
  43088. $leads = isset($this->_packageInfo['helper'][0]) ?
  43089. $this->_packageInfo['helper'] :
  43090. array($this->_packageInfo['helper']);
  43091. foreach ($leads as $maintainer) {
  43092. $s = $maintainer;
  43093. $s['handle'] = $s['user'];
  43094. unset($s['user']);
  43095. $s['role'] = 'helper';
  43096. $ret[] = $s;
  43097. }
  43098. }
  43099. return $ret;
  43100. }
  43101. return false;
  43102. }
  43103. function getLeads()
  43104. {
  43105. if (isset($this->_packageInfo['lead'])) {
  43106. return $this->_packageInfo['lead'];
  43107. }
  43108. return false;
  43109. }
  43110. function getDevelopers()
  43111. {
  43112. if (isset($this->_packageInfo['developer'])) {
  43113. return $this->_packageInfo['developer'];
  43114. }
  43115. return false;
  43116. }
  43117. function getContributors()
  43118. {
  43119. if (isset($this->_packageInfo['contributor'])) {
  43120. return $this->_packageInfo['contributor'];
  43121. }
  43122. return false;
  43123. }
  43124. function getHelpers()
  43125. {
  43126. if (isset($this->_packageInfo['helper'])) {
  43127. return $this->_packageInfo['helper'];
  43128. }
  43129. return false;
  43130. }
  43131. function setDate($date)
  43132. {
  43133. if (!isset($this->_packageInfo['date'])) {
  43134. // ensure that the extends tag is set up in the right location
  43135. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  43136. array('time', 'version',
  43137. 'stability', 'license', 'notes', 'contents', 'compatible',
  43138. 'dependencies', 'providesextension', 'srcpackage', 'srcuri',
  43139. 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
  43140. 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date');
  43141. }
  43142. $this->_packageInfo['date'] = $date;
  43143. $this->_isValid = 0;
  43144. }
  43145. function setTime($time)
  43146. {
  43147. $this->_isValid = 0;
  43148. if (!isset($this->_packageInfo['time'])) {
  43149. // ensure that the time tag is set up in the right location
  43150. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  43151. array('version',
  43152. 'stability', 'license', 'notes', 'contents', 'compatible',
  43153. 'dependencies', 'providesextension', 'srcpackage', 'srcuri',
  43154. 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
  43155. 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time');
  43156. }
  43157. $this->_packageInfo['time'] = $time;
  43158. }
  43159. function getDate()
  43160. {
  43161. if (isset($this->_packageInfo['date'])) {
  43162. return $this->_packageInfo['date'];
  43163. }
  43164. return false;
  43165. }
  43166. function getTime()
  43167. {
  43168. if (isset($this->_packageInfo['time'])) {
  43169. return $this->_packageInfo['time'];
  43170. }
  43171. return false;
  43172. }
  43173. /**
  43174. * @param package|api version category to return
  43175. */
  43176. function getVersion($key = 'release')
  43177. {
  43178. if (isset($this->_packageInfo['version'][$key])) {
  43179. return $this->_packageInfo['version'][$key];
  43180. }
  43181. return false;
  43182. }
  43183. function getStability()
  43184. {
  43185. if (isset($this->_packageInfo['stability'])) {
  43186. return $this->_packageInfo['stability'];
  43187. }
  43188. return false;
  43189. }
  43190. function getState($key = 'release')
  43191. {
  43192. if (isset($this->_packageInfo['stability'][$key])) {
  43193. return $this->_packageInfo['stability'][$key];
  43194. }
  43195. return false;
  43196. }
  43197. function getLicense($raw = false)
  43198. {
  43199. if (isset($this->_packageInfo['license'])) {
  43200. if ($raw) {
  43201. return $this->_packageInfo['license'];
  43202. }
  43203. if (is_array($this->_packageInfo['license'])) {
  43204. return $this->_packageInfo['license']['_content'];
  43205. } else {
  43206. return $this->_packageInfo['license'];
  43207. }
  43208. }
  43209. return false;
  43210. }
  43211. function getLicenseLocation()
  43212. {
  43213. if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) {
  43214. return false;
  43215. }
  43216. return $this->_packageInfo['license']['attribs'];
  43217. }
  43218. function getNotes()
  43219. {
  43220. if (isset($this->_packageInfo['notes'])) {
  43221. return $this->_packageInfo['notes'];
  43222. }
  43223. return false;
  43224. }
  43225. /**
  43226. * Return the <usesrole> tag contents, if any
  43227. * @return array|false
  43228. */
  43229. function getUsesrole()
  43230. {
  43231. if (isset($this->_packageInfo['usesrole'])) {
  43232. return $this->_packageInfo['usesrole'];
  43233. }
  43234. return false;
  43235. }
  43236. /**
  43237. * Return the <usestask> tag contents, if any
  43238. * @return array|false
  43239. */
  43240. function getUsestask()
  43241. {
  43242. if (isset($this->_packageInfo['usestask'])) {
  43243. return $this->_packageInfo['usestask'];
  43244. }
  43245. return false;
  43246. }
  43247. /**
  43248. * This should only be used to retrieve filenames and install attributes
  43249. */
  43250. function getFilelist($preserve = false)
  43251. {
  43252. if (isset($this->_packageInfo['filelist']) && !$preserve) {
  43253. return $this->_packageInfo['filelist'];
  43254. }
  43255. $this->flattenFilelist();
  43256. if ($contents = $this->getContents()) {
  43257. $ret = array();
  43258. if (!isset($contents['dir'])) {
  43259. return false;
  43260. }
  43261. if (!isset($contents['dir']['file'][0])) {
  43262. $contents['dir']['file'] = array($contents['dir']['file']);
  43263. }
  43264. foreach ($contents['dir']['file'] as $file) {
  43265. if (!isset($file['attribs']['name'])) {
  43266. continue;
  43267. }
  43268. $name = $file['attribs']['name'];
  43269. if (!$preserve) {
  43270. $file = $file['attribs'];
  43271. }
  43272. $ret[$name] = $file;
  43273. }
  43274. if (!$preserve) {
  43275. $this->_packageInfo['filelist'] = $ret;
  43276. }
  43277. return $ret;
  43278. }
  43279. return false;
  43280. }
  43281. /**
  43282. * Return configure options array, if any
  43283. *
  43284. * @return array|false
  43285. */
  43286. function getConfigureOptions()
  43287. {
  43288. if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
  43289. return false;
  43290. }
  43291. $releases = $this->getReleases();
  43292. if (isset($releases[0])) {
  43293. $releases = $releases[0];
  43294. }
  43295. if (isset($releases['configureoption'])) {
  43296. if (!isset($releases['configureoption'][0])) {
  43297. $releases['configureoption'] = array($releases['configureoption']);
  43298. }
  43299. for ($i = 0; $i < count($releases['configureoption']); $i++) {
  43300. $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs'];
  43301. }
  43302. return $releases['configureoption'];
  43303. }
  43304. return false;
  43305. }
  43306. /**
  43307. * This is only used at install-time, after all serialization
  43308. * is over.
  43309. */
  43310. function resetFilelist()
  43311. {
  43312. $this->_packageInfo['filelist'] = array();
  43313. }
  43314. /**
  43315. * Retrieve a list of files that should be installed on this computer
  43316. * @return array
  43317. */
  43318. function getInstallationFilelist($forfilecheck = false)
  43319. {
  43320. $contents = $this->getFilelist(true);
  43321. if (isset($contents['dir']['attribs']['baseinstalldir'])) {
  43322. $base = $contents['dir']['attribs']['baseinstalldir'];
  43323. }
  43324. if (isset($this->_packageInfo['bundle'])) {
  43325. return PEAR::raiseError(
  43326. 'Exception: bundles should be handled in download code only');
  43327. }
  43328. $release = $this->getReleases();
  43329. if ($release) {
  43330. if (!isset($release[0])) {
  43331. if (!isset($release['installconditions']) && !isset($release['filelist'])) {
  43332. if ($forfilecheck) {
  43333. return $this->getFilelist();
  43334. }
  43335. return $contents;
  43336. }
  43337. $release = array($release);
  43338. }
  43339. $depchecker = &$this->getPEARDependency2($this->_config, array(),
  43340. array('channel' => $this->getChannel(), 'package' => $this->getPackage()),
  43341. PEAR_VALIDATE_INSTALLING);
  43342. foreach ($release as $instance) {
  43343. if (isset($instance['installconditions'])) {
  43344. $installconditions = $instance['installconditions'];
  43345. if (is_array($installconditions)) {
  43346. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  43347. foreach ($installconditions as $type => $conditions) {
  43348. if (!isset($conditions[0])) {
  43349. $conditions = array($conditions);
  43350. }
  43351. foreach ($conditions as $condition) {
  43352. $ret = $depchecker->{"validate{$type}Dependency"}($condition);
  43353. if (PEAR::isError($ret)) {
  43354. PEAR::popErrorHandling();
  43355. continue 3; // skip this release
  43356. }
  43357. }
  43358. }
  43359. PEAR::popErrorHandling();
  43360. }
  43361. }
  43362. // this is the release to use
  43363. if (isset($instance['filelist'])) {
  43364. // ignore files
  43365. if (isset($instance['filelist']['ignore'])) {
  43366. $ignore = isset($instance['filelist']['ignore'][0]) ?
  43367. $instance['filelist']['ignore'] :
  43368. array($instance['filelist']['ignore']);
  43369. foreach ($ignore as $ig) {
  43370. unset ($contents[$ig['attribs']['name']]);
  43371. }
  43372. }
  43373. // install files as this name
  43374. if (isset($instance['filelist']['install'])) {
  43375. $installas = isset($instance['filelist']['install'][0]) ?
  43376. $instance['filelist']['install'] :
  43377. array($instance['filelist']['install']);
  43378. foreach ($installas as $as) {
  43379. $contents[$as['attribs']['name']]['attribs']['install-as'] =
  43380. $as['attribs']['as'];
  43381. }
  43382. }
  43383. }
  43384. if ($forfilecheck) {
  43385. foreach ($contents as $file => $attrs) {
  43386. $contents[$file] = $attrs['attribs'];
  43387. }
  43388. }
  43389. return $contents;
  43390. }
  43391. } else { // simple release - no installconditions or install-as
  43392. if ($forfilecheck) {
  43393. return $this->getFilelist();
  43394. }
  43395. return $contents;
  43396. }
  43397. // no releases matched
  43398. return PEAR::raiseError('No releases in package.xml matched the existing operating ' .
  43399. 'system, extensions installed, or architecture, cannot install');
  43400. }
  43401. /**
  43402. * This is only used at install-time, after all serialization
  43403. * is over.
  43404. * @param string file name
  43405. * @param string installed path
  43406. */
  43407. function setInstalledAs($file, $path)
  43408. {
  43409. if ($path) {
  43410. return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
  43411. }
  43412. unset($this->_packageInfo['filelist'][$file]['installed_as']);
  43413. }
  43414. function getInstalledLocation($file)
  43415. {
  43416. if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) {
  43417. return $this->_packageInfo['filelist'][$file]['installed_as'];
  43418. }
  43419. return false;
  43420. }
  43421. /**
  43422. * This is only used at install-time, after all serialization
  43423. * is over.
  43424. */
  43425. function installedFile($file, $atts)
  43426. {
  43427. if (isset($this->_packageInfo['filelist'][$file])) {
  43428. $this->_packageInfo['filelist'][$file] =
  43429. array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
  43430. } else {
  43431. $this->_packageInfo['filelist'][$file] = $atts['attribs'];
  43432. }
  43433. }
  43434. /**
  43435. * Retrieve the contents tag
  43436. */
  43437. function getContents()
  43438. {
  43439. if (isset($this->_packageInfo['contents'])) {
  43440. return $this->_packageInfo['contents'];
  43441. }
  43442. return false;
  43443. }
  43444. /**
  43445. * @param string full path to file
  43446. * @param string attribute name
  43447. * @param string attribute value
  43448. * @param int risky but fast - use this to choose a file based on its position in the list
  43449. * of files. Index is zero-based like PHP arrays.
  43450. * @return bool success of operation
  43451. */
  43452. function setFileAttribute($filename, $attr, $value, $index = false)
  43453. {
  43454. $this->_isValid = 0;
  43455. if (in_array($attr, array('role', 'name', 'baseinstalldir'))) {
  43456. $this->_filesValid = false;
  43457. }
  43458. if ($index !== false &&
  43459. isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) {
  43460. $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value;
  43461. return true;
  43462. }
  43463. if (!isset($this->_packageInfo['contents']['dir']['file'])) {
  43464. return false;
  43465. }
  43466. $files = $this->_packageInfo['contents']['dir']['file'];
  43467. if (!isset($files[0])) {
  43468. $files = array($files);
  43469. $ind = false;
  43470. } else {
  43471. $ind = true;
  43472. }
  43473. foreach ($files as $i => $file) {
  43474. if (isset($file['attribs'])) {
  43475. if ($file['attribs']['name'] == $filename) {
  43476. if ($ind) {
  43477. $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value;
  43478. } else {
  43479. $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value;
  43480. }
  43481. return true;
  43482. }
  43483. }
  43484. }
  43485. return false;
  43486. }
  43487. function setDirtree($path)
  43488. {
  43489. if (!isset($this->_packageInfo['dirtree'])) {
  43490. $this->_packageInfo['dirtree'] = array();
  43491. }
  43492. $this->_packageInfo['dirtree'][$path] = true;
  43493. }
  43494. function getDirtree()
  43495. {
  43496. if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
  43497. return $this->_packageInfo['dirtree'];
  43498. }
  43499. return false;
  43500. }
  43501. function resetDirtree()
  43502. {
  43503. unset($this->_packageInfo['dirtree']);
  43504. }
  43505. /**
  43506. * Determines whether this package claims it is compatible with the version of
  43507. * the package that has a recommended version dependency
  43508. * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package
  43509. * @return boolean
  43510. */
  43511. function isCompatible($pf)
  43512. {
  43513. if (!isset($this->_packageInfo['compatible'])) {
  43514. return false;
  43515. }
  43516. if (!isset($this->_packageInfo['channel'])) {
  43517. return false;
  43518. }
  43519. $me = $pf->getVersion();
  43520. $compatible = $this->_packageInfo['compatible'];
  43521. if (!isset($compatible[0])) {
  43522. $compatible = array($compatible);
  43523. }
  43524. $found = false;
  43525. foreach ($compatible as $info) {
  43526. if (strtolower($info['name']) == strtolower($pf->getPackage())) {
  43527. if (strtolower($info['channel']) == strtolower($pf->getChannel())) {
  43528. $found = true;
  43529. break;
  43530. }
  43531. }
  43532. }
  43533. if (!$found) {
  43534. return false;
  43535. }
  43536. if (isset($info['exclude'])) {
  43537. if (!isset($info['exclude'][0])) {
  43538. $info['exclude'] = array($info['exclude']);
  43539. }
  43540. foreach ($info['exclude'] as $exclude) {
  43541. if (version_compare($me, $exclude, '==')) {
  43542. return false;
  43543. }
  43544. }
  43545. }
  43546. if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) {
  43547. return true;
  43548. }
  43549. return false;
  43550. }
  43551. /**
  43552. * @return array|false
  43553. */
  43554. function getCompatible()
  43555. {
  43556. if (isset($this->_packageInfo['compatible'])) {
  43557. return $this->_packageInfo['compatible'];
  43558. }
  43559. return false;
  43560. }
  43561. function getDependencies()
  43562. {
  43563. if (isset($this->_packageInfo['dependencies'])) {
  43564. return $this->_packageInfo['dependencies'];
  43565. }
  43566. return false;
  43567. }
  43568. function isSubpackageOf($p)
  43569. {
  43570. return $p->isSubpackage($this);
  43571. }
  43572. /**
  43573. * Determines whether the passed in package is a subpackage of this package.
  43574. *
  43575. * No version checking is done, only name verification.
  43576. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  43577. * @return bool
  43578. */
  43579. function isSubpackage($p)
  43580. {
  43581. $sub = array();
  43582. if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) {
  43583. $sub = $this->_packageInfo['dependencies']['required']['subpackage'];
  43584. if (!isset($sub[0])) {
  43585. $sub = array($sub);
  43586. }
  43587. }
  43588. if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) {
  43589. $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage'];
  43590. if (!isset($sub1[0])) {
  43591. $sub1 = array($sub1);
  43592. }
  43593. $sub = array_merge($sub, $sub1);
  43594. }
  43595. if (isset($this->_packageInfo['dependencies']['group'])) {
  43596. $group = $this->_packageInfo['dependencies']['group'];
  43597. if (!isset($group[0])) {
  43598. $group = array($group);
  43599. }
  43600. foreach ($group as $deps) {
  43601. if (isset($deps['subpackage'])) {
  43602. $sub2 = $deps['subpackage'];
  43603. if (!isset($sub2[0])) {
  43604. $sub2 = array($sub2);
  43605. }
  43606. $sub = array_merge($sub, $sub2);
  43607. }
  43608. }
  43609. }
  43610. foreach ($sub as $dep) {
  43611. if (strtolower($dep['name']) == strtolower($p->getPackage())) {
  43612. if (isset($dep['channel'])) {
  43613. if (strtolower($dep['channel']) == strtolower($p->getChannel())) {
  43614. return true;
  43615. }
  43616. } else {
  43617. if ($dep['uri'] == $p->getURI()) {
  43618. return true;
  43619. }
  43620. }
  43621. }
  43622. }
  43623. return false;
  43624. }
  43625. function dependsOn($package, $channel)
  43626. {
  43627. if (!($deps = $this->getDependencies())) {
  43628. return false;
  43629. }
  43630. foreach (array('package', 'subpackage') as $type) {
  43631. foreach (array('required', 'optional') as $needed) {
  43632. if (isset($deps[$needed][$type])) {
  43633. if (!isset($deps[$needed][$type][0])) {
  43634. $deps[$needed][$type] = array($deps[$needed][$type]);
  43635. }
  43636. foreach ($deps[$needed][$type] as $dep) {
  43637. $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
  43638. if (strtolower($dep['name']) == strtolower($package) &&
  43639. $depchannel == $channel) {
  43640. return true;
  43641. }
  43642. }
  43643. }
  43644. }
  43645. if (isset($deps['group'])) {
  43646. if (!isset($deps['group'][0])) {
  43647. $dep['group'] = array($deps['group']);
  43648. }
  43649. foreach ($deps['group'] as $group) {
  43650. if (isset($group[$type])) {
  43651. if (!is_array($group[$type])) {
  43652. $group[$type] = array($group[$type]);
  43653. }
  43654. foreach ($group[$type] as $dep) {
  43655. $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
  43656. if (strtolower($dep['name']) == strtolower($package) &&
  43657. $depchannel == $channel) {
  43658. return true;
  43659. }
  43660. }
  43661. }
  43662. }
  43663. }
  43664. }
  43665. return false;
  43666. }
  43667. /**
  43668. * Get the contents of a dependency group
  43669. * @param string
  43670. * @return array|false
  43671. */
  43672. function getDependencyGroup($name)
  43673. {
  43674. $name = strtolower($name);
  43675. if (!isset($this->_packageInfo['dependencies']['group'])) {
  43676. return false;
  43677. }
  43678. $groups = $this->_packageInfo['dependencies']['group'];
  43679. if (!isset($groups[0])) {
  43680. $groups = array($groups);
  43681. }
  43682. foreach ($groups as $group) {
  43683. if (strtolower($group['attribs']['name']) == $name) {
  43684. return $group;
  43685. }
  43686. }
  43687. return false;
  43688. }
  43689. /**
  43690. * Retrieve a partial package.xml 1.0 representation of dependencies
  43691. *
  43692. * a very limited representation of dependencies is returned by this method.
  43693. * The <exclude> tag for excluding certain versions of a dependency is
  43694. * completely ignored. In addition, dependency groups are ignored, with the
  43695. * assumption that all dependencies in dependency groups are also listed in
  43696. * the optional group that work with all dependency groups
  43697. * @param boolean return package.xml 2.0 <dependencies> tag
  43698. * @return array|false
  43699. */
  43700. function getDeps($raw = false, $nopearinstaller = false)
  43701. {
  43702. if (isset($this->_packageInfo['dependencies'])) {
  43703. if ($raw) {
  43704. return $this->_packageInfo['dependencies'];
  43705. }
  43706. $ret = array();
  43707. $map = array(
  43708. 'php' => 'php',
  43709. 'package' => 'pkg',
  43710. 'subpackage' => 'pkg',
  43711. 'extension' => 'ext',
  43712. 'os' => 'os',
  43713. 'pearinstaller' => 'pkg',
  43714. );
  43715. foreach (array('required', 'optional') as $type) {
  43716. $optional = ($type == 'optional') ? 'yes' : 'no';
  43717. if (!isset($this->_packageInfo['dependencies'][$type])
  43718. || empty($this->_packageInfo['dependencies'][$type])) {
  43719. continue;
  43720. }
  43721. foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) {
  43722. if ($dtype == 'pearinstaller' && $nopearinstaller) {
  43723. continue;
  43724. }
  43725. if ((is_array($deps) && !isset($deps[0])) || !is_array($deps)) {
  43726. $deps = array($deps);
  43727. }
  43728. foreach ($deps as $dep) {
  43729. if (!isset($map[$dtype])) {
  43730. // no support for arch type
  43731. continue;
  43732. }
  43733. if ($dtype == 'pearinstaller') {
  43734. $dep['name'] = 'PEAR';
  43735. $dep['channel'] = 'pear.php.net';
  43736. }
  43737. $s = array('type' => $map[$dtype]);
  43738. if (isset($dep['channel'])) {
  43739. $s['channel'] = $dep['channel'];
  43740. }
  43741. if (isset($dep['uri'])) {
  43742. $s['uri'] = $dep['uri'];
  43743. }
  43744. if (isset($dep['name'])) {
  43745. $s['name'] = $dep['name'];
  43746. }
  43747. if (isset($dep['conflicts'])) {
  43748. $s['rel'] = 'not';
  43749. } else {
  43750. if (!isset($dep['min']) &&
  43751. !isset($dep['max'])) {
  43752. $s['rel'] = 'has';
  43753. $s['optional'] = $optional;
  43754. } elseif (isset($dep['min']) &&
  43755. isset($dep['max'])) {
  43756. $s['rel'] = 'ge';
  43757. $s1 = $s;
  43758. $s1['rel'] = 'le';
  43759. $s['version'] = $dep['min'];
  43760. $s1['version'] = $dep['max'];
  43761. if (isset($dep['channel'])) {
  43762. $s1['channel'] = $dep['channel'];
  43763. }
  43764. if ($dtype != 'php') {
  43765. $s['name'] = $dep['name'];
  43766. $s1['name'] = $dep['name'];
  43767. }
  43768. $s['optional'] = $optional;
  43769. $s1['optional'] = $optional;
  43770. $ret[] = $s1;
  43771. } elseif (isset($dep['min'])) {
  43772. if (isset($dep['exclude']) &&
  43773. $dep['exclude'] == $dep['min']) {
  43774. $s['rel'] = 'gt';
  43775. } else {
  43776. $s['rel'] = 'ge';
  43777. }
  43778. $s['version'] = $dep['min'];
  43779. $s['optional'] = $optional;
  43780. if ($dtype != 'php') {
  43781. $s['name'] = $dep['name'];
  43782. }
  43783. } elseif (isset($dep['max'])) {
  43784. if (isset($dep['exclude']) &&
  43785. $dep['exclude'] == $dep['max']) {
  43786. $s['rel'] = 'lt';
  43787. } else {
  43788. $s['rel'] = 'le';
  43789. }
  43790. $s['version'] = $dep['max'];
  43791. $s['optional'] = $optional;
  43792. if ($dtype != 'php') {
  43793. $s['name'] = $dep['name'];
  43794. }
  43795. }
  43796. }
  43797. $ret[] = $s;
  43798. }
  43799. }
  43800. }
  43801. if (count($ret)) {
  43802. return $ret;
  43803. }
  43804. }
  43805. return false;
  43806. }
  43807. /**
  43808. * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false
  43809. */
  43810. function getPackageType()
  43811. {
  43812. if (isset($this->_packageInfo['phprelease'])) {
  43813. return 'php';
  43814. }
  43815. if (isset($this->_packageInfo['extsrcrelease'])) {
  43816. return 'extsrc';
  43817. }
  43818. if (isset($this->_packageInfo['extbinrelease'])) {
  43819. return 'extbin';
  43820. }
  43821. if (isset($this->_packageInfo['zendextsrcrelease'])) {
  43822. return 'zendextsrc';
  43823. }
  43824. if (isset($this->_packageInfo['zendextbinrelease'])) {
  43825. return 'zendextbin';
  43826. }
  43827. if (isset($this->_packageInfo['bundle'])) {
  43828. return 'bundle';
  43829. }
  43830. return false;
  43831. }
  43832. /**
  43833. * @return array|false
  43834. */
  43835. function getReleases()
  43836. {
  43837. $type = $this->getPackageType();
  43838. if ($type != 'bundle') {
  43839. $type .= 'release';
  43840. }
  43841. if ($this->getPackageType() && isset($this->_packageInfo[$type])) {
  43842. return $this->_packageInfo[$type];
  43843. }
  43844. return false;
  43845. }
  43846. /**
  43847. * @return array
  43848. */
  43849. function getChangelog()
  43850. {
  43851. if (isset($this->_packageInfo['changelog'])) {
  43852. return $this->_packageInfo['changelog'];
  43853. }
  43854. return false;
  43855. }
  43856. function hasDeps()
  43857. {
  43858. return isset($this->_packageInfo['dependencies']);
  43859. }
  43860. function getPackagexmlVersion()
  43861. {
  43862. if (isset($this->_packageInfo['zendextsrcrelease'])) {
  43863. return '2.1';
  43864. }
  43865. if (isset($this->_packageInfo['zendextbinrelease'])) {
  43866. return '2.1';
  43867. }
  43868. return '2.0';
  43869. }
  43870. /**
  43871. * @return array|false
  43872. */
  43873. function getSourcePackage()
  43874. {
  43875. if (isset($this->_packageInfo['extbinrelease']) ||
  43876. isset($this->_packageInfo['zendextbinrelease'])) {
  43877. return array('channel' => $this->_packageInfo['srcchannel'],
  43878. 'package' => $this->_packageInfo['srcpackage']);
  43879. }
  43880. return false;
  43881. }
  43882. function getBundledPackages()
  43883. {
  43884. if (isset($this->_packageInfo['bundle'])) {
  43885. return $this->_packageInfo['contents']['bundledpackage'];
  43886. }
  43887. return false;
  43888. }
  43889. function getLastModified()
  43890. {
  43891. if (isset($this->_packageInfo['_lastmodified'])) {
  43892. return $this->_packageInfo['_lastmodified'];
  43893. }
  43894. return false;
  43895. }
  43896. /**
  43897. * Get the contents of a file listed within the package.xml
  43898. * @param string
  43899. * @return string
  43900. */
  43901. function getFileContents($file)
  43902. {
  43903. if ($this->_archiveFile == $this->_packageFile) { // unpacked
  43904. $dir = dirname($this->_packageFile);
  43905. $file = $dir . DIRECTORY_SEPARATOR . $file;
  43906. $file = str_replace(array('/', '\\'),
  43907. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
  43908. if (file_exists($file) && is_readable($file)) {
  43909. return implode('', file($file));
  43910. }
  43911. } else { // tgz
  43912. $tar = new Archive_Tar($this->_archiveFile);
  43913. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  43914. if ($file != 'package.xml' && $file != 'package2.xml') {
  43915. $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
  43916. }
  43917. $file = $tar->extractInString($file);
  43918. $tar->popErrorHandling();
  43919. if (PEAR::isError($file)) {
  43920. return PEAR::raiseError("Cannot locate file '$file' in archive");
  43921. }
  43922. return $file;
  43923. }
  43924. }
  43925. function &getRW()
  43926. {
  43927. if (!class_exists('PEAR_PackageFile_v2_rw')) {
  43928. require_once 'PEAR/PackageFile/v2/rw.php';
  43929. }
  43930. $a = new PEAR_PackageFile_v2_rw;
  43931. foreach (get_object_vars($this) as $name => $unused) {
  43932. if (!isset($this->$name)) {
  43933. continue;
  43934. }
  43935. if ($name == '_config' || $name == '_logger'|| $name == '_registry' ||
  43936. $name == '_stack') {
  43937. $a->$name = &$this->$name;
  43938. } else {
  43939. $a->$name = $this->$name;
  43940. }
  43941. }
  43942. return $a;
  43943. }
  43944. function &getDefaultGenerator()
  43945. {
  43946. if (!class_exists('PEAR_PackageFile_Generator_v2')) {
  43947. require_once 'PEAR/PackageFile/Generator/v2.php';
  43948. }
  43949. $a = new PEAR_PackageFile_Generator_v2($this);
  43950. return $a;
  43951. }
  43952. function analyzeSourceCode($file, $string = false)
  43953. {
  43954. if (!isset($this->_v2Validator) ||
  43955. !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
  43956. if (!class_exists('PEAR_PackageFile_v2_Validator')) {
  43957. require_once 'PEAR/PackageFile/v2/Validator.php';
  43958. }
  43959. $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
  43960. }
  43961. return $this->_v2Validator->analyzeSourceCode($file, $string);
  43962. }
  43963. function validate($state = PEAR_VALIDATE_NORMAL)
  43964. {
  43965. if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
  43966. return false;
  43967. }
  43968. if (!isset($this->_v2Validator) ||
  43969. !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
  43970. if (!class_exists('PEAR_PackageFile_v2_Validator')) {
  43971. require_once 'PEAR/PackageFile/v2/Validator.php';
  43972. }
  43973. $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
  43974. }
  43975. if (isset($this->_packageInfo['xsdversion'])) {
  43976. unset($this->_packageInfo['xsdversion']);
  43977. }
  43978. return $this->_v2Validator->validate($this, $state);
  43979. }
  43980. function getTasksNs()
  43981. {
  43982. if (!isset($this->_tasksNs)) {
  43983. if (isset($this->_packageInfo['attribs'])) {
  43984. foreach ($this->_packageInfo['attribs'] as $name => $value) {
  43985. if ($value == 'http://pear.php.net/dtd/tasks-1.0') {
  43986. $this->_tasksNs = str_replace('xmlns:', '', $name);
  43987. break;
  43988. }
  43989. }
  43990. }
  43991. }
  43992. return $this->_tasksNs;
  43993. }
  43994. /**
  43995. * Determine whether a task name is a valid task. Custom tasks may be defined
  43996. * using subdirectories by putting a "-" in the name, as in <tasks:mycustom-task>
  43997. *
  43998. * Note that this method will auto-load the task class file and test for the existence
  43999. * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class
  44000. * PEAR_Task_mycustom_task
  44001. * @param string
  44002. * @return boolean
  44003. */
  44004. function getTask($task)
  44005. {
  44006. $this->getTasksNs();
  44007. // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace
  44008. $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task);
  44009. $taskfile = str_replace(' ', '/', ucwords($task));
  44010. $task = str_replace(array(' ', '/'), '_', ucwords($task));
  44011. if (class_exists("PEAR_Task_$task")) {
  44012. return "PEAR_Task_$task";
  44013. }
  44014. $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true);
  44015. if ($fp) {
  44016. fclose($fp);
  44017. require_once "PEAR/Task/$taskfile.php";
  44018. return "PEAR_Task_$task";
  44019. }
  44020. return false;
  44021. }
  44022. /**
  44023. * Key-friendly array_splice
  44024. * @param tagname to splice a value in before
  44025. * @param mixed the value to splice in
  44026. * @param string the new tag name
  44027. */
  44028. function _ksplice($array, $key, $value, $newkey)
  44029. {
  44030. $offset = array_search($key, array_keys($array));
  44031. $after = array_slice($array, $offset);
  44032. $before = array_slice($array, 0, $offset);
  44033. $before[$newkey] = $value;
  44034. return array_merge($before, $after);
  44035. }
  44036. /**
  44037. * @param array a list of possible keys, in the order they may occur
  44038. * @param mixed contents of the new package.xml tag
  44039. * @param string tag name
  44040. * @access private
  44041. */
  44042. function _insertBefore($array, $keys, $contents, $newkey)
  44043. {
  44044. foreach ($keys as $key) {
  44045. if (isset($array[$key])) {
  44046. return $array = $this->_ksplice($array, $key, $contents, $newkey);
  44047. }
  44048. }
  44049. $array[$newkey] = $contents;
  44050. return $array;
  44051. }
  44052. /**
  44053. * @param subsection of {@link $_packageInfo}
  44054. * @param array|string tag contents
  44055. * @param array format:
  44056. * <pre>
  44057. * array(
  44058. * tagname => array(list of tag names that follow this one),
  44059. * childtagname => array(list of child tag names that follow this one),
  44060. * )
  44061. * </pre>
  44062. *
  44063. * This allows construction of nested tags
  44064. * @access private
  44065. */
  44066. function _mergeTag($manip, $contents, $order)
  44067. {
  44068. if (count($order)) {
  44069. foreach ($order as $tag => $curorder) {
  44070. if (!isset($manip[$tag])) {
  44071. // ensure that the tag is set up
  44072. $manip = $this->_insertBefore($manip, $curorder, array(), $tag);
  44073. }
  44074. if (count($order) > 1) {
  44075. $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1));
  44076. return $manip;
  44077. }
  44078. }
  44079. } else {
  44080. return $manip;
  44081. }
  44082. if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) {
  44083. $manip[$tag][] = $contents;
  44084. } else {
  44085. if (is_array($manip[$tag]) && !count($manip[$tag])) {
  44086. $manip[$tag] = $contents;
  44087. } else {
  44088. $manip[$tag] = array($manip[$tag]);
  44089. $manip[$tag][] = $contents;
  44090. }
  44091. }
  44092. return $manip;
  44093. }
  44094. }
  44095. ?>
  44096. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/REST/10.php�����������������������������������������������������������������������0000644�0001750�0001750�00000077621�13565304531�014530� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  44097. /**
  44098. * PEAR_REST_10
  44099. *
  44100. * PHP versions 4 and 5
  44101. *
  44102. * @category pear
  44103. * @package PEAR
  44104. * @author Greg Beaver <cellog@php.net>
  44105. * @copyright 1997-2009 The Authors
  44106. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  44107. * @link http://pear.php.net/package/PEAR
  44108. * @since File available since Release 1.4.0a12
  44109. */
  44110. /**
  44111. * For downloading REST xml/txt files
  44112. */
  44113. require_once 'PEAR/REST.php';
  44114. /**
  44115. * Implement REST 1.0
  44116. *
  44117. * @category pear
  44118. * @package PEAR
  44119. * @author Greg Beaver <cellog@php.net>
  44120. * @copyright 1997-2009 The Authors
  44121. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  44122. * @version Release: 1.10.10
  44123. * @link http://pear.php.net/package/PEAR
  44124. * @since Class available since Release 1.4.0a12
  44125. */
  44126. class PEAR_REST_10
  44127. {
  44128. /**
  44129. * @var PEAR_REST
  44130. */
  44131. var $_rest;
  44132. function __construct($config, $options = array())
  44133. {
  44134. $this->_rest = new PEAR_REST($config, $options);
  44135. }
  44136. /**
  44137. * Retrieve information about a remote package to be downloaded from a REST server
  44138. *
  44139. * @param string $base The uri to prepend to all REST calls
  44140. * @param array $packageinfo an array of format:
  44141. * <pre>
  44142. * array(
  44143. * 'package' => 'packagename',
  44144. * 'channel' => 'channelname',
  44145. * ['state' => 'alpha' (or valid state),]
  44146. * -or-
  44147. * ['version' => '1.whatever']
  44148. * </pre>
  44149. * @param string $prefstate Current preferred_state config variable value
  44150. * @param bool $installed the installed version of this package to compare against
  44151. * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
  44152. */
  44153. function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
  44154. {
  44155. $states = $this->betterStates($prefstate, true);
  44156. if (!$states) {
  44157. return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  44158. }
  44159. $channel = $packageinfo['channel'];
  44160. $package = $packageinfo['package'];
  44161. $state = isset($packageinfo['state']) ? $packageinfo['state'] : null;
  44162. $version = isset($packageinfo['version']) ? $packageinfo['version'] : null;
  44163. $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
  44164. $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  44165. if (PEAR::isError($info)) {
  44166. return PEAR::raiseError('No releases available for package "' .
  44167. $channel . '/' . $package . '"');
  44168. }
  44169. if (!isset($info['r'])) {
  44170. return false;
  44171. }
  44172. $release = $found = false;
  44173. if (!is_array($info['r']) || !isset($info['r'][0])) {
  44174. $info['r'] = array($info['r']);
  44175. }
  44176. foreach ($info['r'] as $release) {
  44177. if (!isset($this->_rest->_options['force']) && ($installed &&
  44178. version_compare($release['v'], $installed, '<'))) {
  44179. continue;
  44180. }
  44181. if (isset($state)) {
  44182. // try our preferred state first
  44183. if ($release['s'] == $state) {
  44184. $found = true;
  44185. break;
  44186. }
  44187. // see if there is something newer and more stable
  44188. // bug #7221
  44189. if (in_array($release['s'], $this->betterStates($state), true)) {
  44190. $found = true;
  44191. break;
  44192. }
  44193. } elseif (isset($version)) {
  44194. if ($release['v'] == $version) {
  44195. $found = true;
  44196. break;
  44197. }
  44198. } else {
  44199. if (in_array($release['s'], $states)) {
  44200. $found = true;
  44201. break;
  44202. }
  44203. }
  44204. }
  44205. return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
  44206. }
  44207. function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
  44208. $prefstate = 'stable', $installed = false, $channel = false)
  44209. {
  44210. $states = $this->betterStates($prefstate, true);
  44211. if (!$states) {
  44212. return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  44213. }
  44214. $channel = $dependency['channel'];
  44215. $package = $dependency['name'];
  44216. $state = isset($dependency['state']) ? $dependency['state'] : null;
  44217. $version = isset($dependency['version']) ? $dependency['version'] : null;
  44218. $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
  44219. $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  44220. if (PEAR::isError($info)) {
  44221. return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
  44222. . '" dependency "' . $channel . '/' . $package . '" has no releases');
  44223. }
  44224. if (!is_array($info) || !isset($info['r'])) {
  44225. return false;
  44226. }
  44227. $exclude = array();
  44228. $min = $max = $recommended = false;
  44229. if ($xsdversion == '1.0') {
  44230. switch ($dependency['rel']) {
  44231. case 'ge' :
  44232. $min = $dependency['version'];
  44233. break;
  44234. case 'gt' :
  44235. $min = $dependency['version'];
  44236. $exclude = array($dependency['version']);
  44237. break;
  44238. case 'eq' :
  44239. $recommended = $dependency['version'];
  44240. break;
  44241. case 'lt' :
  44242. $max = $dependency['version'];
  44243. $exclude = array($dependency['version']);
  44244. break;
  44245. case 'le' :
  44246. $max = $dependency['version'];
  44247. break;
  44248. case 'ne' :
  44249. $exclude = array($dependency['version']);
  44250. break;
  44251. }
  44252. } else {
  44253. $min = isset($dependency['min']) ? $dependency['min'] : false;
  44254. $max = isset($dependency['max']) ? $dependency['max'] : false;
  44255. $recommended = isset($dependency['recommended']) ?
  44256. $dependency['recommended'] : false;
  44257. if (isset($dependency['exclude'])) {
  44258. if (!isset($dependency['exclude'][0])) {
  44259. $exclude = array($dependency['exclude']);
  44260. }
  44261. }
  44262. }
  44263. $release = $found = false;
  44264. if (!is_array($info['r']) || !isset($info['r'][0])) {
  44265. $info['r'] = array($info['r']);
  44266. }
  44267. foreach ($info['r'] as $release) {
  44268. if (!isset($this->_rest->_options['force']) && ($installed &&
  44269. version_compare($release['v'], $installed, '<'))) {
  44270. continue;
  44271. }
  44272. if (in_array($release['v'], $exclude)) { // skip excluded versions
  44273. continue;
  44274. }
  44275. // allow newer releases to say "I'm OK with the dependent package"
  44276. if ($xsdversion == '2.0' && isset($release['co'])) {
  44277. if (!is_array($release['co']) || !isset($release['co'][0])) {
  44278. $release['co'] = array($release['co']);
  44279. }
  44280. foreach ($release['co'] as $entry) {
  44281. if (isset($entry['x']) && !is_array($entry['x'])) {
  44282. $entry['x'] = array($entry['x']);
  44283. } elseif (!isset($entry['x'])) {
  44284. $entry['x'] = array();
  44285. }
  44286. if ($entry['c'] == $deppackage['channel'] &&
  44287. strtolower($entry['p']) == strtolower($deppackage['package']) &&
  44288. version_compare($deppackage['version'], $entry['min'], '>=') &&
  44289. version_compare($deppackage['version'], $entry['max'], '<=') &&
  44290. !in_array($release['v'], $entry['x'])) {
  44291. $recommended = $release['v'];
  44292. break;
  44293. }
  44294. }
  44295. }
  44296. if ($recommended) {
  44297. if ($release['v'] != $recommended) { // if we want a specific
  44298. // version, then skip all others
  44299. continue;
  44300. } else {
  44301. if (!in_array($release['s'], $states)) {
  44302. // the stability is too low, but we must return the
  44303. // recommended version if possible
  44304. return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
  44305. }
  44306. }
  44307. }
  44308. if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
  44309. continue;
  44310. }
  44311. if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
  44312. continue;
  44313. }
  44314. if ($installed && version_compare($release['v'], $installed, '<')) {
  44315. continue;
  44316. }
  44317. if (in_array($release['s'], $states)) { // if in the preferred state...
  44318. $found = true; // ... then use it
  44319. break;
  44320. }
  44321. }
  44322. return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
  44323. }
  44324. /**
  44325. * Take raw data and return the array needed for processing a download URL
  44326. *
  44327. * @param string $base REST base uri
  44328. * @param string $package Package name
  44329. * @param array $release an array of format array('v' => version, 's' => state)
  44330. * describing the release to download
  44331. * @param array $info list of all releases as defined by allreleases.xml
  44332. * @param bool|null $found determines whether the release was found or this is the next
  44333. * best alternative. If null, then versions were skipped because
  44334. * of PHP dependency
  44335. * @return array|PEAR_Error
  44336. * @access private
  44337. */
  44338. function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false)
  44339. {
  44340. if (!$found) {
  44341. $release = $info['r'][0];
  44342. }
  44343. $packageLower = strtolower($package);
  44344. $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' .
  44345. 'info.xml', false, false, $channel);
  44346. if (PEAR::isError($pinfo)) {
  44347. return PEAR::raiseError('Package "' . $package .
  44348. '" does not have REST info xml available');
  44349. }
  44350. $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
  44351. $release['v'] . '.xml', false, false, $channel);
  44352. if (PEAR::isError($releaseinfo)) {
  44353. return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
  44354. '" does not have REST xml available');
  44355. }
  44356. $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
  44357. 'deps.' . $release['v'] . '.txt', false, true, $channel);
  44358. if (PEAR::isError($packagexml)) {
  44359. return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
  44360. '" does not have REST dependency information available');
  44361. }
  44362. $packagexml = unserialize($packagexml);
  44363. if (!$packagexml) {
  44364. $packagexml = array();
  44365. }
  44366. $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower .
  44367. '/allreleases.xml', false, false, $channel);
  44368. if (PEAR::isError($allinfo)) {
  44369. return $allinfo;
  44370. }
  44371. if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) {
  44372. $allinfo['r'] = array($allinfo['r']);
  44373. }
  44374. $compatible = false;
  44375. foreach ($allinfo['r'] as $release) {
  44376. if ($release['v'] != $releaseinfo['v']) {
  44377. continue;
  44378. }
  44379. if (!isset($release['co'])) {
  44380. break;
  44381. }
  44382. $compatible = array();
  44383. if (!is_array($release['co']) || !isset($release['co'][0])) {
  44384. $release['co'] = array($release['co']);
  44385. }
  44386. foreach ($release['co'] as $entry) {
  44387. $comp = array();
  44388. $comp['name'] = $entry['p'];
  44389. $comp['channel'] = $entry['c'];
  44390. $comp['min'] = $entry['min'];
  44391. $comp['max'] = $entry['max'];
  44392. if (isset($entry['x']) && !is_array($entry['x'])) {
  44393. $comp['exclude'] = $entry['x'];
  44394. }
  44395. $compatible[] = $comp;
  44396. }
  44397. if (count($compatible) == 1) {
  44398. $compatible = $compatible[0];
  44399. }
  44400. break;
  44401. }
  44402. $deprecated = false;
  44403. if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
  44404. if (is_array($pinfo['dp'])) {
  44405. $deprecated = array('channel' => (string) $pinfo['dc'],
  44406. 'package' => trim($pinfo['dp']['_content']));
  44407. } else {
  44408. $deprecated = array('channel' => (string) $pinfo['dc'],
  44409. 'package' => trim($pinfo['dp']));
  44410. }
  44411. }
  44412. $return = array(
  44413. 'version' => $releaseinfo['v'],
  44414. 'info' => $packagexml,
  44415. 'package' => $releaseinfo['p']['_content'],
  44416. 'stability' => $releaseinfo['st'],
  44417. 'compatible' => $compatible,
  44418. 'deprecated' => $deprecated,
  44419. );
  44420. if ($found) {
  44421. $return['url'] = $releaseinfo['g'];
  44422. return $return;
  44423. }
  44424. $return['php'] = $phpversion;
  44425. return $return;
  44426. }
  44427. function listPackages($base, $channel = false)
  44428. {
  44429. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  44430. if (PEAR::isError($packagelist)) {
  44431. return $packagelist;
  44432. }
  44433. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  44434. return array();
  44435. }
  44436. if (!is_array($packagelist['p'])) {
  44437. $packagelist['p'] = array($packagelist['p']);
  44438. }
  44439. return $packagelist['p'];
  44440. }
  44441. /**
  44442. * List all categories of a REST server
  44443. *
  44444. * @param string $base base URL of the server
  44445. * @return array of categorynames
  44446. */
  44447. function listCategories($base, $channel = false)
  44448. {
  44449. $categories = array();
  44450. // c/categories.xml does not exist;
  44451. // check for every package its category manually
  44452. // This is SLOOOWWWW : ///
  44453. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  44454. if (PEAR::isError($packagelist)) {
  44455. return $packagelist;
  44456. }
  44457. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  44458. $ret = array();
  44459. return $ret;
  44460. }
  44461. if (!is_array($packagelist['p'])) {
  44462. $packagelist['p'] = array($packagelist['p']);
  44463. }
  44464. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  44465. foreach ($packagelist['p'] as $package) {
  44466. $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  44467. if (PEAR::isError($inf)) {
  44468. PEAR::popErrorHandling();
  44469. return $inf;
  44470. }
  44471. $cat = $inf['ca']['_content'];
  44472. if (!isset($categories[$cat])) {
  44473. $categories[$cat] = $inf['ca'];
  44474. }
  44475. }
  44476. return array_values($categories);
  44477. }
  44478. /**
  44479. * List a category of a REST server
  44480. *
  44481. * @param string $base base URL of the server
  44482. * @param string $category name of the category
  44483. * @param boolean $info also download full package info
  44484. * @return array of packagenames
  44485. */
  44486. function listCategory($base, $category, $info = false, $channel = false)
  44487. {
  44488. // gives '404 Not Found' error when category doesn't exist
  44489. $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel);
  44490. if (PEAR::isError($packagelist)) {
  44491. return $packagelist;
  44492. }
  44493. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  44494. return array();
  44495. }
  44496. if (!is_array($packagelist['p']) ||
  44497. !isset($packagelist['p'][0])) { // only 1 pkg
  44498. $packagelist = array($packagelist['p']);
  44499. } else {
  44500. $packagelist = $packagelist['p'];
  44501. }
  44502. if ($info == true) {
  44503. // get individual package info
  44504. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  44505. foreach ($packagelist as $i => $packageitem) {
  44506. $url = sprintf('%s'.'r/%s/latest.txt',
  44507. $base,
  44508. strtolower($packageitem['_content']));
  44509. $version = $this->_rest->retrieveData($url, false, false, $channel);
  44510. if (PEAR::isError($version)) {
  44511. break; // skipit
  44512. }
  44513. $url = sprintf('%s'.'r/%s/%s.xml',
  44514. $base,
  44515. strtolower($packageitem['_content']),
  44516. $version);
  44517. $info = $this->_rest->retrieveData($url, false, false, $channel);
  44518. if (PEAR::isError($info)) {
  44519. break; // skipit
  44520. }
  44521. $packagelist[$i]['info'] = $info;
  44522. }
  44523. PEAR::popErrorHandling();
  44524. }
  44525. return $packagelist;
  44526. }
  44527. function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
  44528. {
  44529. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  44530. if (PEAR::isError($packagelist)) {
  44531. return $packagelist;
  44532. }
  44533. if ($this->_rest->config->get('verbose') > 0) {
  44534. $ui = &PEAR_Frontend::singleton();
  44535. $ui->log('Retrieving data...0%', true);
  44536. }
  44537. $ret = array();
  44538. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  44539. return $ret;
  44540. }
  44541. if (!is_array($packagelist['p'])) {
  44542. $packagelist['p'] = array($packagelist['p']);
  44543. }
  44544. // only search-packagename = quicksearch !
  44545. if ($searchpackage && (!$searchsummary || empty($searchpackage))) {
  44546. $newpackagelist = array();
  44547. foreach ($packagelist['p'] as $package) {
  44548. if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) {
  44549. $newpackagelist[] = $package;
  44550. }
  44551. }
  44552. $packagelist['p'] = $newpackagelist;
  44553. }
  44554. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  44555. $next = .1;
  44556. foreach ($packagelist['p'] as $progress => $package) {
  44557. if ($this->_rest->config->get('verbose') > 0) {
  44558. if ($progress / count($packagelist['p']) >= $next) {
  44559. if ($next == .5) {
  44560. $ui->log('50%', false);
  44561. } else {
  44562. $ui->log('.', false);
  44563. }
  44564. $next += .1;
  44565. }
  44566. }
  44567. if ($basic) { // remote-list command
  44568. if ($dostable) {
  44569. $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  44570. '/stable.txt', false, false, $channel);
  44571. } else {
  44572. $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  44573. '/latest.txt', false, false, $channel);
  44574. }
  44575. if (PEAR::isError($latest)) {
  44576. $latest = false;
  44577. }
  44578. $info = array('stable' => $latest);
  44579. } else { // list-all command
  44580. $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  44581. if (PEAR::isError($inf)) {
  44582. PEAR::popErrorHandling();
  44583. return $inf;
  44584. }
  44585. if ($searchpackage) {
  44586. $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false);
  44587. if (!$found && !(isset($searchsummary) && !empty($searchsummary)
  44588. && (stristr($inf['s'], $searchsummary) !== false
  44589. || stristr($inf['d'], $searchsummary) !== false)))
  44590. {
  44591. continue;
  44592. };
  44593. }
  44594. $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  44595. '/allreleases.xml', false, false, $channel);
  44596. if (PEAR::isError($releases)) {
  44597. continue;
  44598. }
  44599. if (!isset($releases['r'][0])) {
  44600. $releases['r'] = array($releases['r']);
  44601. }
  44602. unset($latest);
  44603. unset($unstable);
  44604. unset($stable);
  44605. unset($state);
  44606. foreach ($releases['r'] as $release) {
  44607. if (!isset($latest)) {
  44608. if ($dostable && $release['s'] == 'stable') {
  44609. $latest = $release['v'];
  44610. $state = 'stable';
  44611. }
  44612. if (!$dostable) {
  44613. $latest = $release['v'];
  44614. $state = $release['s'];
  44615. }
  44616. }
  44617. if (!isset($stable) && $release['s'] == 'stable') {
  44618. $stable = $release['v'];
  44619. if (!isset($unstable)) {
  44620. $unstable = $stable;
  44621. }
  44622. }
  44623. if (!isset($unstable) && $release['s'] != 'stable') {
  44624. $latest = $unstable = $release['v'];
  44625. $state = $release['s'];
  44626. }
  44627. if (isset($latest) && !isset($state)) {
  44628. $state = $release['s'];
  44629. }
  44630. if (isset($latest) && isset($stable) && isset($unstable)) {
  44631. break;
  44632. }
  44633. }
  44634. $deps = array();
  44635. if (!isset($unstable)) {
  44636. $unstable = false;
  44637. $state = 'stable';
  44638. if (isset($stable)) {
  44639. $latest = $unstable = $stable;
  44640. }
  44641. } else {
  44642. $latest = $unstable;
  44643. }
  44644. if (!isset($latest)) {
  44645. $latest = false;
  44646. }
  44647. if ($latest) {
  44648. $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
  44649. $latest . '.txt', false, false, $channel);
  44650. if (!PEAR::isError($d)) {
  44651. $d = unserialize($d);
  44652. if ($d) {
  44653. if (isset($d['required'])) {
  44654. if (!class_exists('PEAR_PackageFile_v2')) {
  44655. require_once 'PEAR/PackageFile/v2.php';
  44656. }
  44657. if (!isset($pf)) {
  44658. $pf = new PEAR_PackageFile_v2;
  44659. }
  44660. $pf->setDeps($d);
  44661. $tdeps = $pf->getDeps();
  44662. } else {
  44663. $tdeps = $d;
  44664. }
  44665. foreach ($tdeps as $dep) {
  44666. if ($dep['type'] !== 'pkg') {
  44667. continue;
  44668. }
  44669. $deps[] = $dep;
  44670. }
  44671. }
  44672. }
  44673. }
  44674. if (!isset($stable)) {
  44675. $stable = '-n/a-';
  44676. }
  44677. if (!$searchpackage) {
  44678. $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' =>
  44679. $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
  44680. 'unstable' => $unstable, 'state' => $state);
  44681. } else {
  44682. $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' =>
  44683. $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
  44684. 'unstable' => $unstable, 'state' => $state);
  44685. }
  44686. }
  44687. $ret[$package] = $info;
  44688. }
  44689. PEAR::popErrorHandling();
  44690. return $ret;
  44691. }
  44692. function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
  44693. {
  44694. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  44695. if (PEAR::isError($packagelist)) {
  44696. return $packagelist;
  44697. }
  44698. $ret = array();
  44699. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  44700. return $ret;
  44701. }
  44702. if (!is_array($packagelist['p'])) {
  44703. $packagelist['p'] = array($packagelist['p']);
  44704. }
  44705. foreach ($packagelist['p'] as $package) {
  44706. if (!isset($installed[strtolower($package)])) {
  44707. continue;
  44708. }
  44709. $inst_version = $reg->packageInfo($package, 'version', $channel);
  44710. $inst_state = $reg->packageInfo($package, 'release_state', $channel);
  44711. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  44712. $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  44713. '/allreleases.xml', false, false, $channel);
  44714. PEAR::popErrorHandling();
  44715. if (PEAR::isError($info)) {
  44716. continue; // no remote releases
  44717. }
  44718. if (!isset($info['r'])) {
  44719. continue;
  44720. }
  44721. $release = $found = false;
  44722. if (!is_array($info['r']) || !isset($info['r'][0])) {
  44723. $info['r'] = array($info['r']);
  44724. }
  44725. // $info['r'] is sorted by version number
  44726. usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
  44727. foreach ($info['r'] as $release) {
  44728. if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
  44729. // not newer than the one installed
  44730. break;
  44731. }
  44732. // new version > installed version
  44733. if (!$pref_state) {
  44734. // every state is a good state
  44735. $found = true;
  44736. break;
  44737. } else {
  44738. $new_state = $release['s'];
  44739. // if new state >= installed state: go
  44740. if (in_array($new_state, $this->betterStates($inst_state, true))) {
  44741. $found = true;
  44742. break;
  44743. } else {
  44744. // only allow to lower the state of package,
  44745. // if new state >= preferred state: go
  44746. if (in_array($new_state, $this->betterStates($pref_state, true))) {
  44747. $found = true;
  44748. break;
  44749. }
  44750. }
  44751. }
  44752. }
  44753. if (!$found) {
  44754. continue;
  44755. }
  44756. $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
  44757. $release['v'] . '.xml', false, false, $channel);
  44758. if (PEAR::isError($relinfo)) {
  44759. return $relinfo;
  44760. }
  44761. $ret[$package] = array(
  44762. 'version' => $release['v'],
  44763. 'state' => $release['s'],
  44764. 'filesize' => $relinfo['f'],
  44765. );
  44766. }
  44767. return $ret;
  44768. }
  44769. function packageInfo($base, $package, $channel = false)
  44770. {
  44771. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  44772. $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  44773. if (PEAR::isError($pinfo)) {
  44774. PEAR::popErrorHandling();
  44775. return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' .
  44776. $pinfo->getMessage());
  44777. }
  44778. $releases = array();
  44779. $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  44780. '/allreleases.xml', false, false, $channel);
  44781. if (!PEAR::isError($allreleases)) {
  44782. if (!class_exists('PEAR_PackageFile_v2')) {
  44783. require_once 'PEAR/PackageFile/v2.php';
  44784. }
  44785. if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) {
  44786. $allreleases['r'] = array($allreleases['r']);
  44787. }
  44788. $pf = new PEAR_PackageFile_v2;
  44789. foreach ($allreleases['r'] as $release) {
  44790. $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
  44791. $release['v'] . '.txt', false, false, $channel);
  44792. if (PEAR::isError($ds)) {
  44793. continue;
  44794. }
  44795. if (!isset($latest)) {
  44796. $latest = $release['v'];
  44797. }
  44798. $pf->setDeps(unserialize($ds));
  44799. $ds = $pf->getDeps();
  44800. $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package)
  44801. . '/' . $release['v'] . '.xml', false, false, $channel);
  44802. if (PEAR::isError($info)) {
  44803. continue;
  44804. }
  44805. $releases[$release['v']] = array(
  44806. 'doneby' => $info['m'],
  44807. 'license' => $info['l'],
  44808. 'summary' => $info['s'],
  44809. 'description' => $info['d'],
  44810. 'releasedate' => $info['da'],
  44811. 'releasenotes' => $info['n'],
  44812. 'state' => $release['s'],
  44813. 'deps' => $ds ? $ds : array(),
  44814. );
  44815. }
  44816. } else {
  44817. $latest = '';
  44818. }
  44819. PEAR::popErrorHandling();
  44820. if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
  44821. if (is_array($pinfo['dp'])) {
  44822. $deprecated = array('channel' => (string) $pinfo['dc'],
  44823. 'package' => trim($pinfo['dp']['_content']));
  44824. } else {
  44825. $deprecated = array('channel' => (string) $pinfo['dc'],
  44826. 'package' => trim($pinfo['dp']));
  44827. }
  44828. } else {
  44829. $deprecated = false;
  44830. }
  44831. if (!isset($latest)) {
  44832. $latest = '';
  44833. }
  44834. return array(
  44835. 'name' => $pinfo['n'],
  44836. 'channel' => $pinfo['c'],
  44837. 'category' => $pinfo['ca']['_content'],
  44838. 'stable' => $latest,
  44839. 'license' => $pinfo['l'],
  44840. 'summary' => $pinfo['s'],
  44841. 'description' => $pinfo['d'],
  44842. 'releases' => $releases,
  44843. 'deprecated' => $deprecated,
  44844. );
  44845. }
  44846. /**
  44847. * Return an array containing all of the states that are more stable than
  44848. * or equal to the passed in state
  44849. *
  44850. * @param string Release state
  44851. * @param boolean Determines whether to include $state in the list
  44852. * @return false|array False if $state is not a valid release state
  44853. */
  44854. function betterStates($state, $include = false)
  44855. {
  44856. static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  44857. $i = array_search($state, $states);
  44858. if ($i === false) {
  44859. return false;
  44860. }
  44861. if ($include) {
  44862. $i--;
  44863. }
  44864. return array_slice($states, $i + 1);
  44865. }
  44866. /**
  44867. * Sort releases by version number
  44868. *
  44869. * @access private
  44870. */
  44871. function _sortReleasesByVersionNumber($a, $b)
  44872. {
  44873. if (version_compare($a['v'], $b['v'], '=')) {
  44874. return 0;
  44875. }
  44876. if (version_compare($a['v'], $b['v'], '>')) {
  44877. return -1;
  44878. }
  44879. if (version_compare($a['v'], $b['v'], '<')) {
  44880. return 1;
  44881. }
  44882. }
  44883. }
  44884. ���������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/REST/11.php�����������������������������������������������������������������������0000644�0001750�0001750�00000025751�13565304531�014526� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  44885. /**
  44886. * PEAR_REST_11 - implement faster list-all/remote-list command
  44887. *
  44888. * PHP versions 4 and 5
  44889. *
  44890. * @category pear
  44891. * @package PEAR
  44892. * @author Greg Beaver <cellog@php.net>
  44893. * @copyright 1997-2009 The Authors
  44894. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  44895. * @link http://pear.php.net/package/PEAR
  44896. * @since File available since Release 1.4.3
  44897. */
  44898. /**
  44899. * For downloading REST xml/txt files
  44900. */
  44901. require_once 'PEAR/REST.php';
  44902. /**
  44903. * Implement REST 1.1
  44904. *
  44905. * @category pear
  44906. * @package PEAR
  44907. * @author Greg Beaver <cellog@php.net>
  44908. * @copyright 1997-2009 The Authors
  44909. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  44910. * @version Release: 1.10.10
  44911. * @link http://pear.php.net/package/PEAR
  44912. * @since Class available since Release 1.4.3
  44913. */
  44914. class PEAR_REST_11
  44915. {
  44916. /**
  44917. * @var PEAR_REST
  44918. */
  44919. var $_rest;
  44920. function __construct($config, $options = array())
  44921. {
  44922. $this->_rest = new PEAR_REST($config, $options);
  44923. }
  44924. function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
  44925. {
  44926. $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel);
  44927. if (PEAR::isError($categorylist)) {
  44928. return $categorylist;
  44929. }
  44930. $ret = array();
  44931. if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) {
  44932. $categorylist['c'] = array($categorylist['c']);
  44933. }
  44934. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  44935. foreach ($categorylist['c'] as $progress => $category) {
  44936. $category = $category['_content'];
  44937. $packagesinfo = $this->_rest->retrieveData($base .
  44938. 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel);
  44939. if (PEAR::isError($packagesinfo)) {
  44940. continue;
  44941. }
  44942. if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) {
  44943. continue;
  44944. }
  44945. if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) {
  44946. $packagesinfo['pi'] = array($packagesinfo['pi']);
  44947. }
  44948. foreach ($packagesinfo['pi'] as $packageinfo) {
  44949. if (empty($packageinfo)) {
  44950. continue;
  44951. }
  44952. $info = $packageinfo['p'];
  44953. $package = $info['n'];
  44954. $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false;
  44955. unset($latest);
  44956. unset($unstable);
  44957. unset($stable);
  44958. unset($state);
  44959. if ($releases) {
  44960. if (!isset($releases['r'][0])) {
  44961. $releases['r'] = array($releases['r']);
  44962. }
  44963. foreach ($releases['r'] as $release) {
  44964. if (!isset($latest)) {
  44965. if ($dostable && $release['s'] == 'stable') {
  44966. $latest = $release['v'];
  44967. $state = 'stable';
  44968. }
  44969. if (!$dostable) {
  44970. $latest = $release['v'];
  44971. $state = $release['s'];
  44972. }
  44973. }
  44974. if (!isset($stable) && $release['s'] == 'stable') {
  44975. $stable = $release['v'];
  44976. if (!isset($unstable)) {
  44977. $unstable = $stable;
  44978. }
  44979. }
  44980. if (!isset($unstable) && $release['s'] != 'stable') {
  44981. $unstable = $release['v'];
  44982. $state = $release['s'];
  44983. }
  44984. if (isset($latest) && !isset($state)) {
  44985. $state = $release['s'];
  44986. }
  44987. if (isset($latest) && isset($stable) && isset($unstable)) {
  44988. break;
  44989. }
  44990. }
  44991. }
  44992. if ($basic) { // remote-list command
  44993. if (!isset($latest)) {
  44994. $latest = false;
  44995. }
  44996. if ($dostable) {
  44997. // $state is not set if there are no releases
  44998. if (isset($state) && $state == 'stable') {
  44999. $ret[$package] = array('stable' => $latest);
  45000. } else {
  45001. $ret[$package] = array('stable' => '-n/a-');
  45002. }
  45003. } else {
  45004. $ret[$package] = array('stable' => $latest);
  45005. }
  45006. continue;
  45007. }
  45008. // list-all command
  45009. if (!isset($unstable)) {
  45010. $unstable = false;
  45011. $state = 'stable';
  45012. if (isset($stable)) {
  45013. $latest = $unstable = $stable;
  45014. }
  45015. } else {
  45016. $latest = $unstable;
  45017. }
  45018. if (!isset($latest)) {
  45019. $latest = false;
  45020. }
  45021. $deps = array();
  45022. if ($latest && isset($packageinfo['deps'])) {
  45023. if (!is_array($packageinfo['deps']) ||
  45024. !isset($packageinfo['deps'][0])
  45025. ) {
  45026. $packageinfo['deps'] = array($packageinfo['deps']);
  45027. }
  45028. $d = false;
  45029. foreach ($packageinfo['deps'] as $dep) {
  45030. if ($dep['v'] == $latest) {
  45031. $d = unserialize($dep['d']);
  45032. }
  45033. }
  45034. if ($d) {
  45035. if (isset($d['required'])) {
  45036. if (!class_exists('PEAR_PackageFile_v2')) {
  45037. require_once 'PEAR/PackageFile/v2.php';
  45038. }
  45039. if (!isset($pf)) {
  45040. $pf = new PEAR_PackageFile_v2;
  45041. }
  45042. $pf->setDeps($d);
  45043. $tdeps = $pf->getDeps();
  45044. } else {
  45045. $tdeps = $d;
  45046. }
  45047. foreach ($tdeps as $dep) {
  45048. if ($dep['type'] !== 'pkg') {
  45049. continue;
  45050. }
  45051. $deps[] = $dep;
  45052. }
  45053. }
  45054. }
  45055. $info = array(
  45056. 'stable' => $latest,
  45057. 'summary' => $info['s'],
  45058. 'description' => $info['d'],
  45059. 'deps' => $deps,
  45060. 'category' => $info['ca']['_content'],
  45061. 'unstable' => $unstable,
  45062. 'state' => $state
  45063. );
  45064. $ret[$package] = $info;
  45065. }
  45066. }
  45067. PEAR::popErrorHandling();
  45068. return $ret;
  45069. }
  45070. /**
  45071. * List all categories of a REST server
  45072. *
  45073. * @param string $base base URL of the server
  45074. * @return array of categorynames
  45075. */
  45076. function listCategories($base, $channel = false)
  45077. {
  45078. $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel);
  45079. if (PEAR::isError($categorylist)) {
  45080. return $categorylist;
  45081. }
  45082. if (!is_array($categorylist) || !isset($categorylist['c'])) {
  45083. return array();
  45084. }
  45085. if (isset($categorylist['c']['_content'])) {
  45086. // only 1 category
  45087. $categorylist['c'] = array($categorylist['c']);
  45088. }
  45089. return $categorylist['c'];
  45090. }
  45091. /**
  45092. * List packages in a category of a REST server
  45093. *
  45094. * @param string $base base URL of the server
  45095. * @param string $category name of the category
  45096. * @param boolean $info also download full package info
  45097. * @return array of packagenames
  45098. */
  45099. function listCategory($base, $category, $info = false, $channel = false)
  45100. {
  45101. if ($info == false) {
  45102. $url = '%s'.'c/%s/packages.xml';
  45103. } else {
  45104. $url = '%s'.'c/%s/packagesinfo.xml';
  45105. }
  45106. $url = sprintf($url,
  45107. $base,
  45108. urlencode($category));
  45109. // gives '404 Not Found' error when category doesn't exist
  45110. $packagelist = $this->_rest->retrieveData($url, false, false, $channel);
  45111. if (PEAR::isError($packagelist)) {
  45112. return $packagelist;
  45113. }
  45114. if (!is_array($packagelist)) {
  45115. return array();
  45116. }
  45117. if ($info == false) {
  45118. if (!isset($packagelist['p'])) {
  45119. return array();
  45120. }
  45121. if (!is_array($packagelist['p']) ||
  45122. !isset($packagelist['p'][0])) { // only 1 pkg
  45123. $packagelist = array($packagelist['p']);
  45124. } else {
  45125. $packagelist = $packagelist['p'];
  45126. }
  45127. return $packagelist;
  45128. }
  45129. // info == true
  45130. if (!isset($packagelist['pi'])) {
  45131. return array();
  45132. }
  45133. if (!is_array($packagelist['pi']) ||
  45134. !isset($packagelist['pi'][0])) { // only 1 pkg
  45135. $packagelist_pre = array($packagelist['pi']);
  45136. } else {
  45137. $packagelist_pre = $packagelist['pi'];
  45138. }
  45139. $packagelist = array();
  45140. foreach ($packagelist_pre as $i => $item) {
  45141. // compatibility with r/<latest.txt>.xml
  45142. if (isset($item['a']['r'][0])) {
  45143. // multiple releases
  45144. $item['p']['v'] = $item['a']['r'][0]['v'];
  45145. $item['p']['st'] = $item['a']['r'][0]['s'];
  45146. } elseif (isset($item['a'])) {
  45147. // first and only release
  45148. $item['p']['v'] = $item['a']['r']['v'];
  45149. $item['p']['st'] = $item['a']['r']['s'];
  45150. }
  45151. $packagelist[$i] = array('attribs' => $item['p']['r'],
  45152. '_content' => $item['p']['n'],
  45153. 'info' => $item['p']);
  45154. }
  45155. return $packagelist;
  45156. }
  45157. /**
  45158. * Return an array containing all of the states that are more stable than
  45159. * or equal to the passed in state
  45160. *
  45161. * @param string Release state
  45162. * @param boolean Determines whether to include $state in the list
  45163. * @return false|array False if $state is not a valid release state
  45164. */
  45165. function betterStates($state, $include = false)
  45166. {
  45167. static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  45168. $i = array_search($state, $states);
  45169. if ($i === false) {
  45170. return false;
  45171. }
  45172. if ($include) {
  45173. $i--;
  45174. }
  45175. return array_slice($states, $i + 1);
  45176. }
  45177. }
  45178. ?>
  45179. �����������������������PEAR-1.10.10/PEAR/REST/13.php�����������������������������������������������������������������������0000644�0001750�0001750�00000035427�13565304531�014531� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  45180. /**
  45181. * PEAR_REST_13
  45182. *
  45183. * PHP versions 4 and 5
  45184. *
  45185. * @category pear
  45186. * @package PEAR
  45187. * @author Greg Beaver <cellog@php.net>
  45188. * @copyright 1997-2009 The Authors
  45189. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45190. * @link http://pear.php.net/package/PEAR
  45191. * @since File available since Release 1.4.0a12
  45192. */
  45193. /**
  45194. * For downloading REST xml/txt files
  45195. */
  45196. require_once 'PEAR/REST.php';
  45197. require_once 'PEAR/REST/10.php';
  45198. /**
  45199. * Implement REST 1.3
  45200. *
  45201. * @category pear
  45202. * @package PEAR
  45203. * @author Greg Beaver <cellog@php.net>
  45204. * @copyright 1997-2009 The Authors
  45205. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45206. * @version Release: 1.10.10
  45207. * @link http://pear.php.net/package/PEAR
  45208. * @since Class available since Release 1.4.0a12
  45209. */
  45210. class PEAR_REST_13 extends PEAR_REST_10
  45211. {
  45212. /**
  45213. * Retrieve information about a remote package to be downloaded from a REST server
  45214. *
  45215. * This is smart enough to resolve the minimum PHP version dependency prior to download
  45216. * @param string $base The uri to prepend to all REST calls
  45217. * @param array $packageinfo an array of format:
  45218. * <pre>
  45219. * array(
  45220. * 'package' => 'packagename',
  45221. * 'channel' => 'channelname',
  45222. * ['state' => 'alpha' (or valid state),]
  45223. * -or-
  45224. * ['version' => '1.whatever']
  45225. * </pre>
  45226. * @param string $prefstate Current preferred_state config variable value
  45227. * @param bool $installed the installed version of this package to compare against
  45228. * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
  45229. */
  45230. function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
  45231. {
  45232. $states = $this->betterStates($prefstate, true);
  45233. if (!$states) {
  45234. return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  45235. }
  45236. $channel = $packageinfo['channel'];
  45237. $package = $packageinfo['package'];
  45238. $state = isset($packageinfo['state']) ? $packageinfo['state'] : null;
  45239. $version = isset($packageinfo['version']) ? $packageinfo['version'] : null;
  45240. $restFile = $base . 'r/' . strtolower($package) . '/allreleases2.xml';
  45241. $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  45242. if (PEAR::isError($info)) {
  45243. return PEAR::raiseError('No releases available for package "' .
  45244. $channel . '/' . $package . '"');
  45245. }
  45246. if (!isset($info['r'])) {
  45247. return false;
  45248. }
  45249. $release = $found = false;
  45250. if (!is_array($info['r']) || !isset($info['r'][0])) {
  45251. $info['r'] = array($info['r']);
  45252. }
  45253. $skippedphp = false;
  45254. foreach ($info['r'] as $release) {
  45255. if (!isset($this->_rest->_options['force']) && ($installed &&
  45256. version_compare($release['v'], $installed, '<'))) {
  45257. continue;
  45258. }
  45259. if (isset($state)) {
  45260. // try our preferred state first
  45261. if ($release['s'] == $state) {
  45262. if (!isset($version) && version_compare($release['m'], phpversion(), '>')) {
  45263. // skip releases that require a PHP version newer than our PHP version
  45264. $skippedphp = $release;
  45265. continue;
  45266. }
  45267. $found = true;
  45268. break;
  45269. }
  45270. // see if there is something newer and more stable
  45271. // bug #7221
  45272. if (in_array($release['s'], $this->betterStates($state), true)) {
  45273. if (!isset($version) && version_compare($release['m'], phpversion(), '>')) {
  45274. // skip releases that require a PHP version newer than our PHP version
  45275. $skippedphp = $release;
  45276. continue;
  45277. }
  45278. $found = true;
  45279. break;
  45280. }
  45281. } elseif (isset($version)) {
  45282. if ($release['v'] == $version) {
  45283. if (!isset($this->_rest->_options['force']) &&
  45284. !isset($version) &&
  45285. version_compare($release['m'], phpversion(), '>')) {
  45286. // skip releases that require a PHP version newer than our PHP version
  45287. $skippedphp = $release;
  45288. continue;
  45289. }
  45290. $found = true;
  45291. break;
  45292. }
  45293. } else {
  45294. if (in_array($release['s'], $states)) {
  45295. if (version_compare($release['m'], phpversion(), '>')) {
  45296. // skip releases that require a PHP version newer than our PHP version
  45297. $skippedphp = $release;
  45298. continue;
  45299. }
  45300. $found = true;
  45301. break;
  45302. }
  45303. }
  45304. }
  45305. if (!$found && $skippedphp) {
  45306. $found = null;
  45307. }
  45308. return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel);
  45309. }
  45310. function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
  45311. $prefstate = 'stable', $installed = false, $channel = false)
  45312. {
  45313. $states = $this->betterStates($prefstate, true);
  45314. if (!$states) {
  45315. return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  45316. }
  45317. $channel = $dependency['channel'];
  45318. $package = $dependency['name'];
  45319. $state = isset($dependency['state']) ? $dependency['state'] : null;
  45320. $version = isset($dependency['version']) ? $dependency['version'] : null;
  45321. $restFile = $base . 'r/' . strtolower($package) .'/allreleases2.xml';
  45322. $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  45323. if (PEAR::isError($info)) {
  45324. return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
  45325. . '" dependency "' . $channel . '/' . $package . '" has no releases');
  45326. }
  45327. if (!is_array($info) || !isset($info['r'])) {
  45328. return false;
  45329. }
  45330. $exclude = array();
  45331. $min = $max = $recommended = false;
  45332. if ($xsdversion == '1.0') {
  45333. $pinfo['package'] = $dependency['name'];
  45334. $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this
  45335. switch ($dependency['rel']) {
  45336. case 'ge' :
  45337. $min = $dependency['version'];
  45338. break;
  45339. case 'gt' :
  45340. $min = $dependency['version'];
  45341. $exclude = array($dependency['version']);
  45342. break;
  45343. case 'eq' :
  45344. $recommended = $dependency['version'];
  45345. break;
  45346. case 'lt' :
  45347. $max = $dependency['version'];
  45348. $exclude = array($dependency['version']);
  45349. break;
  45350. case 'le' :
  45351. $max = $dependency['version'];
  45352. break;
  45353. case 'ne' :
  45354. $exclude = array($dependency['version']);
  45355. break;
  45356. }
  45357. } else {
  45358. $pinfo['package'] = $dependency['name'];
  45359. $min = isset($dependency['min']) ? $dependency['min'] : false;
  45360. $max = isset($dependency['max']) ? $dependency['max'] : false;
  45361. $recommended = isset($dependency['recommended']) ?
  45362. $dependency['recommended'] : false;
  45363. if (isset($dependency['exclude'])) {
  45364. if (!isset($dependency['exclude'][0])) {
  45365. $exclude = array($dependency['exclude']);
  45366. }
  45367. }
  45368. }
  45369. $skippedphp = $found = $release = false;
  45370. if (!is_array($info['r']) || !isset($info['r'][0])) {
  45371. $info['r'] = array($info['r']);
  45372. }
  45373. foreach ($info['r'] as $release) {
  45374. if (!isset($this->_rest->_options['force']) && ($installed &&
  45375. version_compare($release['v'], $installed, '<'))) {
  45376. continue;
  45377. }
  45378. if (in_array($release['v'], $exclude)) { // skip excluded versions
  45379. continue;
  45380. }
  45381. // allow newer releases to say "I'm OK with the dependent package"
  45382. if ($xsdversion == '2.0' && isset($release['co'])) {
  45383. if (!is_array($release['co']) || !isset($release['co'][0])) {
  45384. $release['co'] = array($release['co']);
  45385. }
  45386. foreach ($release['co'] as $entry) {
  45387. if (isset($entry['x']) && !is_array($entry['x'])) {
  45388. $entry['x'] = array($entry['x']);
  45389. } elseif (!isset($entry['x'])) {
  45390. $entry['x'] = array();
  45391. }
  45392. if ($entry['c'] == $deppackage['channel'] &&
  45393. strtolower($entry['p']) == strtolower($deppackage['package']) &&
  45394. version_compare($deppackage['version'], $entry['min'], '>=') &&
  45395. version_compare($deppackage['version'], $entry['max'], '<=') &&
  45396. !in_array($release['v'], $entry['x'])) {
  45397. if (version_compare($release['m'], phpversion(), '>')) {
  45398. // skip dependency releases that require a PHP version
  45399. // newer than our PHP version
  45400. $skippedphp = $release;
  45401. continue;
  45402. }
  45403. $recommended = $release['v'];
  45404. break;
  45405. }
  45406. }
  45407. }
  45408. if ($recommended) {
  45409. if ($release['v'] != $recommended) { // if we want a specific
  45410. // version, then skip all others
  45411. continue;
  45412. }
  45413. if (!in_array($release['s'], $states)) {
  45414. // the stability is too low, but we must return the
  45415. // recommended version if possible
  45416. return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
  45417. }
  45418. }
  45419. if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
  45420. continue;
  45421. }
  45422. if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
  45423. continue;
  45424. }
  45425. if ($installed && version_compare($release['v'], $installed, '<')) {
  45426. continue;
  45427. }
  45428. if (in_array($release['s'], $states)) { // if in the preferred state...
  45429. if (version_compare($release['m'], phpversion(), '>')) {
  45430. // skip dependency releases that require a PHP version
  45431. // newer than our PHP version
  45432. $skippedphp = $release;
  45433. continue;
  45434. }
  45435. $found = true; // ... then use it
  45436. break;
  45437. }
  45438. }
  45439. if (!$found && $skippedphp) {
  45440. $found = null;
  45441. }
  45442. return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel);
  45443. }
  45444. /**
  45445. * List package upgrades but take the PHP version into account.
  45446. */
  45447. function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
  45448. {
  45449. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  45450. if (PEAR::isError($packagelist)) {
  45451. return $packagelist;
  45452. }
  45453. $ret = array();
  45454. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  45455. return $ret;
  45456. }
  45457. if (!is_array($packagelist['p'])) {
  45458. $packagelist['p'] = array($packagelist['p']);
  45459. }
  45460. foreach ($packagelist['p'] as $package) {
  45461. if (!isset($installed[strtolower($package)])) {
  45462. continue;
  45463. }
  45464. $inst_version = $reg->packageInfo($package, 'version', $channel);
  45465. $inst_state = $reg->packageInfo($package, 'release_state', $channel);
  45466. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  45467. $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  45468. '/allreleases2.xml', false, false, $channel);
  45469. PEAR::popErrorHandling();
  45470. if (PEAR::isError($info)) {
  45471. continue; // no remote releases
  45472. }
  45473. if (!isset($info['r'])) {
  45474. continue;
  45475. }
  45476. $release = $found = false;
  45477. if (!is_array($info['r']) || !isset($info['r'][0])) {
  45478. $info['r'] = array($info['r']);
  45479. }
  45480. // $info['r'] is sorted by version number
  45481. usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
  45482. foreach ($info['r'] as $release) {
  45483. if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
  45484. // not newer than the one installed
  45485. break;
  45486. }
  45487. if (version_compare($release['m'], phpversion(), '>')) {
  45488. // skip dependency releases that require a PHP version
  45489. // newer than our PHP version
  45490. continue;
  45491. }
  45492. // new version > installed version
  45493. if (!$pref_state) {
  45494. // every state is a good state
  45495. $found = true;
  45496. break;
  45497. } else {
  45498. $new_state = $release['s'];
  45499. // if new state >= installed state: go
  45500. if (in_array($new_state, $this->betterStates($inst_state, true))) {
  45501. $found = true;
  45502. break;
  45503. } else {
  45504. // only allow to lower the state of package,
  45505. // if new state >= preferred state: go
  45506. if (in_array($new_state, $this->betterStates($pref_state, true))) {
  45507. $found = true;
  45508. break;
  45509. }
  45510. }
  45511. }
  45512. }
  45513. if (!$found) {
  45514. continue;
  45515. }
  45516. $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
  45517. $release['v'] . '.xml', false, false, $channel);
  45518. if (PEAR::isError($relinfo)) {
  45519. return $relinfo;
  45520. }
  45521. $ret[$package] = array(
  45522. 'version' => $release['v'],
  45523. 'state' => $release['s'],
  45524. 'filesize' => $relinfo['f'],
  45525. );
  45526. }
  45527. return $ret;
  45528. }
  45529. }�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Postinstallscript/rw.php�����������������������������������������������������0000644�0001750�0001750�00000014034�13565304531�020613� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  45530. /**
  45531. * <tasks:postinstallscript> - read/write version
  45532. *
  45533. * PHP versions 4 and 5
  45534. *
  45535. * @category pear
  45536. * @package PEAR
  45537. * @author Greg Beaver <cellog@php.net>
  45538. * @copyright 1997-2009 The Authors
  45539. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45540. * @link http://pear.php.net/package/PEAR
  45541. * @since File available since Release 1.4.0a10
  45542. */
  45543. /**
  45544. * Base class
  45545. */
  45546. require_once 'PEAR/Task/Postinstallscript.php';
  45547. /**
  45548. * Abstracts the postinstallscript file task xml.
  45549. * @category pear
  45550. * @package PEAR
  45551. * @author Greg Beaver <cellog@php.net>
  45552. * @copyright 1997-2009 The Authors
  45553. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45554. * @version Release: 1.10.10
  45555. * @link http://pear.php.net/package/PEAR
  45556. * @since Class available since Release 1.4.0a10
  45557. */
  45558. class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript
  45559. {
  45560. /**
  45561. * parent package file object
  45562. *
  45563. * @var PEAR_PackageFile_v2_rw
  45564. */
  45565. public $_pkg;
  45566. /**
  45567. * Enter description here...
  45568. *
  45569. * @param PEAR_PackageFile_v2_rw $pkg Package
  45570. * @param PEAR_Config $config Config
  45571. * @param PEAR_Frontend $logger Logger
  45572. * @param array $fileXml XML
  45573. *
  45574. * @return PEAR_Task_Postinstallscript_rw
  45575. */
  45576. function __construct(&$pkg, &$config, &$logger, $fileXml)
  45577. {
  45578. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  45579. $this->_contents = $fileXml;
  45580. $this->_pkg = &$pkg;
  45581. $this->_params = array();
  45582. }
  45583. public function validate()
  45584. {
  45585. return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
  45586. }
  45587. public function getName()
  45588. {
  45589. return 'postinstallscript';
  45590. }
  45591. /**
  45592. * add a simple <paramgroup> to the post-install script
  45593. *
  45594. * Order is significant, so call this method in the same
  45595. * sequence the users should see the paramgroups. The $params
  45596. * parameter should either be the result of a call to {@link getParam()}
  45597. * or an array of calls to getParam().
  45598. *
  45599. * Use {@link addConditionTypeGroup()} to add a <paramgroup> containing
  45600. * a <conditiontype> tag
  45601. *
  45602. * @param string $id <paramgroup> id as seen by the script
  45603. * @param array|false $params array of getParam() calls, or false for no params
  45604. * @param string|false $instructions
  45605. */
  45606. public function addParamGroup($id, $params = false, $instructions = false)
  45607. {
  45608. if ($params && isset($params[0]) && !isset($params[1])) {
  45609. $params = $params[0];
  45610. }
  45611. $stuff =
  45612. array(
  45613. $this->_pkg->getTasksNs().':id' => $id,
  45614. );
  45615. if ($instructions) {
  45616. $stuff[$this->_pkg->getTasksNs().':instructions'] = $instructions;
  45617. }
  45618. if ($params) {
  45619. $stuff[$this->_pkg->getTasksNs().':param'] = $params;
  45620. }
  45621. $this->_params[$this->_pkg->getTasksNs().':paramgroup'][] = $stuff;
  45622. }
  45623. /**
  45624. * Add a complex <paramgroup> to the post-install script with conditions
  45625. *
  45626. * This inserts a <paramgroup> with
  45627. *
  45628. * Order is significant, so call this method in the same
  45629. * sequence the users should see the paramgroups. The $params
  45630. * parameter should either be the result of a call to {@link getParam()}
  45631. * or an array of calls to getParam().
  45632. *
  45633. * Use {@link addParamGroup()} to add a simple <paramgroup>
  45634. *
  45635. * @param string $id <paramgroup> id as seen by the script
  45636. * @param string $oldgroup <paramgroup> id of the section referenced by
  45637. * <conditiontype>
  45638. * @param string $param name of the <param> from the older section referenced
  45639. * by <contitiontype>
  45640. * @param string $value value to match of the parameter
  45641. * @param string $conditiontype one of '=', '!=', 'preg_match'
  45642. * @param array|false $params array of getParam() calls, or false for no params
  45643. * @param string|false $instructions
  45644. */
  45645. public function addConditionTypeGroup($id,
  45646. $oldgroup,
  45647. $param,
  45648. $value,
  45649. $conditiontype = '=',
  45650. $params = false,
  45651. $instructions = false
  45652. ) {
  45653. if ($params && isset($params[0]) && !isset($params[1])) {
  45654. $params = $params[0];
  45655. }
  45656. $stuff = array(
  45657. $this->_pkg->getTasksNs().':id' => $id,
  45658. );
  45659. if ($instructions) {
  45660. $stuff[$this->_pkg->getTasksNs().':instructions'] = $instructions;
  45661. }
  45662. $stuff[$this->_pkg->getTasksNs().':name'] = $oldgroup.'::'.$param;
  45663. $stuff[$this->_pkg->getTasksNs().':conditiontype'] = $conditiontype;
  45664. $stuff[$this->_pkg->getTasksNs().':value'] = $value;
  45665. if ($params) {
  45666. $stuff[$this->_pkg->getTasksNs().':param'] = $params;
  45667. }
  45668. $this->_params[$this->_pkg->getTasksNs().':paramgroup'][] = $stuff;
  45669. }
  45670. public function getXml()
  45671. {
  45672. return $this->_params;
  45673. }
  45674. /**
  45675. * Use to set up a param tag for use in creating a paramgroup
  45676. *
  45677. * @param mixed $name Name of parameter
  45678. * @param mixed $prompt Prompt
  45679. * @param string $type Type, defaults to 'string'
  45680. * @param mixed $default Default value
  45681. *
  45682. * @return array
  45683. */
  45684. public function getParam(
  45685. $name, $prompt, $type = 'string', $default = null
  45686. ) {
  45687. if ($default !== null) {
  45688. return
  45689. array(
  45690. $this->_pkg->getTasksNs().':name' => $name,
  45691. $this->_pkg->getTasksNs().':prompt' => $prompt,
  45692. $this->_pkg->getTasksNs().':type' => $type,
  45693. $this->_pkg->getTasksNs().':default' => $default,
  45694. );
  45695. }
  45696. return
  45697. array(
  45698. $this->_pkg->getTasksNs().':name' => $name,
  45699. $this->_pkg->getTasksNs().':prompt' => $prompt,
  45700. $this->_pkg->getTasksNs().':type' => $type,
  45701. );
  45702. }
  45703. }
  45704. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Replace/rw.php���������������������������������������������������������������0000644�0001750�0001750�00000003027�13565304531�016425� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  45705. /**
  45706. * <tasks:replace> - read/write version
  45707. *
  45708. * PHP versions 4 and 5
  45709. *
  45710. * @category pear
  45711. * @package PEAR
  45712. * @author Greg Beaver <cellog@php.net>
  45713. * @copyright 1997-2009 The Authors
  45714. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45715. * @link http://pear.php.net/package/PEAR
  45716. * @since File available since Release 1.4.0a10
  45717. */
  45718. /**
  45719. * Base class
  45720. */
  45721. require_once 'PEAR/Task/Replace.php';
  45722. /**
  45723. * Abstracts the replace task xml.
  45724. * @category pear
  45725. * @package PEAR
  45726. * @author Greg Beaver <cellog@php.net>
  45727. * @copyright 1997-2009 The Authors
  45728. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45729. * @version Release: 1.10.10
  45730. * @link http://pear.php.net/package/PEAR
  45731. * @since Class available since Release 1.4.0a10
  45732. */
  45733. class PEAR_Task_Replace_rw extends PEAR_Task_Replace
  45734. {
  45735. public function __construct(&$pkg, &$config, &$logger, $fileXml)
  45736. {
  45737. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  45738. $this->_contents = $fileXml;
  45739. $this->_pkg = &$pkg;
  45740. $this->_params = array();
  45741. }
  45742. public function validate()
  45743. {
  45744. return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
  45745. }
  45746. public function setInfo($from, $to, $type)
  45747. {
  45748. $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type));
  45749. }
  45750. public function getName()
  45751. {
  45752. return 'replace';
  45753. }
  45754. public function getXml()
  45755. {
  45756. return $this->_params;
  45757. }
  45758. }
  45759. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Unixeol/rw.php���������������������������������������������������������������0000644�0001750�0001750�00000002434�13565304531�016476� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  45760. /**
  45761. * <tasks:unixeol> - read/write version
  45762. *
  45763. * PHP versions 4 and 5
  45764. *
  45765. * @category pear
  45766. * @package PEAR
  45767. * @author Greg Beaver <cellog@php.net>
  45768. * @copyright 1997-2009 The Authors
  45769. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45770. * @link http://pear.php.net/package/PEAR
  45771. * @since File available since Release 1.4.0a10
  45772. */
  45773. /**
  45774. * Base class
  45775. */
  45776. require_once 'PEAR/Task/Unixeol.php';
  45777. /**
  45778. * Abstracts the unixeol task xml.
  45779. * @category pear
  45780. * @package PEAR
  45781. * @author Greg Beaver <cellog@php.net>
  45782. * @copyright 1997-2009 The Authors
  45783. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45784. * @version Release: 1.10.10
  45785. * @link http://pear.php.net/package/PEAR
  45786. * @since Class available since Release 1.4.0a10
  45787. */
  45788. class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol
  45789. {
  45790. function __construct(&$pkg, &$config, &$logger, $fileXml)
  45791. {
  45792. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  45793. $this->_contents = $fileXml;
  45794. $this->_pkg = &$pkg;
  45795. $this->_params = array();
  45796. }
  45797. public function validate()
  45798. {
  45799. return true;
  45800. }
  45801. public function getName()
  45802. {
  45803. return 'unixeol';
  45804. }
  45805. public function getXml()
  45806. {
  45807. return '';
  45808. }
  45809. }
  45810. ?>
  45811. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Windowseol/rw.php������������������������������������������������������������0000644�0001750�0001750�00000002451�13565304531�017204� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  45812. /**
  45813. * <tasks:windowseol> - read/write version
  45814. *
  45815. * PHP versions 4 and 5
  45816. *
  45817. * @category pear
  45818. * @package PEAR
  45819. * @author Greg Beaver <cellog@php.net>
  45820. * @copyright 1997-2009 The Authors
  45821. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45822. * @link http://pear.php.net/package/PEAR
  45823. * @since File available since Release 1.4.0a10
  45824. */
  45825. /**
  45826. * Base class
  45827. */
  45828. require_once 'PEAR/Task/Windowseol.php';
  45829. /**
  45830. * Abstracts the windowseol task xml.
  45831. *
  45832. * @category pear
  45833. * @package PEAR
  45834. * @author Greg Beaver <cellog@php.net>
  45835. * @copyright 1997-2009 The Authors
  45836. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45837. * @version Release: 1.10.10
  45838. * @link http://pear.php.net/package/PEAR
  45839. * @since Class available since Release 1.4.0a10
  45840. */
  45841. class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol
  45842. {
  45843. function __construct(&$pkg, &$config, &$logger, $fileXml)
  45844. {
  45845. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  45846. $this->_contents = $fileXml;
  45847. $this->_pkg = &$pkg;
  45848. $this->_params = array();
  45849. }
  45850. public function validate()
  45851. {
  45852. return true;
  45853. }
  45854. public function getName()
  45855. {
  45856. return 'windowseol';
  45857. }
  45858. public function getXml()
  45859. {
  45860. return '';
  45861. }
  45862. }
  45863. ?>
  45864. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Common.php�������������������������������������������������������������������0000644�0001750�0001750�00000014037�13565304531�015655� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  45865. /**
  45866. * PEAR_Task_Common, base class for installer tasks
  45867. *
  45868. * PHP versions 4 and 5
  45869. *
  45870. * @category pear
  45871. * @package PEAR
  45872. * @author Greg Beaver <cellog@php.net>
  45873. * @copyright 1997-2009 The Authors
  45874. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45875. * @link http://pear.php.net/package/PEAR
  45876. * @since File available since Release 1.4.0a1
  45877. */
  45878. /**#@+
  45879. * Error codes for task validation routines
  45880. */
  45881. define('PEAR_TASK_ERROR_NOATTRIBS', 1);
  45882. define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2);
  45883. define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3);
  45884. define('PEAR_TASK_ERROR_INVALID', 4);
  45885. /**#@-*/
  45886. define('PEAR_TASK_PACKAGE', 1);
  45887. define('PEAR_TASK_INSTALL', 2);
  45888. define('PEAR_TASK_PACKAGEANDINSTALL', 3);
  45889. /**
  45890. * A task is an operation that manipulates the contents of a file.
  45891. *
  45892. * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been
  45893. * processed and installed, and are designed to operate on all files containing the task.
  45894. * The Post-install script task simply takes advantage of the fact that it will be run
  45895. * after installation, replace is a simple task.
  45896. *
  45897. * Combining tasks is possible, but ordering is significant.
  45898. *
  45899. * <file name="test.php" role="php">
  45900. * <tasks:replace from="@data-dir@" to="data_dir" type="pear-config"/>
  45901. * <tasks:postinstallscript/>
  45902. * </file>
  45903. *
  45904. * This will first replace any instance of @data-dir@ in the test.php file
  45905. * with the path to the current data directory. Then, it will include the
  45906. * test.php file and run the script it contains to configure the package post-installation.
  45907. *
  45908. * @category pear
  45909. * @package PEAR
  45910. * @author Greg Beaver <cellog@php.net>
  45911. * @copyright 1997-2009 The Authors
  45912. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  45913. * @version Release: 1.10.10
  45914. * @link http://pear.php.net/package/PEAR
  45915. * @since Class available since Release 1.4.0a1
  45916. * @abstract
  45917. */
  45918. class PEAR_Task_Common
  45919. {
  45920. /**
  45921. * Valid types for this version are 'simple' and 'multiple'
  45922. *
  45923. * - simple tasks operate on the contents of a file and write out changes to disk
  45924. * - multiple tasks operate on the contents of many files and write out the
  45925. * changes directly to disk
  45926. *
  45927. * Child task classes must override this property.
  45928. *
  45929. * @access protected
  45930. */
  45931. protected $type = 'simple';
  45932. /**
  45933. * Determines which install phase this task is executed under
  45934. */
  45935. public $phase = PEAR_TASK_INSTALL;
  45936. /**
  45937. * @access protected
  45938. */
  45939. protected $config;
  45940. /**
  45941. * @access protected
  45942. */
  45943. protected $registry;
  45944. /**
  45945. * @access protected
  45946. */
  45947. public $logger;
  45948. /**
  45949. * @access protected
  45950. */
  45951. protected $installphase;
  45952. /**
  45953. * @param PEAR_Config
  45954. * @param PEAR_Common
  45955. */
  45956. function __construct(&$config, &$logger, $phase)
  45957. {
  45958. $this->config = &$config;
  45959. $this->registry = &$config->getRegistry();
  45960. $this->logger = &$logger;
  45961. $this->installphase = $phase;
  45962. if ($this->type == 'multiple') {
  45963. $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this;
  45964. }
  45965. }
  45966. /**
  45967. * Validate the basic contents of a task tag.
  45968. *
  45969. * @param PEAR_PackageFile_v2
  45970. * @param array
  45971. * @param PEAR_Config
  45972. * @param array the entire parsed <file> tag
  45973. *
  45974. * @return true|array On error, return an array in format:
  45975. * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...])
  45976. *
  45977. * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in
  45978. * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and
  45979. * an array of legal values in
  45980. *
  45981. * @abstract
  45982. */
  45983. public static function validateXml($pkg, $xml, $config, $fileXml)
  45984. {
  45985. }
  45986. /**
  45987. * Initialize a task instance with the parameters
  45988. *
  45989. * @param array raw, parsed xml
  45990. * @param array attributes from the <file> tag containing this task
  45991. * @param string|null last installed version of this package
  45992. * @abstract
  45993. */
  45994. public function init($xml, $fileAttributes, $lastVersion)
  45995. {
  45996. }
  45997. /**
  45998. * Begin a task processing session. All multiple tasks will be processed
  45999. * after each file has been successfully installed, all simple tasks should
  46000. * perform their task here and return any errors using the custom
  46001. * throwError() method to allow forward compatibility
  46002. *
  46003. * This method MUST NOT write out any changes to disk
  46004. *
  46005. * @param PEAR_PackageFile_v2
  46006. * @param string file contents
  46007. * @param string the eventual final file location (informational only)
  46008. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  46009. * (use $this->throwError), otherwise return the new contents
  46010. * @abstract
  46011. */
  46012. public function startSession($pkg, $contents, $dest)
  46013. {
  46014. }
  46015. /**
  46016. * This method is used to process each of the tasks for a particular
  46017. * multiple class type. Simple tasks need not implement this method.
  46018. *
  46019. * @param array an array of tasks
  46020. * @access protected
  46021. */
  46022. public static function run($tasks)
  46023. {
  46024. }
  46025. /**
  46026. * @final
  46027. */
  46028. public static function hasPostinstallTasks()
  46029. {
  46030. return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
  46031. }
  46032. /**
  46033. * @final
  46034. */
  46035. public static function runPostinstallTasks()
  46036. {
  46037. foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) {
  46038. $err = call_user_func(
  46039. array($class, 'run'),
  46040. $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]
  46041. );
  46042. if ($err) {
  46043. return PEAR_Task_Common::throwError($err);
  46044. }
  46045. }
  46046. unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
  46047. }
  46048. /**
  46049. * Determines whether a role is a script
  46050. * @return bool
  46051. */
  46052. public function isScript()
  46053. {
  46054. return $this->type == 'script';
  46055. }
  46056. public function throwError($msg, $code = -1)
  46057. {
  46058. include_once 'PEAR.php';
  46059. return PEAR::raiseError($msg, $code);
  46060. }
  46061. }
  46062. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Postinstallscript.php��������������������������������������������������������0000644�0001750�0001750�00000034570�13565304531�020172� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  46063. /**
  46064. * <tasks:postinstallscript>
  46065. *
  46066. * PHP versions 4 and 5
  46067. *
  46068. * @category pear
  46069. * @package PEAR
  46070. * @author Greg Beaver <cellog@php.net>
  46071. * @copyright 1997-2009 The Authors
  46072. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46073. * @link http://pear.php.net/package/PEAR
  46074. * @since File available since Release 1.4.0a1
  46075. */
  46076. /**
  46077. * Base class
  46078. */
  46079. require_once 'PEAR/Task/Common.php';
  46080. /**
  46081. * Implements the postinstallscript file task.
  46082. *
  46083. * Note that post-install scripts are handled separately from installation, by the
  46084. * "pear run-scripts" command
  46085. *
  46086. * @category pear
  46087. * @package PEAR
  46088. * @author Greg Beaver <cellog@php.net>
  46089. * @copyright 1997-2009 The Authors
  46090. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46091. * @version Release: 1.10.10
  46092. * @link http://pear.php.net/package/PEAR
  46093. * @since Class available since Release 1.4.0a1
  46094. */
  46095. class PEAR_Task_Postinstallscript extends PEAR_Task_Common
  46096. {
  46097. public $type = 'script';
  46098. public $_class;
  46099. public $_params;
  46100. public $_obj;
  46101. /**
  46102. *
  46103. * @var PEAR_PackageFile_v2
  46104. */
  46105. public $_pkg;
  46106. public $_contents;
  46107. public $phase = PEAR_TASK_INSTALL;
  46108. /**
  46109. * Validate the raw xml at parsing-time.
  46110. *
  46111. * This also attempts to validate the script to make sure it meets the criteria
  46112. * for a post-install script
  46113. *
  46114. * @param PEAR_PackageFile_v2
  46115. * @param array The XML contents of the <postinstallscript> tag
  46116. * @param PEAR_Config
  46117. * @param array the entire parsed <file> tag
  46118. */
  46119. public static function validateXml($pkg, $xml, $config, $fileXml)
  46120. {
  46121. if ($fileXml['role'] != 'php') {
  46122. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46123. $fileXml['name'].'" must be role="php"', );
  46124. }
  46125. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  46126. $file = $pkg->getFileContents($fileXml['name']);
  46127. if (PEAR::isError($file)) {
  46128. PEAR::popErrorHandling();
  46129. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46130. $fileXml['name'].'" is not valid: '.
  46131. $file->getMessage(), );
  46132. } elseif ($file === null) {
  46133. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46134. $fileXml['name'].'" could not be retrieved for processing!', );
  46135. } else {
  46136. $analysis = $pkg->analyzeSourceCode($file, true);
  46137. if (!$analysis) {
  46138. PEAR::popErrorHandling();
  46139. $warnings = '';
  46140. foreach ($pkg->getValidationWarnings() as $warn) {
  46141. $warnings .= $warn['message']."\n";
  46142. }
  46143. return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "'.
  46144. $fileXml['name'].'" failed: '.$warnings, );
  46145. }
  46146. if (count($analysis['declared_classes']) != 1) {
  46147. PEAR::popErrorHandling();
  46148. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46149. $fileXml['name'].'" must declare exactly 1 class', );
  46150. }
  46151. $class = $analysis['declared_classes'][0];
  46152. if ($class != str_replace(
  46153. array('/', '.php'), array('_', ''),
  46154. $fileXml['name']
  46155. ).'_postinstall') {
  46156. PEAR::popErrorHandling();
  46157. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46158. $fileXml['name'].'" class "'.$class.'" must be named "'.
  46159. str_replace(
  46160. array('/', '.php'), array('_', ''),
  46161. $fileXml['name']
  46162. ).'_postinstall"', );
  46163. }
  46164. if (!isset($analysis['declared_methods'][$class])) {
  46165. PEAR::popErrorHandling();
  46166. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46167. $fileXml['name'].'" must declare methods init() and run()', );
  46168. }
  46169. $methods = array('init' => 0, 'run' => 1);
  46170. foreach ($analysis['declared_methods'][$class] as $method) {
  46171. if (isset($methods[$method])) {
  46172. unset($methods[$method]);
  46173. }
  46174. }
  46175. if (count($methods)) {
  46176. PEAR::popErrorHandling();
  46177. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46178. $fileXml['name'].'" must declare methods init() and run()', );
  46179. }
  46180. }
  46181. PEAR::popErrorHandling();
  46182. $definedparams = array();
  46183. $tasksNamespace = $pkg->getTasksNs().':';
  46184. if (!isset($xml[$tasksNamespace.'paramgroup']) && isset($xml['paramgroup'])) {
  46185. // in order to support the older betas, which did not expect internal tags
  46186. // to also use the namespace
  46187. $tasksNamespace = '';
  46188. }
  46189. if (isset($xml[$tasksNamespace.'paramgroup'])) {
  46190. $params = $xml[$tasksNamespace.'paramgroup'];
  46191. if (!is_array($params) || !isset($params[0])) {
  46192. $params = array($params);
  46193. }
  46194. foreach ($params as $param) {
  46195. if (!isset($param[$tasksNamespace.'id'])) {
  46196. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46197. $fileXml['name'].'" <paramgroup> must have '.
  46198. 'an '.$tasksNamespace.'id> tag', );
  46199. }
  46200. if (isset($param[$tasksNamespace.'name'])) {
  46201. if (!in_array($param[$tasksNamespace.'name'], $definedparams)) {
  46202. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46203. $fileXml['name'].'" '.$tasksNamespace.
  46204. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  46205. '" parameter "'.$param[$tasksNamespace.'name'].
  46206. '" has not been previously defined', );
  46207. }
  46208. if (!isset($param[$tasksNamespace.'conditiontype'])) {
  46209. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46210. $fileXml['name'].'" '.$tasksNamespace.
  46211. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  46212. '" must have a '.$tasksNamespace.
  46213. 'conditiontype> tag containing either "=", '.
  46214. '"!=", or "preg_match"', );
  46215. }
  46216. if (!in_array(
  46217. $param[$tasksNamespace.'conditiontype'],
  46218. array('=', '!=', 'preg_match')
  46219. )) {
  46220. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46221. $fileXml['name'].'" '.$tasksNamespace.
  46222. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  46223. '" must have a '.$tasksNamespace.
  46224. 'conditiontype> tag containing either "=", '.
  46225. '"!=", or "preg_match"', );
  46226. }
  46227. if (!isset($param[$tasksNamespace.'value'])) {
  46228. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46229. $fileXml['name'].'" '.$tasksNamespace.
  46230. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  46231. '" must have a '.$tasksNamespace.
  46232. 'value> tag containing expected parameter value', );
  46233. }
  46234. }
  46235. if (isset($param[$tasksNamespace.'instructions'])) {
  46236. if (!is_string($param[$tasksNamespace.'instructions'])) {
  46237. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46238. $fileXml['name'].'" '.$tasksNamespace.
  46239. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  46240. '" '.$tasksNamespace.'instructions> must be simple text', );
  46241. }
  46242. }
  46243. if (!isset($param[$tasksNamespace.'param'])) {
  46244. continue; // <param> is no longer required
  46245. }
  46246. $subparams = $param[$tasksNamespace.'param'];
  46247. if (!is_array($subparams) || !isset($subparams[0])) {
  46248. $subparams = array($subparams);
  46249. }
  46250. foreach ($subparams as $subparam) {
  46251. if (!isset($subparam[$tasksNamespace.'name'])) {
  46252. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46253. $fileXml['name'].'" parameter for '.
  46254. $tasksNamespace.'paramgroup> id "'.
  46255. $param[$tasksNamespace.'id'].'" must have '.
  46256. 'a '.$tasksNamespace.'name> tag', );
  46257. }
  46258. if (!preg_match(
  46259. '/[a-zA-Z0-9]+/',
  46260. $subparam[$tasksNamespace.'name']
  46261. )) {
  46262. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46263. $fileXml['name'].'" parameter "'.
  46264. $subparam[$tasksNamespace.'name'].
  46265. '" for '.$tasksNamespace.'paramgroup> id "'.
  46266. $param[$tasksNamespace.'id'].
  46267. '" is not a valid name. Must contain only alphanumeric characters', );
  46268. }
  46269. if (!isset($subparam[$tasksNamespace.'prompt'])) {
  46270. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46271. $fileXml['name'].'" parameter "'.
  46272. $subparam[$tasksNamespace.'name'].
  46273. '" for '.$tasksNamespace.'paramgroup> id "'.
  46274. $param[$tasksNamespace.'id'].
  46275. '" must have a '.$tasksNamespace.'prompt> tag', );
  46276. }
  46277. if (!isset($subparam[$tasksNamespace.'type'])) {
  46278. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  46279. $fileXml['name'].'" parameter "'.
  46280. $subparam[$tasksNamespace.'name'].
  46281. '" for '.$tasksNamespace.'paramgroup> id "'.
  46282. $param[$tasksNamespace.'id'].
  46283. '" must have a '.$tasksNamespace.'type> tag', );
  46284. }
  46285. $definedparams[] = $param[$tasksNamespace.'id'].'::'.
  46286. $subparam[$tasksNamespace.'name'];
  46287. }
  46288. }
  46289. }
  46290. return true;
  46291. }
  46292. /**
  46293. * Initialize a task instance with the parameters
  46294. * @param array $xml raw, parsed xml
  46295. * @param array $fileattribs attributes from the <file> tag containing
  46296. * this task
  46297. * @param string|null $lastversion last installed version of this package,
  46298. * if any (useful for upgrades)
  46299. */
  46300. public function init($xml, $fileattribs, $lastversion)
  46301. {
  46302. $this->_class = str_replace('/', '_', $fileattribs['name']);
  46303. $this->_filename = $fileattribs['name'];
  46304. $this->_class = str_replace('.php', '', $this->_class).'_postinstall';
  46305. $this->_params = $xml;
  46306. $this->_lastversion = $lastversion;
  46307. }
  46308. /**
  46309. * Strip the tasks: namespace from internal params
  46310. *
  46311. * @access private
  46312. */
  46313. public function _stripNamespace($params = null)
  46314. {
  46315. if ($params === null) {
  46316. $params = array();
  46317. if (!is_array($this->_params)) {
  46318. return;
  46319. }
  46320. foreach ($this->_params as $i => $param) {
  46321. if (is_array($param)) {
  46322. $param = $this->_stripNamespace($param);
  46323. }
  46324. $params[str_replace($this->_pkg->getTasksNs().':', '', $i)] = $param;
  46325. }
  46326. $this->_params = $params;
  46327. } else {
  46328. $newparams = array();
  46329. foreach ($params as $i => $param) {
  46330. if (is_array($param)) {
  46331. $param = $this->_stripNamespace($param);
  46332. }
  46333. $newparams[str_replace($this->_pkg->getTasksNs().':', '', $i)] = $param;
  46334. }
  46335. return $newparams;
  46336. }
  46337. }
  46338. /**
  46339. * Unlike other tasks, the installed file name is passed in instead of the
  46340. * file contents, because this task is handled post-installation
  46341. *
  46342. * @param mixed $pkg PEAR_PackageFile_v1|PEAR_PackageFile_v2
  46343. * @param string $contents file name
  46344. * @param string $dest the eventual final file location (informational only)
  46345. *
  46346. * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail
  46347. * (use $this->throwError)
  46348. */
  46349. public function startSession($pkg, $contents, $dest)
  46350. {
  46351. if ($this->installphase != PEAR_TASK_INSTALL) {
  46352. return false;
  46353. }
  46354. // remove the tasks: namespace if present
  46355. $this->_pkg = $pkg;
  46356. $this->_stripNamespace();
  46357. $this->logger->log(
  46358. 0, 'Including external post-installation script "'.
  46359. $contents.'" - any errors are in this script'
  46360. );
  46361. include_once $contents;
  46362. if (class_exists($this->_class)) {
  46363. $this->logger->log(0, 'Inclusion succeeded');
  46364. } else {
  46365. return $this->throwError(
  46366. 'init of post-install script class "'.$this->_class
  46367. .'" failed'
  46368. );
  46369. }
  46370. $this->_obj = new $this->_class();
  46371. $this->logger->log(1, 'running post-install script "'.$this->_class.'->init()"');
  46372. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  46373. $res = $this->_obj->init($this->config, $pkg, $this->_lastversion);
  46374. PEAR::popErrorHandling();
  46375. if ($res) {
  46376. $this->logger->log(0, 'init succeeded');
  46377. } else {
  46378. return $this->throwError(
  46379. 'init of post-install script "'.$this->_class.
  46380. '->init()" failed'
  46381. );
  46382. }
  46383. $this->_contents = $contents;
  46384. return true;
  46385. }
  46386. /**
  46387. * No longer used
  46388. *
  46389. * @see PEAR_PackageFile_v2::runPostinstallScripts()
  46390. * @param array an array of tasks
  46391. * @param string install or upgrade
  46392. * @access protected
  46393. */
  46394. public static function run($tasks)
  46395. {
  46396. }
  46397. }
  46398. ����������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Replace.php������������������������������������������������������������������0000644�0001750�0001750�00000015371�13565304531�016002� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  46399. /**
  46400. * <tasks:replace>
  46401. *
  46402. * PHP versions 4 and 5
  46403. *
  46404. * @category pear
  46405. * @package PEAR
  46406. * @author Greg Beaver <cellog@php.net>
  46407. * @copyright 1997-2009 The Authors
  46408. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46409. * @link http://pear.php.net/package/PEAR
  46410. * @since File available since Release 1.4.0a1
  46411. */
  46412. /**
  46413. * Base class
  46414. */
  46415. require_once 'PEAR/Task/Common.php';
  46416. /**
  46417. * Implements the replace file task.
  46418. * @category pear
  46419. * @package PEAR
  46420. * @author Greg Beaver <cellog@php.net>
  46421. * @copyright 1997-2009 The Authors
  46422. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46423. * @version Release: 1.10.10
  46424. * @link http://pear.php.net/package/PEAR
  46425. * @since Class available since Release 1.4.0a1
  46426. */
  46427. class PEAR_Task_Replace extends PEAR_Task_Common
  46428. {
  46429. public $type = 'simple';
  46430. public $phase = PEAR_TASK_PACKAGEANDINSTALL;
  46431. public $_replacements;
  46432. /**
  46433. * Validate the raw xml at parsing-time.
  46434. *
  46435. * @param PEAR_PackageFile_v2
  46436. * @param array raw, parsed xml
  46437. * @param PEAR_Config
  46438. */
  46439. public static function validateXml($pkg, $xml, $config, $fileXml)
  46440. {
  46441. if (!isset($xml['attribs'])) {
  46442. return array(PEAR_TASK_ERROR_NOATTRIBS);
  46443. }
  46444. if (!isset($xml['attribs']['type'])) {
  46445. return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type');
  46446. }
  46447. if (!isset($xml['attribs']['to'])) {
  46448. return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to');
  46449. }
  46450. if (!isset($xml['attribs']['from'])) {
  46451. return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from');
  46452. }
  46453. if ($xml['attribs']['type'] == 'pear-config') {
  46454. if (!in_array($xml['attribs']['to'], $config->getKeys())) {
  46455. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
  46456. $config->getKeys(), );
  46457. }
  46458. } elseif ($xml['attribs']['type'] == 'php-const') {
  46459. if (defined($xml['attribs']['to'])) {
  46460. return true;
  46461. } else {
  46462. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
  46463. array('valid PHP constant'), );
  46464. }
  46465. } elseif ($xml['attribs']['type'] == 'package-info') {
  46466. if (in_array(
  46467. $xml['attribs']['to'],
  46468. array('name', 'summary', 'channel', 'notes', 'extends', 'description',
  46469. 'release_notes', 'license', 'release-license', 'license-uri',
  46470. 'version', 'api-version', 'state', 'api-state', 'release_date',
  46471. 'date', 'time', )
  46472. )) {
  46473. return true;
  46474. } else {
  46475. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
  46476. array('name', 'summary', 'channel', 'notes', 'extends', 'description',
  46477. 'release_notes', 'license', 'release-license', 'license-uri',
  46478. 'version', 'api-version', 'state', 'api-state', 'release_date',
  46479. 'date', 'time', ), );
  46480. }
  46481. } else {
  46482. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'],
  46483. array('pear-config', 'package-info', 'php-const'), );
  46484. }
  46485. return true;
  46486. }
  46487. /**
  46488. * Initialize a task instance with the parameters
  46489. * @param array raw, parsed xml
  46490. * @param unused
  46491. * @param unused
  46492. */
  46493. public function init($xml, $attribs, $lastVersion = null)
  46494. {
  46495. $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml;
  46496. }
  46497. /**
  46498. * Do a package.xml 1.0 replacement, with additional package-info fields available
  46499. *
  46500. * See validateXml() source for the complete list of allowed fields
  46501. *
  46502. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  46503. * @param string file contents
  46504. * @param string the eventual final file location (informational only)
  46505. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  46506. * (use $this->throwError), otherwise return the new contents
  46507. */
  46508. public function startSession($pkg, $contents, $dest)
  46509. {
  46510. $subst_from = $subst_to = array();
  46511. foreach ($this->_replacements as $a) {
  46512. $a = $a['attribs'];
  46513. $to = '';
  46514. if ($a['type'] == 'pear-config') {
  46515. if ($this->installphase == PEAR_TASK_PACKAGE) {
  46516. return false;
  46517. }
  46518. if ($a['to'] == 'master_server') {
  46519. $chan = $this->registry->getChannel($pkg->getChannel());
  46520. if (!PEAR::isError($chan)) {
  46521. $to = $chan->getServer();
  46522. } else {
  46523. $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
  46524. return false;
  46525. }
  46526. } else {
  46527. if ($this->config->isDefinedLayer('ftp')) {
  46528. // try the remote config file first
  46529. $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel());
  46530. if (is_null($to)) {
  46531. // then default to local
  46532. $to = $this->config->get($a['to'], null, $pkg->getChannel());
  46533. }
  46534. } else {
  46535. $to = $this->config->get($a['to'], null, $pkg->getChannel());
  46536. }
  46537. }
  46538. if (is_null($to)) {
  46539. $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
  46540. return false;
  46541. }
  46542. } elseif ($a['type'] == 'php-const') {
  46543. if ($this->installphase == PEAR_TASK_PACKAGE) {
  46544. return false;
  46545. }
  46546. if (defined($a['to'])) {
  46547. $to = constant($a['to']);
  46548. } else {
  46549. $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]");
  46550. return false;
  46551. }
  46552. } else {
  46553. if ($t = $pkg->packageInfo($a['to'])) {
  46554. $to = $t;
  46555. } else {
  46556. $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]");
  46557. return false;
  46558. }
  46559. }
  46560. if (!is_null($to)) {
  46561. $subst_from[] = $a['from'];
  46562. $subst_to[] = $to;
  46563. }
  46564. }
  46565. $this->logger->log(
  46566. 3, "doing ".sizeof($subst_from).
  46567. " substitution(s) for $dest"
  46568. );
  46569. if (sizeof($subst_from)) {
  46570. $contents = str_replace($subst_from, $subst_to, $contents);
  46571. }
  46572. return $contents;
  46573. }
  46574. }
  46575. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Unixeol.php������������������������������������������������������������������0000644�0001750�0001750�00000004377�13565304531�016056� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  46576. /**
  46577. * <tasks:unixeol>
  46578. *
  46579. * PHP versions 4 and 5
  46580. *
  46581. * @category pear
  46582. * @package PEAR
  46583. * @author Greg Beaver <cellog@php.net>
  46584. * @copyright 1997-2009 The Authors
  46585. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46586. * @link http://pear.php.net/package/PEAR
  46587. * @since File available since Release 1.4.0a1
  46588. */
  46589. /**
  46590. * Base class
  46591. */
  46592. require_once 'PEAR/Task/Common.php';
  46593. /**
  46594. * Implements the unix line endings file task.
  46595. * @category pear
  46596. * @package PEAR
  46597. * @author Greg Beaver <cellog@php.net>
  46598. * @copyright 1997-2009 The Authors
  46599. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46600. * @version Release: 1.10.10
  46601. * @link http://pear.php.net/package/PEAR
  46602. * @since Class available since Release 1.4.0a1
  46603. */
  46604. class PEAR_Task_Unixeol extends PEAR_Task_Common
  46605. {
  46606. public $type = 'simple';
  46607. public $phase = PEAR_TASK_PACKAGE;
  46608. public $_replacements;
  46609. /**
  46610. * Validate the raw xml at parsing-time.
  46611. *
  46612. * @param PEAR_PackageFile_v2
  46613. * @param array raw, parsed xml
  46614. * @param PEAR_Config
  46615. */
  46616. public static function validateXml($pkg, $xml, $config, $fileXml)
  46617. {
  46618. if ($xml != '') {
  46619. return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
  46620. }
  46621. return true;
  46622. }
  46623. /**
  46624. * Initialize a task instance with the parameters
  46625. * @param array raw, parsed xml
  46626. * @param unused
  46627. * @param unused
  46628. */
  46629. public function init($xml, $attribs, $lastVersion = null)
  46630. {
  46631. }
  46632. /**
  46633. * Replace all line endings with line endings customized for the current OS
  46634. *
  46635. * See validateXml() source for the complete list of allowed fields
  46636. *
  46637. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  46638. * @param string file contents
  46639. * @param string the eventual final file location (informational only)
  46640. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  46641. * (use $this->throwError), otherwise return the new contents
  46642. */
  46643. public function startSession($pkg, $contents, $dest)
  46644. {
  46645. $this->logger->log(3, "replacing all line endings with \\n in $dest");
  46646. return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents);
  46647. }
  46648. }
  46649. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Task/Windowseol.php���������������������������������������������������������������0000644�0001750�0001750�00000004363�13565304531�016560� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  46650. /**
  46651. * <tasks:windowseol>
  46652. *
  46653. * PHP versions 4 and 5
  46654. *
  46655. * @category pear
  46656. * @package PEAR
  46657. * @author Greg Beaver <cellog@php.net>
  46658. * @copyright 1997-2009 The Authors
  46659. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46660. * @link http://pear.php.net/package/PEAR
  46661. * @since File available since Release 1.4.0a1
  46662. */
  46663. /**
  46664. * Base class
  46665. */
  46666. require_once 'PEAR/Task/Common.php';
  46667. /**
  46668. * Implements the windows line endsings file task.
  46669. *
  46670. * @category pear
  46671. * @package PEAR
  46672. * @author Greg Beaver <cellog@php.net>
  46673. * @copyright 1997-2009 The Authors
  46674. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46675. * @version Release: 1.10.10
  46676. * @link http://pear.php.net/package/PEAR
  46677. * @since Class available since Release 1.4.0a1
  46678. */
  46679. class PEAR_Task_Windowseol extends PEAR_Task_Common
  46680. {
  46681. public $type = 'simple';
  46682. public $phase = PEAR_TASK_PACKAGE;
  46683. public $_replacements;
  46684. /**
  46685. * Validate the raw xml at parsing-time.
  46686. *
  46687. * @param PEAR_PackageFile_v2
  46688. * @param array raw, parsed xml
  46689. * @param PEAR_Config
  46690. */
  46691. public static function validateXml($pkg, $xml, $config, $fileXml)
  46692. {
  46693. if ($xml != '') {
  46694. return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
  46695. }
  46696. return true;
  46697. }
  46698. /**
  46699. * Initialize a task instance with the parameters
  46700. * @param array raw, parsed xml
  46701. * @param unused
  46702. * @param unused
  46703. */
  46704. public function init($xml, $attribs, $lastVersion = null)
  46705. {
  46706. }
  46707. /**
  46708. * Replace all line endings with windows line endings
  46709. *
  46710. * See validateXml() source for the complete list of allowed fields
  46711. *
  46712. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  46713. * @param string file contents
  46714. * @param string the eventual final file location (informational only)
  46715. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  46716. * (use $this->throwError), otherwise return the new contents
  46717. */
  46718. public function startSession($pkg, $contents, $dest)
  46719. {
  46720. $this->logger->log(3, "replacing all line endings with \\r\\n in $dest");
  46721. return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents);
  46722. }
  46723. }
  46724. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Validator/PECL.php����������������������������������������������������������������0000644�0001750�0001750�00000004071�13565304531�016170� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  46725. /**
  46726. * Channel Validator for the pecl.php.net channel
  46727. *
  46728. * PHP 4 and PHP 5
  46729. *
  46730. * @category pear
  46731. * @package PEAR
  46732. * @author Greg Beaver <cellog@php.net>
  46733. * @copyright 1997-2006 The PHP Group
  46734. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46735. * @link http://pear.php.net/package/PEAR
  46736. * @since File available since Release 1.4.0a5
  46737. */
  46738. /**
  46739. * This is the parent class for all validators
  46740. */
  46741. require_once 'PEAR/Validate.php';
  46742. /**
  46743. * Channel Validator for the pecl.php.net channel
  46744. * @category pear
  46745. * @package PEAR
  46746. * @author Greg Beaver <cellog@php.net>
  46747. * @copyright 1997-2009 The Authors
  46748. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46749. * @version Release: 1.10.10
  46750. * @link http://pear.php.net/package/PEAR
  46751. * @since Class available since Release 1.4.0a5
  46752. */
  46753. class PEAR_Validator_PECL extends PEAR_Validate
  46754. {
  46755. function validateVersion()
  46756. {
  46757. if ($this->_state == PEAR_VALIDATE_PACKAGING) {
  46758. $version = $this->_packagexml->getVersion();
  46759. $versioncomponents = explode('.', $version);
  46760. $last = array_pop($versioncomponents);
  46761. if (substr($last, 1, 2) == 'rc') {
  46762. $this->_addFailure('version', 'Release Candidate versions must have ' .
  46763. 'upper-case RC, not lower-case rc');
  46764. return false;
  46765. }
  46766. }
  46767. return true;
  46768. }
  46769. function validatePackageName()
  46770. {
  46771. $ret = parent::validatePackageName();
  46772. if ($this->_packagexml->getPackageType() == 'extsrc' ||
  46773. $this->_packagexml->getPackageType() == 'zendextsrc') {
  46774. if (strtolower($this->_packagexml->getPackage()) !=
  46775. strtolower($this->_packagexml->getProvidesExtension())) {
  46776. $this->_addWarning('providesextension', 'package name "' .
  46777. $this->_packagexml->getPackage() . '" is different from extension name "' .
  46778. $this->_packagexml->getProvidesExtension() . '"');
  46779. }
  46780. }
  46781. return $ret;
  46782. }
  46783. }
  46784. ?>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Builder.php�����������������������������������������������������������������������0000644�0001750�0001750�00000044766�13565304531�015125� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  46785. /**
  46786. * PEAR_Builder for building PHP extensions (PECL packages)
  46787. *
  46788. * PHP versions 4 and 5
  46789. *
  46790. * @category pear
  46791. * @package PEAR
  46792. * @author Stig Bakken <ssb@php.net>
  46793. * @author Greg Beaver <cellog@php.net>
  46794. * @copyright 1997-2009 The Authors
  46795. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46796. * @link http://pear.php.net/package/PEAR
  46797. * @since File available since Release 0.1
  46798. *
  46799. * TODO: log output parameters in PECL command line
  46800. * TODO: msdev path in configuration
  46801. */
  46802. /**
  46803. * Needed for extending PEAR_Builder
  46804. */
  46805. require_once 'PEAR/Common.php';
  46806. require_once 'PEAR/PackageFile.php';
  46807. require_once 'System.php';
  46808. /**
  46809. * Class to handle building (compiling) extensions.
  46810. *
  46811. * @category pear
  46812. * @package PEAR
  46813. * @author Stig Bakken <ssb@php.net>
  46814. * @author Greg Beaver <cellog@php.net>
  46815. * @copyright 1997-2009 The Authors
  46816. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  46817. * @version Release: 1.10.10
  46818. * @link http://pear.php.net/package/PEAR
  46819. * @since Class available since PHP 4.0.2
  46820. * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php
  46821. */
  46822. class PEAR_Builder extends PEAR_Common
  46823. {
  46824. var $php_api_version = 0;
  46825. var $zend_module_api_no = 0;
  46826. var $zend_extension_api_no = 0;
  46827. var $extensions_built = array();
  46828. /**
  46829. * @var string Used for reporting when it is not possible to pass function
  46830. * via extra parameter, e.g. log, msdevCallback
  46831. */
  46832. var $current_callback = null;
  46833. // used for msdev builds
  46834. var $_lastline = null;
  46835. var $_firstline = null;
  46836. /**
  46837. * Parsed --configureoptions.
  46838. *
  46839. * @var mixed[]
  46840. */
  46841. var $_parsed_configure_options;
  46842. /**
  46843. * PEAR_Builder constructor.
  46844. *
  46845. * @param mixed[] $configureoptions
  46846. * @param object $ui user interface object (instance of PEAR_Frontend_*)
  46847. *
  46848. * @access public
  46849. */
  46850. function __construct($configureoptions, &$ui)
  46851. {
  46852. parent::__construct();
  46853. $this->setFrontendObject($ui);
  46854. $this->_parseConfigureOptions($configureoptions);
  46855. }
  46856. /**
  46857. * Parse --configureoptions string.
  46858. *
  46859. * @param string Options, in the form "X=1 Y=2 Z='there\'s always one'"
  46860. */
  46861. function _parseConfigureOptions($options)
  46862. {
  46863. $data = '<XML><PROPERTIES ' . $options . ' /></XML>';
  46864. $parser = xml_parser_create('ISO-8859-1');
  46865. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  46866. xml_set_element_handler(
  46867. $parser, array($this, '_parseConfigureOptionsStartElement'),
  46868. array($this, '_parseConfigureOptionsEndElement'));
  46869. xml_parse($parser, $data, true);
  46870. xml_parser_free($parser);
  46871. }
  46872. /**
  46873. * Handle element start.
  46874. *
  46875. * @see PEAR_Builder::_parseConfigureOptions()
  46876. *
  46877. * @param resource $parser
  46878. * @param string $tagName
  46879. * @param mixed[] $attribs
  46880. */
  46881. function _parseConfigureOptionsStartElement($parser, $tagName, $attribs)
  46882. {
  46883. if ($tagName !== 'PROPERTIES') {
  46884. return;
  46885. }
  46886. $this->_parsed_configure_options = $attribs;
  46887. }
  46888. /**
  46889. * Handle element end.
  46890. *
  46891. * @see PEAR_Builder::_parseConfigureOptions()
  46892. *
  46893. * @param resource
  46894. * @param string $element
  46895. */
  46896. function _parseConfigureOptionsEndElement($parser, $element)
  46897. {
  46898. }
  46899. /**
  46900. * Build an extension from source on windows.
  46901. * requires msdev
  46902. */
  46903. function _build_win32($descfile, $callback = null)
  46904. {
  46905. if (is_object($descfile)) {
  46906. $pkg = $descfile;
  46907. $descfile = $pkg->getPackageFile();
  46908. } else {
  46909. $pf = new PEAR_PackageFile($this->config, $this->debug);
  46910. $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
  46911. if (PEAR::isError($pkg)) {
  46912. return $pkg;
  46913. }
  46914. }
  46915. $dir = dirname($descfile);
  46916. $old_cwd = getcwd();
  46917. if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
  46918. return $this->raiseError("could not chdir to $dir");
  46919. }
  46920. // packages that were in a .tar have the packagefile in this directory
  46921. $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
  46922. if (file_exists($dir) && is_dir($vdir)) {
  46923. if (!chdir($vdir)) {
  46924. return $this->raiseError("could not chdir to " . realpath($vdir));
  46925. }
  46926. $dir = getcwd();
  46927. }
  46928. $this->log(2, "building in $dir");
  46929. $dsp = $pkg->getPackage().'.dsp';
  46930. if (!file_exists("$dir/$dsp")) {
  46931. return $this->raiseError("The DSP $dsp does not exist.");
  46932. }
  46933. // XXX TODO: make release build type configurable
  46934. $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"';
  46935. $err = $this->_runCommand($command, array(&$this, 'msdevCallback'));
  46936. if (PEAR::isError($err)) {
  46937. return $err;
  46938. }
  46939. // figure out the build platform and type
  46940. $platform = 'Win32';
  46941. $buildtype = 'Release';
  46942. if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) {
  46943. $platform = $matches[1];
  46944. $buildtype = $matches[2];
  46945. }
  46946. if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/', $this->_lastline, $matches)) {
  46947. if ($matches[2]) {
  46948. // there were errors in the build
  46949. return $this->raiseError("There were errors during compilation.");
  46950. }
  46951. $out = $matches[1];
  46952. } else {
  46953. return $this->raiseError("Did not understand the completion status returned from msdev.exe.");
  46954. }
  46955. // msdev doesn't tell us the output directory :/
  46956. // open the dsp, find /out and use that directory
  46957. $dsptext = join(file($dsp),'');
  46958. // this regex depends on the build platform and type having been
  46959. // correctly identified above.
  46960. $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'.
  46961. $pkg->getPackage().'\s-\s'.
  46962. $platform.'\s'.
  46963. $buildtype.'").*?'.
  46964. '\/out:"(.*?)"/is';
  46965. if ($dsptext && preg_match($regex, $dsptext, $matches)) {
  46966. // what we get back is a relative path to the output file itself.
  46967. $outfile = realpath($matches[2]);
  46968. } else {
  46969. return $this->raiseError("Could not retrieve output information from $dsp.");
  46970. }
  46971. // realpath returns false if the file doesn't exist
  46972. if ($outfile && copy($outfile, "$dir/$out")) {
  46973. $outfile = "$dir/$out";
  46974. }
  46975. $built_files[] = array(
  46976. 'file' => "$outfile",
  46977. 'php_api' => $this->php_api_version,
  46978. 'zend_mod_api' => $this->zend_module_api_no,
  46979. 'zend_ext_api' => $this->zend_extension_api_no,
  46980. );
  46981. return $built_files;
  46982. }
  46983. // }}}
  46984. // {{{ msdevCallback()
  46985. function msdevCallback($what, $data)
  46986. {
  46987. if (!$this->_firstline)
  46988. $this->_firstline = $data;
  46989. $this->_lastline = $data;
  46990. call_user_func($this->current_callback, $what, $data);
  46991. }
  46992. /**
  46993. * @param string
  46994. * @param string
  46995. * @param array
  46996. * @access private
  46997. */
  46998. function _harvestInstDir($dest_prefix, $dirname, &$built_files)
  46999. {
  47000. $d = opendir($dirname);
  47001. if (!$d)
  47002. return false;
  47003. $ret = true;
  47004. while (($ent = readdir($d)) !== false) {
  47005. if ($ent[0] == '.')
  47006. continue;
  47007. $full = $dirname . DIRECTORY_SEPARATOR . $ent;
  47008. if (is_dir($full)) {
  47009. if (!$this->_harvestInstDir(
  47010. $dest_prefix . DIRECTORY_SEPARATOR . $ent,
  47011. $full, $built_files)) {
  47012. $ret = false;
  47013. break;
  47014. }
  47015. } else {
  47016. $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent;
  47017. $built_files[] = array(
  47018. 'file' => $full,
  47019. 'dest' => $dest,
  47020. 'php_api' => $this->php_api_version,
  47021. 'zend_mod_api' => $this->zend_module_api_no,
  47022. 'zend_ext_api' => $this->zend_extension_api_no,
  47023. );
  47024. }
  47025. }
  47026. closedir($d);
  47027. return $ret;
  47028. }
  47029. /**
  47030. * Build an extension from source. Runs "phpize" in the source
  47031. * directory, but compiles in a temporary directory
  47032. * (TMPDIR/pear-build-USER/PACKAGE-VERSION).
  47033. *
  47034. * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or
  47035. * a PEAR_PackageFile object
  47036. *
  47037. * @param mixed $callback callback function used to report output,
  47038. * see PEAR_Builder::_runCommand for details
  47039. *
  47040. * @return array an array of associative arrays with built files,
  47041. * format:
  47042. * array( array( 'file' => '/path/to/ext.so',
  47043. * 'php_api' => YYYYMMDD,
  47044. * 'zend_mod_api' => YYYYMMDD,
  47045. * 'zend_ext_api' => YYYYMMDD ),
  47046. * ... )
  47047. *
  47048. * @access public
  47049. *
  47050. * @see PEAR_Builder::_runCommand
  47051. */
  47052. function build($descfile, $callback = null)
  47053. {
  47054. if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php([^\\/\\\\]+)?$/',
  47055. $this->config->get('php_bin'), $matches)) {
  47056. if (isset($matches[2]) && strlen($matches[2]) &&
  47057. trim($matches[2]) != trim($this->config->get('php_prefix'))) {
  47058. $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') .
  47059. ' appears to have a prefix ' . $matches[2] . ', but' .
  47060. ' config variable php_prefix does not match');
  47061. }
  47062. if (isset($matches[3]) && strlen($matches[3]) &&
  47063. trim($matches[3]) != trim($this->config->get('php_suffix'))) {
  47064. $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') .
  47065. ' appears to have a suffix ' . $matches[3] . ', but' .
  47066. ' config variable php_suffix does not match');
  47067. }
  47068. }
  47069. $this->current_callback = $callback;
  47070. if (PEAR_OS == "Windows") {
  47071. return $this->_build_win32($descfile, $callback);
  47072. }
  47073. if (PEAR_OS != 'Unix') {
  47074. return $this->raiseError("building extensions not supported on this platform");
  47075. }
  47076. if (is_object($descfile)) {
  47077. $pkg = $descfile;
  47078. $descfile = $pkg->getPackageFile();
  47079. if (is_a($pkg, 'PEAR_PackageFile_v1')) {
  47080. $dir = dirname($descfile);
  47081. } else {
  47082. $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName();
  47083. // automatically delete at session end
  47084. self::addTempFile($dir);
  47085. }
  47086. } else {
  47087. $pf = new PEAR_PackageFile($this->config);
  47088. $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
  47089. if (PEAR::isError($pkg)) {
  47090. return $pkg;
  47091. }
  47092. $dir = dirname($descfile);
  47093. }
  47094. // Find config. outside of normal path - e.g. config.m4
  47095. foreach (array_keys($pkg->getInstallationFileList()) as $item) {
  47096. if (stristr(basename($item), 'config.m4') && dirname($item) != '.') {
  47097. $dir .= DIRECTORY_SEPARATOR . dirname($item);
  47098. break;
  47099. }
  47100. }
  47101. $old_cwd = getcwd();
  47102. if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
  47103. return $this->raiseError("could not chdir to $dir");
  47104. }
  47105. $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
  47106. if (is_dir($vdir)) {
  47107. chdir($vdir);
  47108. }
  47109. $dir = getcwd();
  47110. $this->log(2, "building in $dir");
  47111. $binDir = $this->config->get('bin_dir');
  47112. if (!preg_match('@(^|:)' . preg_quote($binDir, '@') . '(:|$)@', getenv('PATH'))) {
  47113. putenv('PATH=' . $binDir . ':' . getenv('PATH'));
  47114. }
  47115. $err = $this->_runCommand($this->config->get('php_prefix')
  47116. . "phpize" .
  47117. $this->config->get('php_suffix'),
  47118. array(&$this, 'phpizeCallback'));
  47119. if (PEAR::isError($err)) {
  47120. return $err;
  47121. }
  47122. if (!$err) {
  47123. return $this->raiseError("`phpize' failed");
  47124. }
  47125. // {{{ start of interactive part
  47126. $configure_command = "$dir/configure";
  47127. $phpConfigName = $this->config->get('php_prefix')
  47128. . 'php-config'
  47129. . $this->config->get('php_suffix');
  47130. $phpConfigPath = System::which($phpConfigName);
  47131. if ($phpConfigPath !== false) {
  47132. $configure_command .= ' --with-php-config='
  47133. . $phpConfigPath;
  47134. }
  47135. $configure_options = $pkg->getConfigureOptions();
  47136. if ($configure_options) {
  47137. foreach ($configure_options as $option) {
  47138. $default = array_key_exists('default', $option) ? $option['default'] : null;
  47139. if (array_key_exists($option['name'], $this->_parsed_configure_options)) {
  47140. $response = $this->_parsed_configure_options[$option['name']];
  47141. } else {
  47142. list($response) = $this->ui->userDialog(
  47143. 'build', [$option['prompt']], ['text'], [$default]);
  47144. }
  47145. if (substr($option['name'], 0, 5) === 'with-' &&
  47146. ($response === 'yes' || $response === 'autodetect')) {
  47147. $configure_command .= " --{$option[name]}";
  47148. } else {
  47149. $configure_command .= " --{$option[name]}=".trim($response);
  47150. }
  47151. }
  47152. }
  47153. // }}} end of interactive part
  47154. // FIXME make configurable
  47155. if (!$user=getenv('USER')) {
  47156. $user='defaultuser';
  47157. }
  47158. $tmpdir = $this->config->get('temp_dir');
  47159. $build_basedir = System::mktemp(' -t "' . $tmpdir . '" -d "pear-build-' . $user . '"');
  47160. $build_dir = "$build_basedir/$vdir";
  47161. $inst_dir = "$build_basedir/install-$vdir";
  47162. $this->log(1, "building in $build_dir");
  47163. if (is_dir($build_dir)) {
  47164. System::rm(array('-rf', $build_dir));
  47165. }
  47166. if (!System::mkDir(array('-p', $build_dir))) {
  47167. return $this->raiseError("could not create build dir: $build_dir");
  47168. }
  47169. self::addTempFile($build_dir);
  47170. if (!System::mkDir(array('-p', $inst_dir))) {
  47171. return $this->raiseError("could not create temporary install dir: $inst_dir");
  47172. }
  47173. self::addTempFile($inst_dir);
  47174. $make_command = getenv('MAKE') ? getenv('MAKE') : 'make';
  47175. $to_run = array(
  47176. $configure_command,
  47177. $make_command,
  47178. "$make_command INSTALL_ROOT=\"$inst_dir\" install",
  47179. "find \"$inst_dir\" | xargs ls -dils"
  47180. );
  47181. if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) {
  47182. return $this->raiseError("could not chdir to $build_dir");
  47183. }
  47184. putenv('PHP_PEAR_VERSION=1.10.10');
  47185. foreach ($to_run as $cmd) {
  47186. $err = $this->_runCommand($cmd, $callback);
  47187. if (PEAR::isError($err)) {
  47188. chdir($old_cwd);
  47189. return $err;
  47190. }
  47191. if (!$err) {
  47192. chdir($old_cwd);
  47193. return $this->raiseError("`$cmd' failed");
  47194. }
  47195. }
  47196. if (!($dp = opendir("modules"))) {
  47197. chdir($old_cwd);
  47198. return $this->raiseError("no `modules' directory found");
  47199. }
  47200. $built_files = array();
  47201. $prefix = exec($this->config->get('php_prefix')
  47202. . "php-config" .
  47203. $this->config->get('php_suffix') . " --prefix");
  47204. $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files);
  47205. chdir($old_cwd);
  47206. return $built_files;
  47207. }
  47208. /**
  47209. * Message callback function used when running the "phpize"
  47210. * program. Extracts the API numbers used. Ignores other message
  47211. * types than "cmdoutput".
  47212. *
  47213. * @param string $what the type of message
  47214. * @param mixed $data the message
  47215. *
  47216. * @return void
  47217. *
  47218. * @access public
  47219. */
  47220. function phpizeCallback($what, $data)
  47221. {
  47222. if ($what != 'cmdoutput') {
  47223. return;
  47224. }
  47225. $this->log(1, rtrim($data));
  47226. if (preg_match('/You should update your .aclocal.m4/', $data)) {
  47227. return;
  47228. }
  47229. $matches = array();
  47230. if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) {
  47231. $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1]));
  47232. $apino = (int)$matches[2];
  47233. if (isset($this->$member)) {
  47234. $this->$member = $apino;
  47235. //$msg = sprintf("%-22s : %d", $matches[1], $apino);
  47236. //$this->log(1, $msg);
  47237. }
  47238. }
  47239. }
  47240. /**
  47241. * Run an external command, using a message callback to report
  47242. * output. The command will be run through popen and output is
  47243. * reported for every line with a "cmdoutput" message with the
  47244. * line string, including newlines, as payload.
  47245. *
  47246. * @param string $command the command to run
  47247. *
  47248. * @param mixed $callback (optional) function to use as message
  47249. * callback
  47250. *
  47251. * @return bool whether the command was successful (exit code 0
  47252. * means success, any other means failure)
  47253. *
  47254. * @access private
  47255. */
  47256. function _runCommand($command, $callback = null)
  47257. {
  47258. $this->log(1, "running: $command");
  47259. $pp = popen("$command 2>&1", "r");
  47260. if (!$pp) {
  47261. return $this->raiseError("failed to run `$command'");
  47262. }
  47263. if ($callback && $callback[0]->debug == 1) {
  47264. $olddbg = $callback[0]->debug;
  47265. $callback[0]->debug = 2;
  47266. }
  47267. while ($line = fgets($pp, 1024)) {
  47268. if ($callback) {
  47269. call_user_func($callback, 'cmdoutput', $line);
  47270. } else {
  47271. $this->log(2, rtrim($line));
  47272. }
  47273. }
  47274. if ($callback && isset($olddbg)) {
  47275. $callback[0]->debug = $olddbg;
  47276. }
  47277. $exitcode = is_resource($pp) ? pclose($pp) : -1;
  47278. return ($exitcode == 0);
  47279. }
  47280. function log($level, $msg, $append_crlf = true)
  47281. {
  47282. if ($this->current_callback) {
  47283. if ($this->debug >= $level) {
  47284. call_user_func($this->current_callback, 'output', $msg);
  47285. }
  47286. return;
  47287. }
  47288. return parent::log($level, $msg, $append_crlf);
  47289. }
  47290. }
  47291. ����������PEAR-1.10.10/PEAR/ChannelFile.php�������������������������������������������������������������������0000644�0001750�0001750�00000143234�13565304531�015675� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  47292. /**
  47293. * PEAR_ChannelFile, the channel handling class
  47294. *
  47295. * PHP versions 4 and 5
  47296. *
  47297. * @category pear
  47298. * @package PEAR
  47299. * @author Greg Beaver <cellog@php.net>
  47300. * @copyright 1997-2009 The Authors
  47301. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  47302. * @link http://pear.php.net/package/PEAR
  47303. * @since File available since Release 1.4.0a1
  47304. */
  47305. /**
  47306. * Needed for error handling
  47307. */
  47308. require_once 'PEAR/ErrorStack.php';
  47309. require_once 'PEAR/XMLParser.php';
  47310. require_once 'PEAR/Common.php';
  47311. /**
  47312. * Error code if the channel.xml <channel> tag does not contain a valid version
  47313. */
  47314. define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
  47315. /**
  47316. * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
  47317. * currently
  47318. */
  47319. define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
  47320. /**
  47321. * Error code if parsing is attempted with no xml extension
  47322. */
  47323. define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
  47324. /**
  47325. * Error code if creating the xml parser resource fails
  47326. */
  47327. define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
  47328. /**
  47329. * Error code used for all sax xml parsing errors
  47330. */
  47331. define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
  47332. /**#@+
  47333. * Validation errors
  47334. */
  47335. /**
  47336. * Error code when channel name is missing
  47337. */
  47338. define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
  47339. /**
  47340. * Error code when channel name is invalid
  47341. */
  47342. define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
  47343. /**
  47344. * Error code when channel summary is missing
  47345. */
  47346. define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
  47347. /**
  47348. * Error code when channel summary is multi-line
  47349. */
  47350. define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
  47351. /**
  47352. * Error code when channel server is missing for protocol
  47353. */
  47354. define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
  47355. /**
  47356. * Error code when channel server is invalid for protocol
  47357. */
  47358. define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
  47359. /**
  47360. * Error code when a mirror name is invalid
  47361. */
  47362. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
  47363. /**
  47364. * Error code when a mirror type is invalid
  47365. */
  47366. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
  47367. /**
  47368. * Error code when an attempt is made to generate xml, but the parsed content is invalid
  47369. */
  47370. define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
  47371. /**
  47372. * Error code when an empty package name validate regex is passed in
  47373. */
  47374. define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
  47375. /**
  47376. * Error code when a <function> tag has no version
  47377. */
  47378. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
  47379. /**
  47380. * Error code when a <function> tag has no name
  47381. */
  47382. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
  47383. /**
  47384. * Error code when a <validatepackage> tag has no name
  47385. */
  47386. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
  47387. /**
  47388. * Error code when a <validatepackage> tag has no version attribute
  47389. */
  47390. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
  47391. /**
  47392. * Error code when a mirror does not exist but is called for in one of the set*
  47393. * methods.
  47394. */
  47395. define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
  47396. /**
  47397. * Error code when a server port is not numeric
  47398. */
  47399. define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
  47400. /**
  47401. * Error code when <static> contains no version attribute
  47402. */
  47403. define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
  47404. /**
  47405. * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
  47406. */
  47407. define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
  47408. /**
  47409. * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
  47410. */
  47411. define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
  47412. /**
  47413. * Error code when ssl attribute is present and is not "yes"
  47414. */
  47415. define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
  47416. /**#@-*/
  47417. /**
  47418. * Mirror types allowed. Currently only internet servers are recognized.
  47419. */
  47420. $GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server');
  47421. /**
  47422. * The Channel handling class
  47423. *
  47424. * @category pear
  47425. * @package PEAR
  47426. * @author Greg Beaver <cellog@php.net>
  47427. * @copyright 1997-2009 The Authors
  47428. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  47429. * @version Release: 1.10.10
  47430. * @link http://pear.php.net/package/PEAR
  47431. * @since Class available since Release 1.4.0a1
  47432. */
  47433. class PEAR_ChannelFile
  47434. {
  47435. /**
  47436. * @access private
  47437. * @var PEAR_ErrorStack
  47438. * @access private
  47439. */
  47440. var $_stack;
  47441. /**
  47442. * Supported channel.xml versions, for parsing
  47443. * @var array
  47444. * @access private
  47445. */
  47446. var $_supportedVersions = array('1.0');
  47447. /**
  47448. * Parsed channel information
  47449. * @var array
  47450. * @access private
  47451. */
  47452. var $_channelInfo;
  47453. /**
  47454. * index into the subchannels array, used for parsing xml
  47455. * @var int
  47456. * @access private
  47457. */
  47458. var $_subchannelIndex;
  47459. /**
  47460. * index into the mirrors array, used for parsing xml
  47461. * @var int
  47462. * @access private
  47463. */
  47464. var $_mirrorIndex;
  47465. /**
  47466. * Flag used to determine the validity of parsed content
  47467. * @var boolean
  47468. * @access private
  47469. */
  47470. var $_isValid = false;
  47471. function __construct()
  47472. {
  47473. $this->_stack = new PEAR_ErrorStack('PEAR_ChannelFile');
  47474. $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  47475. $this->_isValid = false;
  47476. }
  47477. /**
  47478. * @return array
  47479. * @access protected
  47480. */
  47481. function _getErrorMessage()
  47482. {
  47483. return
  47484. array(
  47485. PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
  47486. 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
  47487. PEAR_CHANNELFILE_ERROR_NO_VERSION =>
  47488. 'No version number found in <channel> tag',
  47489. PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
  47490. '%error%',
  47491. PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
  47492. 'Unable to create XML parser',
  47493. PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
  47494. '%error%',
  47495. PEAR_CHANNELFILE_ERROR_NO_NAME =>
  47496. 'Missing channel name',
  47497. PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
  47498. 'Invalid channel %tag% "%name%"',
  47499. PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
  47500. 'Missing channel summary',
  47501. PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
  47502. 'Channel summary should be on one line, but is multi-line',
  47503. PEAR_CHANNELFILE_ERROR_NO_HOST =>
  47504. 'Missing channel server for %type% server',
  47505. PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
  47506. 'Server name "%server%" is invalid for %type% server',
  47507. PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
  47508. 'Invalid mirror name "%name%", mirror type %type%',
  47509. PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
  47510. 'Invalid mirror type "%type%"',
  47511. PEAR_CHANNELFILE_ERROR_INVALID =>
  47512. 'Cannot generate xml, contents are invalid',
  47513. PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
  47514. 'packagenameregex cannot be empty',
  47515. PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
  47516. '%parent% %protocol% function has no version',
  47517. PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
  47518. '%parent% %protocol% function has no name',
  47519. PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
  47520. '%parent% rest baseurl has no type',
  47521. PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
  47522. 'Validation package has no name in <validatepackage> tag',
  47523. PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
  47524. 'Validation package "%package%" has no version',
  47525. PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
  47526. 'Mirror "%mirror%" does not exist',
  47527. PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
  47528. 'Port "%port%" must be numeric',
  47529. PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
  47530. '<static> tag must contain version attribute',
  47531. PEAR_CHANNELFILE_URI_CANT_MIRROR =>
  47532. 'The __uri pseudo-channel cannot have mirrors',
  47533. PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
  47534. '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
  47535. );
  47536. }
  47537. /**
  47538. * @param string contents of package.xml file
  47539. * @return bool success of parsing
  47540. */
  47541. function fromXmlString($data)
  47542. {
  47543. if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
  47544. if (!in_array($channelversion[1], $this->_supportedVersions)) {
  47545. $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
  47546. array('version' => $channelversion[1]));
  47547. return false;
  47548. }
  47549. $parser = new PEAR_XMLParser;
  47550. $result = $parser->parse($data);
  47551. if ($result !== true) {
  47552. if ($result->getCode() == 1) {
  47553. $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
  47554. array('error' => $result->getMessage()));
  47555. } else {
  47556. $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
  47557. }
  47558. return false;
  47559. }
  47560. $this->_channelInfo = $parser->getData();
  47561. return true;
  47562. } else {
  47563. $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
  47564. return false;
  47565. }
  47566. }
  47567. /**
  47568. * @return array
  47569. */
  47570. function toArray()
  47571. {
  47572. if (!$this->_isValid && !$this->validate()) {
  47573. return false;
  47574. }
  47575. return $this->_channelInfo;
  47576. }
  47577. /**
  47578. * @param array
  47579. *
  47580. * @return PEAR_ChannelFile|false false if invalid
  47581. */
  47582. public static function &fromArray(
  47583. $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
  47584. ) {
  47585. $a = new PEAR_ChannelFile($compatibility, $stackClass);
  47586. $a->_fromArray($data);
  47587. if (!$a->validate()) {
  47588. $a = false;
  47589. return $a;
  47590. }
  47591. return $a;
  47592. }
  47593. /**
  47594. * Unlike {@link fromArray()} this does not do any validation
  47595. *
  47596. * @param array
  47597. *
  47598. * @return PEAR_ChannelFile
  47599. */
  47600. public static function &fromArrayWithErrors(
  47601. $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
  47602. ) {
  47603. $a = new PEAR_ChannelFile($compatibility, $stackClass);
  47604. $a->_fromArray($data);
  47605. return $a;
  47606. }
  47607. /**
  47608. * @param array
  47609. * @access private
  47610. */
  47611. function _fromArray($data)
  47612. {
  47613. $this->_channelInfo = $data;
  47614. }
  47615. /**
  47616. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  47617. * @param boolean determines whether to purge the error stack after retrieving
  47618. * @return array
  47619. */
  47620. function getErrors($purge = false)
  47621. {
  47622. return $this->_stack->getErrors($purge);
  47623. }
  47624. /**
  47625. * Unindent given string (?)
  47626. *
  47627. * @param string $str The string that has to be unindented.
  47628. * @return string
  47629. * @access private
  47630. */
  47631. function _unIndent($str)
  47632. {
  47633. // remove leading newlines
  47634. $str = preg_replace('/^[\r\n]+/', '', $str);
  47635. // find whitespace at the beginning of the first line
  47636. $indent_len = strspn($str, " \t");
  47637. $indent = substr($str, 0, $indent_len);
  47638. $data = '';
  47639. // remove the same amount of whitespace from following lines
  47640. foreach (explode("\n", $str) as $line) {
  47641. if (substr($line, 0, $indent_len) == $indent) {
  47642. $data .= substr($line, $indent_len) . "\n";
  47643. }
  47644. }
  47645. return $data;
  47646. }
  47647. /**
  47648. * Parse a channel.xml file. Expects the name of
  47649. * a channel xml file as input.
  47650. *
  47651. * @param string $descfile name of channel xml file
  47652. * @return bool success of parsing
  47653. */
  47654. function fromXmlFile($descfile)
  47655. {
  47656. if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
  47657. (!$fp = fopen($descfile, 'r'))) {
  47658. require_once 'PEAR.php';
  47659. return PEAR::raiseError("Unable to open $descfile");
  47660. }
  47661. // read the whole thing so we only get one cdata callback
  47662. // for each block of cdata
  47663. fclose($fp);
  47664. $data = file_get_contents($descfile);
  47665. return $this->fromXmlString($data);
  47666. }
  47667. /**
  47668. * Parse channel information from different sources
  47669. *
  47670. * This method is able to extract information about a channel
  47671. * from an .xml file or a string
  47672. *
  47673. * @access public
  47674. * @param string Filename of the source or the source itself
  47675. * @return bool
  47676. */
  47677. function fromAny($info)
  47678. {
  47679. if (is_string($info) && file_exists($info) && strlen($info) < 255) {
  47680. $tmp = substr($info, -4);
  47681. if ($tmp == '.xml') {
  47682. $info = $this->fromXmlFile($info);
  47683. } else {
  47684. $fp = fopen($info, "r");
  47685. $test = fread($fp, 5);
  47686. fclose($fp);
  47687. if ($test == "<?xml") {
  47688. $info = $this->fromXmlFile($info);
  47689. }
  47690. }
  47691. if (PEAR::isError($info)) {
  47692. require_once 'PEAR.php';
  47693. return PEAR::raiseError($info);
  47694. }
  47695. }
  47696. if (is_string($info)) {
  47697. $info = $this->fromXmlString($info);
  47698. }
  47699. return $info;
  47700. }
  47701. /**
  47702. * Return an XML document based on previous parsing and modifications
  47703. *
  47704. * @return string XML data
  47705. *
  47706. * @access public
  47707. */
  47708. function toXml()
  47709. {
  47710. if (!$this->_isValid && !$this->validate()) {
  47711. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
  47712. return false;
  47713. }
  47714. if (!isset($this->_channelInfo['attribs']['version'])) {
  47715. $this->_channelInfo['attribs']['version'] = '1.0';
  47716. }
  47717. $channelInfo = $this->_channelInfo;
  47718. $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
  47719. $ret .= "<channel version=\"" .
  47720. $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
  47721. xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  47722. xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
  47723. . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
  47724. $channelInfo['attribs']['version'] . ".xsd\">
  47725. <name>$channelInfo[name]</name>
  47726. <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
  47727. ";
  47728. if (isset($channelInfo['suggestedalias'])) {
  47729. $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
  47730. }
  47731. if (isset($channelInfo['validatepackage'])) {
  47732. $ret .= ' <validatepackage version="' .
  47733. $channelInfo['validatepackage']['attribs']['version']. '">' .
  47734. htmlspecialchars($channelInfo['validatepackage']['_content']) .
  47735. "</validatepackage>\n";
  47736. }
  47737. $ret .= " <servers>\n";
  47738. $ret .= ' <primary';
  47739. if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
  47740. $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
  47741. }
  47742. if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
  47743. $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
  47744. }
  47745. $ret .= ">\n";
  47746. if (isset($channelInfo['servers']['primary']['rest'])) {
  47747. $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], ' ');
  47748. }
  47749. $ret .= " </primary>\n";
  47750. if (isset($channelInfo['servers']['mirror'])) {
  47751. $ret .= $this->_makeMirrorsXml($channelInfo);
  47752. }
  47753. $ret .= " </servers>\n";
  47754. $ret .= "</channel>";
  47755. return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
  47756. }
  47757. /**
  47758. * Generate the <rest> tag
  47759. * @access private
  47760. */
  47761. function _makeRestXml($info, $indent)
  47762. {
  47763. $ret = $indent . "<rest>\n";
  47764. if (isset($info['baseurl']) && !isset($info['baseurl'][0])) {
  47765. $info['baseurl'] = array($info['baseurl']);
  47766. }
  47767. if (isset($info['baseurl'])) {
  47768. foreach ($info['baseurl'] as $url) {
  47769. $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
  47770. $ret .= ">" . $url['_content'] . "</baseurl>\n";
  47771. }
  47772. }
  47773. $ret .= $indent . "</rest>\n";
  47774. return $ret;
  47775. }
  47776. /**
  47777. * Generate the <mirrors> tag
  47778. * @access private
  47779. */
  47780. function _makeMirrorsXml($channelInfo)
  47781. {
  47782. $ret = "";
  47783. if (!isset($channelInfo['servers']['mirror'][0])) {
  47784. $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
  47785. }
  47786. foreach ($channelInfo['servers']['mirror'] as $mirror) {
  47787. $ret .= ' <mirror host="' . $mirror['attribs']['host'] . '"';
  47788. if (isset($mirror['attribs']['port'])) {
  47789. $ret .= ' port="' . $mirror['attribs']['port'] . '"';
  47790. }
  47791. if (isset($mirror['attribs']['ssl'])) {
  47792. $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
  47793. }
  47794. $ret .= ">\n";
  47795. if (isset($mirror['rest'])) {
  47796. if (isset($mirror['rest'])) {
  47797. $ret .= $this->_makeRestXml($mirror['rest'], ' ');
  47798. }
  47799. $ret .= " </mirror>\n";
  47800. } else {
  47801. $ret .= "/>\n";
  47802. }
  47803. }
  47804. return $ret;
  47805. }
  47806. /**
  47807. * Generate the <functions> tag
  47808. * @access private
  47809. */
  47810. function _makeFunctionsXml($functions, $indent, $rest = false)
  47811. {
  47812. $ret = '';
  47813. if (!isset($functions[0])) {
  47814. $functions = array($functions);
  47815. }
  47816. foreach ($functions as $function) {
  47817. $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
  47818. if ($rest) {
  47819. $ret .= ' uri="' . $function['attribs']['uri'] . '"';
  47820. }
  47821. $ret .= ">" . $function['_content'] . "</function>\n";
  47822. }
  47823. return $ret;
  47824. }
  47825. /**
  47826. * Validation error. Also marks the object contents as invalid
  47827. * @param error code
  47828. * @param array error information
  47829. * @access private
  47830. */
  47831. function _validateError($code, $params = array())
  47832. {
  47833. $this->_stack->push($code, 'error', $params);
  47834. $this->_isValid = false;
  47835. }
  47836. /**
  47837. * Validation warning. Does not mark the object contents invalid.
  47838. * @param error code
  47839. * @param array error information
  47840. * @access private
  47841. */
  47842. function _validateWarning($code, $params = array())
  47843. {
  47844. $this->_stack->push($code, 'warning', $params);
  47845. }
  47846. /**
  47847. * Validate parsed file.
  47848. *
  47849. * @access public
  47850. * @return boolean
  47851. */
  47852. function validate()
  47853. {
  47854. $this->_isValid = true;
  47855. $info = $this->_channelInfo;
  47856. if (empty($info['name'])) {
  47857. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
  47858. } elseif (!$this->validChannelServer($info['name'])) {
  47859. if ($info['name'] != '__uri') {
  47860. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
  47861. 'name' => $info['name']));
  47862. }
  47863. }
  47864. if (empty($info['summary'])) {
  47865. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  47866. } elseif (strpos(trim($info['summary']), "\n") !== false) {
  47867. $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  47868. array('summary' => $info['summary']));
  47869. }
  47870. if (isset($info['suggestedalias'])) {
  47871. if (!$this->validChannelServer($info['suggestedalias'])) {
  47872. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  47873. array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
  47874. }
  47875. }
  47876. if (isset($info['localalias'])) {
  47877. if (!$this->validChannelServer($info['localalias'])) {
  47878. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  47879. array('tag' => 'localalias', 'name' =>$info['localalias']));
  47880. }
  47881. }
  47882. if (isset($info['validatepackage'])) {
  47883. if (!isset($info['validatepackage']['_content'])) {
  47884. $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
  47885. }
  47886. if (!isset($info['validatepackage']['attribs']['version'])) {
  47887. $content = isset($info['validatepackage']['_content']) ?
  47888. $info['validatepackage']['_content'] :
  47889. null;
  47890. $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
  47891. array('package' => $content));
  47892. }
  47893. }
  47894. if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) &&
  47895. !is_numeric($info['servers']['primary']['attribs']['port'])) {
  47896. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
  47897. array('port' => $info['servers']['primary']['attribs']['port']));
  47898. }
  47899. if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) &&
  47900. $info['servers']['primary']['attribs']['ssl'] != 'yes') {
  47901. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  47902. array('ssl' => $info['servers']['primary']['attribs']['ssl'],
  47903. 'server' => $info['name']));
  47904. }
  47905. if (isset($info['servers']['primary']['rest']) &&
  47906. isset($info['servers']['primary']['rest']['baseurl'])) {
  47907. $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
  47908. }
  47909. if (isset($info['servers']['mirror'])) {
  47910. if ($this->_channelInfo['name'] == '__uri') {
  47911. $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
  47912. }
  47913. if (!isset($info['servers']['mirror'][0])) {
  47914. $info['servers']['mirror'] = array($info['servers']['mirror']);
  47915. }
  47916. foreach ($info['servers']['mirror'] as $mirror) {
  47917. if (!isset($mirror['attribs']['host'])) {
  47918. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
  47919. array('type' => 'mirror'));
  47920. } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
  47921. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
  47922. array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
  47923. }
  47924. if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
  47925. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  47926. array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
  47927. }
  47928. if (isset($mirror['rest'])) {
  47929. $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
  47930. $mirror['attribs']['host']);
  47931. }
  47932. }
  47933. }
  47934. return $this->_isValid;
  47935. }
  47936. /**
  47937. * @param string rest - protocol name this function applies to
  47938. * @param array the functions
  47939. * @param string the name of the parent element (mirror name, for instance)
  47940. */
  47941. function _validateFunctions($protocol, $functions, $parent = '')
  47942. {
  47943. if (!isset($functions[0])) {
  47944. $functions = array($functions);
  47945. }
  47946. foreach ($functions as $function) {
  47947. if (!isset($function['_content']) || empty($function['_content'])) {
  47948. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
  47949. array('parent' => $parent, 'protocol' => $protocol));
  47950. }
  47951. if ($protocol == 'rest') {
  47952. if (!isset($function['attribs']['type']) ||
  47953. empty($function['attribs']['type'])) {
  47954. $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE,
  47955. array('parent' => $parent, 'protocol' => $protocol));
  47956. }
  47957. } else {
  47958. if (!isset($function['attribs']['version']) ||
  47959. empty($function['attribs']['version'])) {
  47960. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
  47961. array('parent' => $parent, 'protocol' => $protocol));
  47962. }
  47963. }
  47964. }
  47965. }
  47966. /**
  47967. * Test whether a string contains a valid channel server.
  47968. * @param string $ver the package version to test
  47969. * @return bool
  47970. */
  47971. function validChannelServer($server)
  47972. {
  47973. if ($server == '__uri') {
  47974. return true;
  47975. }
  47976. return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
  47977. }
  47978. /**
  47979. * @return string|false
  47980. */
  47981. function getName()
  47982. {
  47983. if (isset($this->_channelInfo['name'])) {
  47984. return $this->_channelInfo['name'];
  47985. }
  47986. return false;
  47987. }
  47988. /**
  47989. * @return string|false
  47990. */
  47991. function getServer()
  47992. {
  47993. if (isset($this->_channelInfo['name'])) {
  47994. return $this->_channelInfo['name'];
  47995. }
  47996. return false;
  47997. }
  47998. /**
  47999. * @return int|80 port number to connect to
  48000. */
  48001. function getPort($mirror = false)
  48002. {
  48003. if ($mirror) {
  48004. if ($mir = $this->getMirror($mirror)) {
  48005. if (isset($mir['attribs']['port'])) {
  48006. return $mir['attribs']['port'];
  48007. }
  48008. if ($this->getSSL($mirror)) {
  48009. return 443;
  48010. }
  48011. return 80;
  48012. }
  48013. return false;
  48014. }
  48015. if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
  48016. return $this->_channelInfo['servers']['primary']['attribs']['port'];
  48017. }
  48018. if ($this->getSSL()) {
  48019. return 443;
  48020. }
  48021. return 80;
  48022. }
  48023. /**
  48024. * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
  48025. */
  48026. function getSSL($mirror = false)
  48027. {
  48028. if ($mirror) {
  48029. if ($mir = $this->getMirror($mirror)) {
  48030. if (isset($mir['attribs']['ssl'])) {
  48031. return true;
  48032. }
  48033. return false;
  48034. }
  48035. return false;
  48036. }
  48037. if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  48038. return true;
  48039. }
  48040. return false;
  48041. }
  48042. /**
  48043. * @return string|false
  48044. */
  48045. function getSummary()
  48046. {
  48047. if (isset($this->_channelInfo['summary'])) {
  48048. return $this->_channelInfo['summary'];
  48049. }
  48050. return false;
  48051. }
  48052. /**
  48053. * @param string protocol type
  48054. * @param string Mirror name
  48055. * @return array|false
  48056. */
  48057. function getFunctions($protocol, $mirror = false)
  48058. {
  48059. if ($this->getName() == '__uri') {
  48060. return false;
  48061. }
  48062. $function = $protocol == 'rest' ? 'baseurl' : 'function';
  48063. if ($mirror) {
  48064. if ($mir = $this->getMirror($mirror)) {
  48065. if (isset($mir[$protocol][$function])) {
  48066. return $mir[$protocol][$function];
  48067. }
  48068. }
  48069. return false;
  48070. }
  48071. if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
  48072. return $this->_channelInfo['servers']['primary'][$protocol][$function];
  48073. }
  48074. return false;
  48075. }
  48076. /**
  48077. * @param string Protocol type
  48078. * @param string Function name (null to return the
  48079. * first protocol of the type requested)
  48080. * @param string Mirror name, if any
  48081. * @return array
  48082. */
  48083. function getFunction($type, $name = null, $mirror = false)
  48084. {
  48085. $protocols = $this->getFunctions($type, $mirror);
  48086. if (!$protocols) {
  48087. return false;
  48088. }
  48089. foreach ($protocols as $protocol) {
  48090. if ($name === null) {
  48091. return $protocol;
  48092. }
  48093. if ($protocol['_content'] != $name) {
  48094. continue;
  48095. }
  48096. return $protocol;
  48097. }
  48098. return false;
  48099. }
  48100. /**
  48101. * @param string protocol type
  48102. * @param string protocol name
  48103. * @param string version
  48104. * @param string mirror name
  48105. * @return boolean
  48106. */
  48107. function supports($type, $name = null, $mirror = false, $version = '1.0')
  48108. {
  48109. $protocols = $this->getFunctions($type, $mirror);
  48110. if (!$protocols) {
  48111. return false;
  48112. }
  48113. foreach ($protocols as $protocol) {
  48114. if ($protocol['attribs']['version'] != $version) {
  48115. continue;
  48116. }
  48117. if ($name === null) {
  48118. return true;
  48119. }
  48120. if ($protocol['_content'] != $name) {
  48121. continue;
  48122. }
  48123. return true;
  48124. }
  48125. return false;
  48126. }
  48127. /**
  48128. * Determines whether a channel supports Representational State Transfer (REST) protocols
  48129. * for retrieving channel information
  48130. * @param string
  48131. * @return bool
  48132. */
  48133. function supportsREST($mirror = false)
  48134. {
  48135. if ($mirror == $this->_channelInfo['name']) {
  48136. $mirror = false;
  48137. }
  48138. if ($mirror) {
  48139. if ($mir = $this->getMirror($mirror)) {
  48140. return isset($mir['rest']);
  48141. }
  48142. return false;
  48143. }
  48144. return isset($this->_channelInfo['servers']['primary']['rest']);
  48145. }
  48146. /**
  48147. * Get the URL to access a base resource.
  48148. *
  48149. * Hyperlinks in the returned xml will be used to retrieve the proper information
  48150. * needed. This allows extreme extensibility and flexibility in implementation
  48151. * @param string Resource Type to retrieve
  48152. */
  48153. function getBaseURL($resourceType, $mirror = false)
  48154. {
  48155. if ($mirror == $this->_channelInfo['name']) {
  48156. $mirror = false;
  48157. }
  48158. if ($mirror) {
  48159. $mir = $this->getMirror($mirror);
  48160. if (!$mir) {
  48161. return false;
  48162. }
  48163. $rest = $mir['rest'];
  48164. } else {
  48165. $rest = $this->_channelInfo['servers']['primary']['rest'];
  48166. }
  48167. if (!isset($rest['baseurl'][0])) {
  48168. $rest['baseurl'] = array($rest['baseurl']);
  48169. }
  48170. foreach ($rest['baseurl'] as $baseurl) {
  48171. if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
  48172. return $baseurl['_content'];
  48173. }
  48174. }
  48175. return false;
  48176. }
  48177. /**
  48178. * Since REST does not implement RPC, provide this as a logical wrapper around
  48179. * resetFunctions for REST
  48180. * @param string|false mirror name, if any
  48181. */
  48182. function resetREST($mirror = false)
  48183. {
  48184. return $this->resetFunctions('rest', $mirror);
  48185. }
  48186. /**
  48187. * Empty all protocol definitions
  48188. * @param string protocol type
  48189. * @param string|false mirror name, if any
  48190. */
  48191. function resetFunctions($type, $mirror = false)
  48192. {
  48193. if ($mirror) {
  48194. if (isset($this->_channelInfo['servers']['mirror'])) {
  48195. $mirrors = $this->_channelInfo['servers']['mirror'];
  48196. if (!isset($mirrors[0])) {
  48197. $mirrors = array($mirrors);
  48198. }
  48199. foreach ($mirrors as $i => $mir) {
  48200. if ($mir['attribs']['host'] == $mirror) {
  48201. if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
  48202. unset($this->_channelInfo['servers']['mirror'][$i][$type]);
  48203. }
  48204. return true;
  48205. }
  48206. }
  48207. return false;
  48208. }
  48209. return false;
  48210. }
  48211. if (isset($this->_channelInfo['servers']['primary'][$type])) {
  48212. unset($this->_channelInfo['servers']['primary'][$type]);
  48213. }
  48214. return true;
  48215. }
  48216. /**
  48217. * Set a channel's protocols to the protocols supported by pearweb
  48218. */
  48219. function setDefaultPEARProtocols($version = '1.0', $mirror = false)
  48220. {
  48221. switch ($version) {
  48222. case '1.0' :
  48223. $this->resetREST($mirror);
  48224. if (!isset($this->_channelInfo['servers'])) {
  48225. $this->_channelInfo['servers'] = array('primary' =>
  48226. array('rest' => array()));
  48227. } elseif (!isset($this->_channelInfo['servers']['primary'])) {
  48228. $this->_channelInfo['servers']['primary'] = array('rest' => array());
  48229. }
  48230. return true;
  48231. break;
  48232. default :
  48233. return false;
  48234. break;
  48235. }
  48236. }
  48237. /**
  48238. * @return array
  48239. */
  48240. function getMirrors()
  48241. {
  48242. if (isset($this->_channelInfo['servers']['mirror'])) {
  48243. $mirrors = $this->_channelInfo['servers']['mirror'];
  48244. if (!isset($mirrors[0])) {
  48245. $mirrors = array($mirrors);
  48246. }
  48247. return $mirrors;
  48248. }
  48249. return array();
  48250. }
  48251. /**
  48252. * Get the unserialized XML representing a mirror
  48253. * @return array|false
  48254. */
  48255. function getMirror($server)
  48256. {
  48257. foreach ($this->getMirrors() as $mirror) {
  48258. if ($mirror['attribs']['host'] == $server) {
  48259. return $mirror;
  48260. }
  48261. }
  48262. return false;
  48263. }
  48264. /**
  48265. * @param string
  48266. * @return string|false
  48267. * @error PEAR_CHANNELFILE_ERROR_NO_NAME
  48268. * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
  48269. */
  48270. function setName($name)
  48271. {
  48272. return $this->setServer($name);
  48273. }
  48274. /**
  48275. * Set the socket number (port) that is used to connect to this channel
  48276. * @param integer
  48277. * @param string|false name of the mirror server, or false for the primary
  48278. */
  48279. function setPort($port, $mirror = false)
  48280. {
  48281. if ($mirror) {
  48282. if (!isset($this->_channelInfo['servers']['mirror'])) {
  48283. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  48284. array('mirror' => $mirror));
  48285. return false;
  48286. }
  48287. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  48288. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  48289. if ($mirror == $mir['attribs']['host']) {
  48290. $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
  48291. return true;
  48292. }
  48293. }
  48294. return false;
  48295. } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  48296. $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
  48297. $this->_isValid = false;
  48298. return true;
  48299. }
  48300. }
  48301. $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
  48302. $this->_isValid = false;
  48303. return true;
  48304. }
  48305. /**
  48306. * Set the socket number (port) that is used to connect to this channel
  48307. * @param bool Determines whether to turn on SSL support or turn it off
  48308. * @param string|false name of the mirror server, or false for the primary
  48309. */
  48310. function setSSL($ssl = true, $mirror = false)
  48311. {
  48312. if ($mirror) {
  48313. if (!isset($this->_channelInfo['servers']['mirror'])) {
  48314. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  48315. array('mirror' => $mirror));
  48316. return false;
  48317. }
  48318. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  48319. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  48320. if ($mirror == $mir['attribs']['host']) {
  48321. if (!$ssl) {
  48322. if (isset($this->_channelInfo['servers']['mirror'][$i]
  48323. ['attribs']['ssl'])) {
  48324. unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
  48325. }
  48326. } else {
  48327. $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
  48328. }
  48329. return true;
  48330. }
  48331. }
  48332. return false;
  48333. } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  48334. if (!$ssl) {
  48335. if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
  48336. unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
  48337. }
  48338. } else {
  48339. $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
  48340. }
  48341. $this->_isValid = false;
  48342. return true;
  48343. }
  48344. }
  48345. if ($ssl) {
  48346. $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
  48347. } else {
  48348. if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  48349. unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
  48350. }
  48351. }
  48352. $this->_isValid = false;
  48353. return true;
  48354. }
  48355. /**
  48356. * @param string
  48357. * @return string|false
  48358. * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
  48359. * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
  48360. */
  48361. function setServer($server, $mirror = false)
  48362. {
  48363. if (empty($server)) {
  48364. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
  48365. return false;
  48366. } elseif (!$this->validChannelServer($server)) {
  48367. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  48368. array('tag' => 'name', 'name' => $server));
  48369. return false;
  48370. }
  48371. if ($mirror) {
  48372. $found = false;
  48373. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  48374. if ($mirror == $mir['attribs']['host']) {
  48375. $found = true;
  48376. break;
  48377. }
  48378. }
  48379. if (!$found) {
  48380. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  48381. array('mirror' => $mirror));
  48382. return false;
  48383. }
  48384. $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
  48385. return true;
  48386. }
  48387. $this->_channelInfo['name'] = $server;
  48388. return true;
  48389. }
  48390. /**
  48391. * @param string
  48392. * @return boolean success
  48393. * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
  48394. * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
  48395. */
  48396. function setSummary($summary)
  48397. {
  48398. if (empty($summary)) {
  48399. $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  48400. return false;
  48401. } elseif (strpos(trim($summary), "\n") !== false) {
  48402. $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  48403. array('summary' => $summary));
  48404. }
  48405. $this->_channelInfo['summary'] = $summary;
  48406. return true;
  48407. }
  48408. /**
  48409. * @param string
  48410. * @param boolean determines whether the alias is in channel.xml or local
  48411. * @return boolean success
  48412. */
  48413. function setAlias($alias, $local = false)
  48414. {
  48415. if (!$this->validChannelServer($alias)) {
  48416. $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  48417. array('tag' => 'suggestedalias', 'name' => $alias));
  48418. return false;
  48419. }
  48420. if ($local) {
  48421. $this->_channelInfo['localalias'] = $alias;
  48422. } else {
  48423. $this->_channelInfo['suggestedalias'] = $alias;
  48424. }
  48425. return true;
  48426. }
  48427. /**
  48428. * @return string
  48429. */
  48430. function getAlias()
  48431. {
  48432. if (isset($this->_channelInfo['localalias'])) {
  48433. return $this->_channelInfo['localalias'];
  48434. }
  48435. if (isset($this->_channelInfo['suggestedalias'])) {
  48436. return $this->_channelInfo['suggestedalias'];
  48437. }
  48438. if (isset($this->_channelInfo['name'])) {
  48439. return $this->_channelInfo['name'];
  48440. }
  48441. return '';
  48442. }
  48443. /**
  48444. * Set the package validation object if it differs from PEAR's default
  48445. * The class must be includeable via changing _ in the classname to path separator,
  48446. * but no checking of this is made.
  48447. * @param string|false pass in false to reset to the default packagename regex
  48448. * @return boolean success
  48449. */
  48450. function setValidationPackage($validateclass, $version)
  48451. {
  48452. if (empty($validateclass)) {
  48453. unset($this->_channelInfo['validatepackage']);
  48454. }
  48455. $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
  48456. $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
  48457. }
  48458. /**
  48459. * Add a protocol to the provides section
  48460. * @param string protocol type
  48461. * @param string protocol version
  48462. * @param string protocol name, if any
  48463. * @param string mirror name, if this is a mirror's protocol
  48464. * @return bool
  48465. */
  48466. function addFunction($type, $version, $name = '', $mirror = false)
  48467. {
  48468. if ($mirror) {
  48469. return $this->addMirrorFunction($mirror, $type, $version, $name);
  48470. }
  48471. $set = array('attribs' => array('version' => $version), '_content' => $name);
  48472. if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
  48473. if (!isset($this->_channelInfo['servers'])) {
  48474. $this->_channelInfo['servers'] = array('primary' =>
  48475. array($type => array()));
  48476. } elseif (!isset($this->_channelInfo['servers']['primary'])) {
  48477. $this->_channelInfo['servers']['primary'] = array($type => array());
  48478. }
  48479. $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
  48480. $this->_isValid = false;
  48481. return true;
  48482. } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
  48483. $this->_channelInfo['servers']['primary'][$type]['function'] = array(
  48484. $this->_channelInfo['servers']['primary'][$type]['function']);
  48485. }
  48486. $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
  48487. return true;
  48488. }
  48489. /**
  48490. * Add a protocol to a mirror's provides section
  48491. * @param string mirror name (server)
  48492. * @param string protocol type
  48493. * @param string protocol version
  48494. * @param string protocol name, if any
  48495. */
  48496. function addMirrorFunction($mirror, $type, $version, $name = '')
  48497. {
  48498. if (!isset($this->_channelInfo['servers']['mirror'])) {
  48499. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  48500. array('mirror' => $mirror));
  48501. return false;
  48502. }
  48503. $setmirror = false;
  48504. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  48505. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  48506. if ($mirror == $mir['attribs']['host']) {
  48507. $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  48508. break;
  48509. }
  48510. }
  48511. } else {
  48512. if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  48513. $setmirror = &$this->_channelInfo['servers']['mirror'];
  48514. }
  48515. }
  48516. if (!$setmirror) {
  48517. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  48518. array('mirror' => $mirror));
  48519. return false;
  48520. }
  48521. $set = array('attribs' => array('version' => $version), '_content' => $name);
  48522. if (!isset($setmirror[$type]['function'])) {
  48523. $setmirror[$type]['function'] = $set;
  48524. $this->_isValid = false;
  48525. return true;
  48526. } elseif (!isset($setmirror[$type]['function'][0])) {
  48527. $setmirror[$type]['function'] = array($setmirror[$type]['function']);
  48528. }
  48529. $setmirror[$type]['function'][] = $set;
  48530. $this->_isValid = false;
  48531. return true;
  48532. }
  48533. /**
  48534. * @param string Resource Type this url links to
  48535. * @param string URL
  48536. * @param string|false mirror name, if this is not a primary server REST base URL
  48537. */
  48538. function setBaseURL($resourceType, $url, $mirror = false)
  48539. {
  48540. if ($mirror) {
  48541. if (!isset($this->_channelInfo['servers']['mirror'])) {
  48542. $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  48543. array('mirror' => $mirror));
  48544. return false;
  48545. }
  48546. $setmirror = false;
  48547. if (isset($this->_channelInfo['servers']['mirror'][0])) {
  48548. foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  48549. if ($mirror == $mir['attribs']['host']) {
  48550. $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  48551. break;
  48552. }
  48553. }
  48554. } else {
  48555. if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  48556. $setmirror = &$this->_channelInfo['servers']['mirror'];
  48557. }
  48558. }
  48559. } else {
  48560. $setmirror = &$this->_channelInfo['servers']['primary'];
  48561. }
  48562. $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
  48563. if (!isset($setmirror['rest'])) {
  48564. $setmirror['rest'] = array();
  48565. }
  48566. if (!isset($setmirror['rest']['baseurl'])) {
  48567. $setmirror['rest']['baseurl'] = $set;
  48568. $this->_isValid = false;
  48569. return true;
  48570. } elseif (!isset($setmirror['rest']['baseurl'][0])) {
  48571. $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
  48572. }
  48573. foreach ($setmirror['rest']['baseurl'] as $i => $url) {
  48574. if ($url['attribs']['type'] == $resourceType) {
  48575. $this->_isValid = false;
  48576. $setmirror['rest']['baseurl'][$i] = $set;
  48577. return true;
  48578. }
  48579. }
  48580. $setmirror['rest']['baseurl'][] = $set;
  48581. $this->_isValid = false;
  48582. return true;
  48583. }
  48584. /**
  48585. * @param string mirror server
  48586. * @param int mirror http port
  48587. * @return boolean
  48588. */
  48589. function addMirror($server, $port = null)
  48590. {
  48591. if ($this->_channelInfo['name'] == '__uri') {
  48592. return false; // the __uri channel cannot have mirrors by definition
  48593. }
  48594. $set = array('attribs' => array('host' => $server));
  48595. if (is_numeric($port)) {
  48596. $set['attribs']['port'] = $port;
  48597. }
  48598. if (!isset($this->_channelInfo['servers']['mirror'])) {
  48599. $this->_channelInfo['servers']['mirror'] = $set;
  48600. return true;
  48601. }
  48602. if (!isset($this->_channelInfo['servers']['mirror'][0])) {
  48603. $this->_channelInfo['servers']['mirror'] =
  48604. array($this->_channelInfo['servers']['mirror']);
  48605. }
  48606. $this->_channelInfo['servers']['mirror'][] = $set;
  48607. return true;
  48608. }
  48609. /**
  48610. * Retrieve the name of the validation package for this channel
  48611. * @return string|false
  48612. */
  48613. function getValidationPackage()
  48614. {
  48615. if (!$this->_isValid && !$this->validate()) {
  48616. return false;
  48617. }
  48618. if (!isset($this->_channelInfo['validatepackage'])) {
  48619. return array('attribs' => array('version' => 'default'),
  48620. '_content' => 'PEAR_Validate');
  48621. }
  48622. return $this->_channelInfo['validatepackage'];
  48623. }
  48624. /**
  48625. * Retrieve the object that can be used for custom validation
  48626. * @param string|false the name of the package to validate. If the package is
  48627. * the channel validation package, PEAR_Validate is returned
  48628. * @return PEAR_Validate|false false is returned if the validation package
  48629. * cannot be located
  48630. */
  48631. function &getValidationObject($package = false)
  48632. {
  48633. if (!class_exists('PEAR_Validate')) {
  48634. require_once 'PEAR/Validate.php';
  48635. }
  48636. if (!$this->_isValid) {
  48637. if (!$this->validate()) {
  48638. $a = false;
  48639. return $a;
  48640. }
  48641. }
  48642. if (isset($this->_channelInfo['validatepackage'])) {
  48643. if ($package == $this->_channelInfo['validatepackage']) {
  48644. // channel validation packages are always validated by PEAR_Validate
  48645. $val = new PEAR_Validate;
  48646. return $val;
  48647. }
  48648. if (!class_exists(str_replace('.', '_',
  48649. $this->_channelInfo['validatepackage']['_content']))) {
  48650. if ($this->isIncludeable(str_replace('_', '/',
  48651. $this->_channelInfo['validatepackage']['_content']) . '.php')) {
  48652. include_once str_replace('_', '/',
  48653. $this->_channelInfo['validatepackage']['_content']) . '.php';
  48654. $vclass = str_replace('.', '_',
  48655. $this->_channelInfo['validatepackage']['_content']);
  48656. $val = new $vclass;
  48657. } else {
  48658. $a = false;
  48659. return $a;
  48660. }
  48661. } else {
  48662. $vclass = str_replace('.', '_',
  48663. $this->_channelInfo['validatepackage']['_content']);
  48664. $val = new $vclass;
  48665. }
  48666. } else {
  48667. $val = new PEAR_Validate;
  48668. }
  48669. return $val;
  48670. }
  48671. function isIncludeable($path)
  48672. {
  48673. $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
  48674. foreach ($possibilities as $dir) {
  48675. if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
  48676. && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
  48677. return true;
  48678. }
  48679. }
  48680. return false;
  48681. }
  48682. /**
  48683. * This function is used by the channel updater and retrieves a value set by
  48684. * the registry, or the current time if it has not been set
  48685. * @return string
  48686. */
  48687. function lastModified()
  48688. {
  48689. if (isset($this->_channelInfo['_lastmodified'])) {
  48690. return $this->_channelInfo['_lastmodified'];
  48691. }
  48692. return time();
  48693. }
  48694. }
  48695. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Command.php�����������������������������������������������������������������������0000644�0001750�0001750�00000030213�13565304531�015073� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  48696. /**
  48697. * PEAR_Command, command pattern class
  48698. *
  48699. * PHP versions 4 and 5
  48700. *
  48701. * @category pear
  48702. * @package PEAR
  48703. * @author Stig Bakken <ssb@php.net>
  48704. * @author Greg Beaver <cellog@php.net>
  48705. * @copyright 1997-2009 The Authors
  48706. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  48707. * @link http://pear.php.net/package/PEAR
  48708. * @since File available since Release 0.1
  48709. */
  48710. /**
  48711. * Needed for error handling
  48712. */
  48713. require_once 'PEAR.php';
  48714. require_once 'PEAR/Frontend.php';
  48715. require_once 'PEAR/XMLParser.php';
  48716. /**
  48717. * List of commands and what classes they are implemented in.
  48718. * @var array command => implementing class
  48719. */
  48720. $GLOBALS['_PEAR_Command_commandlist'] = array();
  48721. /**
  48722. * List of commands and their descriptions
  48723. * @var array command => description
  48724. */
  48725. $GLOBALS['_PEAR_Command_commanddesc'] = array();
  48726. /**
  48727. * List of shortcuts to common commands.
  48728. * @var array shortcut => command
  48729. */
  48730. $GLOBALS['_PEAR_Command_shortcuts'] = array();
  48731. /**
  48732. * Array of command objects
  48733. * @var array class => object
  48734. */
  48735. $GLOBALS['_PEAR_Command_objects'] = array();
  48736. /**
  48737. * PEAR command class, a simple factory class for administrative
  48738. * commands.
  48739. *
  48740. * How to implement command classes:
  48741. *
  48742. * - The class must be called PEAR_Command_Nnn, installed in the
  48743. * "PEAR/Common" subdir, with a method called getCommands() that
  48744. * returns an array of the commands implemented by the class (see
  48745. * PEAR/Command/Install.php for an example).
  48746. *
  48747. * - The class must implement a run() function that is called with three
  48748. * params:
  48749. *
  48750. * (string) command name
  48751. * (array) assoc array with options, freely defined by each
  48752. * command, for example:
  48753. * array('force' => true)
  48754. * (array) list of the other parameters
  48755. *
  48756. * The run() function returns a PEAR_CommandResponse object. Use
  48757. * these methods to get information:
  48758. *
  48759. * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
  48760. * *_PARTIAL means that you need to issue at least
  48761. * one more command to complete the operation
  48762. * (used for example for validation steps).
  48763. *
  48764. * string getMessage() Returns a message for the user. Remember,
  48765. * no HTML or other interface-specific markup.
  48766. *
  48767. * If something unexpected happens, run() returns a PEAR error.
  48768. *
  48769. * - DON'T OUTPUT ANYTHING! Return text for output instead.
  48770. *
  48771. * - DON'T USE HTML! The text you return will be used from both Gtk,
  48772. * web and command-line interfaces, so for now, keep everything to
  48773. * plain text.
  48774. *
  48775. * - DON'T USE EXIT OR DIE! Always use pear errors. From static
  48776. * classes do PEAR::raiseError(), from other classes do
  48777. * $this->raiseError().
  48778. * @category pear
  48779. * @package PEAR
  48780. * @author Stig Bakken <ssb@php.net>
  48781. * @author Greg Beaver <cellog@php.net>
  48782. * @copyright 1997-2009 The Authors
  48783. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  48784. * @version Release: 1.10.10
  48785. * @link http://pear.php.net/package/PEAR
  48786. * @since Class available since Release 0.1
  48787. */
  48788. class PEAR_Command
  48789. {
  48790. // {{{ factory()
  48791. /**
  48792. * Get the right object for executing a command.
  48793. *
  48794. * @param string $command The name of the command
  48795. * @param object $config Instance of PEAR_Config object
  48796. *
  48797. * @return object the command object or a PEAR error
  48798. */
  48799. public static function &factory($command, &$config)
  48800. {
  48801. if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  48802. PEAR_Command::registerCommands();
  48803. }
  48804. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  48805. $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  48806. }
  48807. if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  48808. $a = PEAR::raiseError("unknown command `$command'");
  48809. return $a;
  48810. }
  48811. $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  48812. if (!class_exists($class)) {
  48813. require_once $GLOBALS['_PEAR_Command_objects'][$class];
  48814. }
  48815. if (!class_exists($class)) {
  48816. $a = PEAR::raiseError("unknown command `$command'");
  48817. return $a;
  48818. }
  48819. $ui =& PEAR_Command::getFrontendObject();
  48820. $obj = new $class($ui, $config);
  48821. return $obj;
  48822. }
  48823. // }}}
  48824. // {{{ & getObject()
  48825. public static function &getObject($command)
  48826. {
  48827. $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  48828. if (!class_exists($class)) {
  48829. require_once $GLOBALS['_PEAR_Command_objects'][$class];
  48830. }
  48831. if (!class_exists($class)) {
  48832. return PEAR::raiseError("unknown command `$command'");
  48833. }
  48834. $ui =& PEAR_Command::getFrontendObject();
  48835. $config = &PEAR_Config::singleton();
  48836. $obj = new $class($ui, $config);
  48837. return $obj;
  48838. }
  48839. // }}}
  48840. // {{{ & getFrontendObject()
  48841. /**
  48842. * Get instance of frontend object.
  48843. *
  48844. * @return object|PEAR_Error
  48845. */
  48846. public static function &getFrontendObject()
  48847. {
  48848. $a = &PEAR_Frontend::singleton();
  48849. return $a;
  48850. }
  48851. // }}}
  48852. // {{{ & setFrontendClass()
  48853. /**
  48854. * Load current frontend class.
  48855. *
  48856. * @param string $uiclass Name of class implementing the frontend
  48857. *
  48858. * @return object the frontend object, or a PEAR error
  48859. */
  48860. public static function &setFrontendClass($uiclass)
  48861. {
  48862. $a = &PEAR_Frontend::setFrontendClass($uiclass);
  48863. return $a;
  48864. }
  48865. // }}}
  48866. // {{{ setFrontendType()
  48867. /**
  48868. * Set current frontend.
  48869. *
  48870. * @param string $uitype Name of the frontend type (for example "CLI")
  48871. *
  48872. * @return object the frontend object, or a PEAR error
  48873. */
  48874. public static function setFrontendType($uitype)
  48875. {
  48876. $uiclass = 'PEAR_Frontend_' . $uitype;
  48877. return PEAR_Command::setFrontendClass($uiclass);
  48878. }
  48879. // }}}
  48880. // {{{ registerCommands()
  48881. /**
  48882. * Scan through the Command directory looking for classes
  48883. * and see what commands they implement.
  48884. *
  48885. * @param bool (optional) if FALSE (default), the new list of
  48886. * commands should replace the current one. If TRUE,
  48887. * new entries will be merged with old.
  48888. *
  48889. * @param string (optional) where (what directory) to look for
  48890. * classes, defaults to the Command subdirectory of
  48891. * the directory from where this file (__FILE__) is
  48892. * included.
  48893. *
  48894. * @return bool TRUE on success, a PEAR error on failure
  48895. */
  48896. public static function registerCommands($merge = false, $dir = null)
  48897. {
  48898. $parser = new PEAR_XMLParser;
  48899. if ($dir === null) {
  48900. $dir = dirname(__FILE__) . '/Command';
  48901. }
  48902. if (!is_dir($dir)) {
  48903. return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
  48904. }
  48905. $dp = @opendir($dir);
  48906. if (empty($dp)) {
  48907. return PEAR::raiseError("registerCommands: opendir($dir) failed");
  48908. }
  48909. if (!$merge) {
  48910. $GLOBALS['_PEAR_Command_commandlist'] = array();
  48911. }
  48912. while ($file = readdir($dp)) {
  48913. if ($file[0] == '.' || substr($file, -4) != '.xml') {
  48914. continue;
  48915. }
  48916. $f = substr($file, 0, -4);
  48917. $class = "PEAR_Command_" . $f;
  48918. // List of commands
  48919. if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
  48920. $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php';
  48921. }
  48922. $parser->parse(file_get_contents("$dir/$file"));
  48923. $implements = $parser->getData();
  48924. foreach ($implements as $command => $desc) {
  48925. if ($command == 'attribs') {
  48926. continue;
  48927. }
  48928. if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  48929. return PEAR::raiseError('Command "' . $command . '" already registered in ' .
  48930. 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  48931. }
  48932. $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
  48933. $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
  48934. if (isset($desc['shortcut'])) {
  48935. $shortcut = $desc['shortcut'];
  48936. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
  48937. return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
  48938. 'registered to command "' . $command . '" in class "' .
  48939. $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  48940. }
  48941. $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
  48942. }
  48943. if (isset($desc['options']) && $desc['options']) {
  48944. foreach ($desc['options'] as $oname => $option) {
  48945. if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
  48946. return PEAR::raiseError('Option "' . $oname . '" short option "' .
  48947. $option['shortopt'] . '" must be ' .
  48948. 'only 1 character in Command "' . $command . '" in class "' .
  48949. $class . '"');
  48950. }
  48951. }
  48952. }
  48953. }
  48954. }
  48955. ksort($GLOBALS['_PEAR_Command_shortcuts']);
  48956. ksort($GLOBALS['_PEAR_Command_commandlist']);
  48957. @closedir($dp);
  48958. return true;
  48959. }
  48960. // }}}
  48961. // {{{ getCommands()
  48962. /**
  48963. * Get the list of currently supported commands, and what
  48964. * classes implement them.
  48965. *
  48966. * @return array command => implementing class
  48967. */
  48968. public static function getCommands()
  48969. {
  48970. if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  48971. PEAR_Command::registerCommands();
  48972. }
  48973. return $GLOBALS['_PEAR_Command_commandlist'];
  48974. }
  48975. // }}}
  48976. // {{{ getShortcuts()
  48977. /**
  48978. * Get the list of command shortcuts.
  48979. *
  48980. * @return array shortcut => command
  48981. */
  48982. public static function getShortcuts()
  48983. {
  48984. if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
  48985. PEAR_Command::registerCommands();
  48986. }
  48987. return $GLOBALS['_PEAR_Command_shortcuts'];
  48988. }
  48989. // }}}
  48990. // {{{ getGetoptArgs()
  48991. /**
  48992. * Compiles arguments for getopt.
  48993. *
  48994. * @param string $command command to get optstring for
  48995. * @param string $short_args (reference) short getopt format
  48996. * @param array $long_args (reference) long getopt format
  48997. *
  48998. * @return void
  48999. */
  49000. public static function getGetoptArgs($command, &$short_args, &$long_args)
  49001. {
  49002. if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  49003. PEAR_Command::registerCommands();
  49004. }
  49005. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  49006. $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  49007. }
  49008. if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  49009. return null;
  49010. }
  49011. $obj = &PEAR_Command::getObject($command);
  49012. return $obj->getGetoptArgs($command, $short_args, $long_args);
  49013. }
  49014. // }}}
  49015. // {{{ getDescription()
  49016. /**
  49017. * Get description for a command.
  49018. *
  49019. * @param string $command Name of the command
  49020. *
  49021. * @return string command description
  49022. */
  49023. public static function getDescription($command)
  49024. {
  49025. if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
  49026. return null;
  49027. }
  49028. return $GLOBALS['_PEAR_Command_commanddesc'][$command];
  49029. }
  49030. // }}}
  49031. // {{{ getHelp()
  49032. /**
  49033. * Get help for command.
  49034. *
  49035. * @param string $command Name of the command to return help for
  49036. */
  49037. public static function getHelp($command)
  49038. {
  49039. $cmds = PEAR_Command::getCommands();
  49040. if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  49041. $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  49042. }
  49043. if (isset($cmds[$command])) {
  49044. $obj = &PEAR_Command::getObject($command);
  49045. return $obj->getHelp($command);
  49046. }
  49047. return false;
  49048. }
  49049. // }}}
  49050. }�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Common.php������������������������������������������������������������������������0000644�0001750�0001750�00000063542�13565304531�014760� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  49051. /**
  49052. * PEAR_Common, the base class for the PEAR Installer
  49053. *
  49054. * PHP versions 4 and 5
  49055. *
  49056. * @category pear
  49057. * @package PEAR
  49058. * @author Stig Bakken <ssb@php.net>
  49059. * @author Tomas V. V. Cox <cox@idecnet.com>
  49060. * @author Greg Beaver <cellog@php.net>
  49061. * @copyright 1997-2009 The Authors
  49062. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  49063. * @link http://pear.php.net/package/PEAR
  49064. * @since File available since Release 0.1.0
  49065. * @deprecated File deprecated since Release 1.4.0a1
  49066. */
  49067. /**
  49068. * Include error handling
  49069. */
  49070. require_once 'PEAR.php';
  49071. /**
  49072. * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
  49073. */
  49074. define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
  49075. define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
  49076. define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/');
  49077. // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
  49078. define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
  49079. define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i');
  49080. // XXX far from perfect :-)
  49081. define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
  49082. ')(-([.0-9a-zA-Z]+))?');
  49083. define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
  49084. '\\z/');
  49085. define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
  49086. define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/');
  49087. // this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
  49088. define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
  49089. define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i');
  49090. define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
  49091. . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
  49092. define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i');
  49093. define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
  49094. . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
  49095. define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/');
  49096. /**
  49097. * List of temporary files and directories registered by
  49098. * PEAR_Common::addTempFile().
  49099. * @var array
  49100. */
  49101. $GLOBALS['_PEAR_Common_tempfiles'] = array();
  49102. /**
  49103. * Valid maintainer roles
  49104. * @var array
  49105. */
  49106. $GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
  49107. /**
  49108. * Valid release states
  49109. * @var array
  49110. */
  49111. $GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
  49112. /**
  49113. * Valid dependency types
  49114. * @var array
  49115. */
  49116. $GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
  49117. /**
  49118. * Valid dependency relations
  49119. * @var array
  49120. */
  49121. $GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
  49122. /**
  49123. * Valid file roles
  49124. * @var array
  49125. */
  49126. $GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
  49127. /**
  49128. * Valid replacement types
  49129. * @var array
  49130. */
  49131. $GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
  49132. /**
  49133. * Valid "provide" types
  49134. * @var array
  49135. */
  49136. $GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
  49137. /**
  49138. * Valid "provide" types
  49139. * @var array
  49140. */
  49141. $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
  49142. /**
  49143. * Class providing common functionality for PEAR administration classes.
  49144. * @category pear
  49145. * @package PEAR
  49146. * @author Stig Bakken <ssb@php.net>
  49147. * @author Tomas V. V. Cox <cox@idecnet.com>
  49148. * @author Greg Beaver <cellog@php.net>
  49149. * @copyright 1997-2009 The Authors
  49150. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  49151. * @version Release: 1.10.10
  49152. * @link http://pear.php.net/package/PEAR
  49153. * @since Class available since Release 1.4.0a1
  49154. * @deprecated This class will disappear, and its components will be spread
  49155. * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
  49156. */
  49157. class PEAR_Common extends PEAR
  49158. {
  49159. /**
  49160. * User Interface object (PEAR_Frontend_* class). If null,
  49161. * the log() method uses print.
  49162. * @var object
  49163. */
  49164. var $ui = null;
  49165. /**
  49166. * Configuration object (PEAR_Config).
  49167. * @var PEAR_Config
  49168. */
  49169. var $config = null;
  49170. /** stack of elements, gives some sort of XML context */
  49171. var $element_stack = array();
  49172. /** name of currently parsed XML element */
  49173. var $current_element;
  49174. /** array of attributes of the currently parsed XML element */
  49175. var $current_attributes = array();
  49176. /** assoc with information about a package */
  49177. var $pkginfo = array();
  49178. var $current_path = null;
  49179. /**
  49180. * Flag variable used to mark a valid package file
  49181. * @var boolean
  49182. * @access private
  49183. */
  49184. var $_validPackageFile;
  49185. /**
  49186. * PEAR_Common constructor
  49187. *
  49188. * @access public
  49189. */
  49190. function __construct()
  49191. {
  49192. parent::__construct();
  49193. $this->config = &PEAR_Config::singleton();
  49194. $this->debug = $this->config->get('verbose');
  49195. }
  49196. /**
  49197. * PEAR_Common destructor
  49198. *
  49199. * @access private
  49200. */
  49201. function _PEAR_Common()
  49202. {
  49203. // doesn't work due to bug #14744
  49204. //$tempfiles = $this->_tempfiles;
  49205. $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
  49206. while ($file = array_shift($tempfiles)) {
  49207. if (@is_dir($file)) {
  49208. if (!class_exists('System')) {
  49209. require_once 'System.php';
  49210. }
  49211. System::rm(array('-rf', $file));
  49212. } elseif (file_exists($file)) {
  49213. unlink($file);
  49214. }
  49215. }
  49216. }
  49217. /**
  49218. * Register a temporary file or directory. When the destructor is
  49219. * executed, all registered temporary files and directories are
  49220. * removed.
  49221. *
  49222. * @param string $file name of file or directory
  49223. *
  49224. * @return void
  49225. *
  49226. * @access public
  49227. */
  49228. static function addTempFile($file)
  49229. {
  49230. if (!class_exists('PEAR_Frontend')) {
  49231. require_once 'PEAR/Frontend.php';
  49232. }
  49233. PEAR_Frontend::addTempFile($file);
  49234. }
  49235. /**
  49236. * Wrapper to System::mkDir(), creates a directory as well as
  49237. * any necessary parent directories.
  49238. *
  49239. * @param string $dir directory name
  49240. *
  49241. * @return bool TRUE on success, or a PEAR error
  49242. *
  49243. * @access public
  49244. */
  49245. function mkDirHier($dir)
  49246. {
  49247. // Only used in Installer - move it there ?
  49248. $this->log(2, "+ create dir $dir");
  49249. if (!class_exists('System')) {
  49250. require_once 'System.php';
  49251. }
  49252. return System::mkDir(array('-p', $dir));
  49253. }
  49254. /**
  49255. * Logging method.
  49256. *
  49257. * @param int $level log level (0 is quiet, higher is noisier)
  49258. * @param string $msg message to write to the log
  49259. *
  49260. * @return void
  49261. */
  49262. public function log($level, $msg, $append_crlf = true)
  49263. {
  49264. if ($this->debug >= $level) {
  49265. if (!class_exists('PEAR_Frontend')) {
  49266. require_once 'PEAR/Frontend.php';
  49267. }
  49268. $ui = &PEAR_Frontend::singleton();
  49269. if (is_a($ui, 'PEAR_Frontend')) {
  49270. $ui->log($msg, $append_crlf);
  49271. } else {
  49272. print "$msg\n";
  49273. }
  49274. }
  49275. }
  49276. /**
  49277. * Create and register a temporary directory.
  49278. *
  49279. * @param string $tmpdir (optional) Directory to use as tmpdir.
  49280. * Will use system defaults (for example
  49281. * /tmp or c:\windows\temp) if not specified
  49282. *
  49283. * @return string name of created directory
  49284. *
  49285. * @access public
  49286. */
  49287. function mkTempDir($tmpdir = '')
  49288. {
  49289. $topt = $tmpdir ? array('-t', $tmpdir) : array();
  49290. $topt = array_merge($topt, array('-d', 'pear'));
  49291. if (!class_exists('System')) {
  49292. require_once 'System.php';
  49293. }
  49294. if (!$tmpdir = System::mktemp($topt)) {
  49295. return false;
  49296. }
  49297. self::addTempFile($tmpdir);
  49298. return $tmpdir;
  49299. }
  49300. /**
  49301. * Set object that represents the frontend to be used.
  49302. *
  49303. * @param object Reference of the frontend object
  49304. * @return void
  49305. * @access public
  49306. */
  49307. function setFrontendObject(&$ui)
  49308. {
  49309. $this->ui = &$ui;
  49310. }
  49311. /**
  49312. * Return an array containing all of the states that are more stable than
  49313. * or equal to the passed in state
  49314. *
  49315. * @param string Release state
  49316. * @param boolean Determines whether to include $state in the list
  49317. * @return false|array False if $state is not a valid release state
  49318. */
  49319. static function betterStates($state, $include = false)
  49320. {
  49321. static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  49322. $i = array_search($state, $states);
  49323. if ($i === false) {
  49324. return false;
  49325. }
  49326. if ($include) {
  49327. $i--;
  49328. }
  49329. return array_slice($states, $i + 1);
  49330. }
  49331. /**
  49332. * Get the valid roles for a PEAR package maintainer
  49333. *
  49334. * @return array
  49335. */
  49336. public static function getUserRoles()
  49337. {
  49338. return $GLOBALS['_PEAR_Common_maintainer_roles'];
  49339. }
  49340. /**
  49341. * Get the valid package release states of packages
  49342. *
  49343. * @return array
  49344. */
  49345. public static function getReleaseStates()
  49346. {
  49347. return $GLOBALS['_PEAR_Common_release_states'];
  49348. }
  49349. /**
  49350. * Get the implemented dependency types (php, ext, pkg etc.)
  49351. *
  49352. * @return array
  49353. */
  49354. public static function getDependencyTypes()
  49355. {
  49356. return $GLOBALS['_PEAR_Common_dependency_types'];
  49357. }
  49358. /**
  49359. * Get the implemented dependency relations (has, lt, ge etc.)
  49360. *
  49361. * @return array
  49362. */
  49363. public static function getDependencyRelations()
  49364. {
  49365. return $GLOBALS['_PEAR_Common_dependency_relations'];
  49366. }
  49367. /**
  49368. * Get the implemented file roles
  49369. *
  49370. * @return array
  49371. */
  49372. public static function getFileRoles()
  49373. {
  49374. return $GLOBALS['_PEAR_Common_file_roles'];
  49375. }
  49376. /**
  49377. * Get the implemented file replacement types in
  49378. *
  49379. * @return array
  49380. */
  49381. public static function getReplacementTypes()
  49382. {
  49383. return $GLOBALS['_PEAR_Common_replacement_types'];
  49384. }
  49385. /**
  49386. * Get the implemented file replacement types in
  49387. *
  49388. * @return array
  49389. */
  49390. public static function getProvideTypes()
  49391. {
  49392. return $GLOBALS['_PEAR_Common_provide_types'];
  49393. }
  49394. /**
  49395. * Get the implemented file replacement types in
  49396. *
  49397. * @return array
  49398. */
  49399. public static function getScriptPhases()
  49400. {
  49401. return $GLOBALS['_PEAR_Common_script_phases'];
  49402. }
  49403. /**
  49404. * Test whether a string contains a valid package name.
  49405. *
  49406. * @param string $name the package name to test
  49407. *
  49408. * @return bool
  49409. *
  49410. * @access public
  49411. */
  49412. function validPackageName($name)
  49413. {
  49414. return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
  49415. }
  49416. /**
  49417. * Test whether a string contains a valid package version.
  49418. *
  49419. * @param string $ver the package version to test
  49420. *
  49421. * @return bool
  49422. *
  49423. * @access public
  49424. */
  49425. function validPackageVersion($ver)
  49426. {
  49427. return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
  49428. }
  49429. /**
  49430. * @param string $path relative or absolute include path
  49431. * @return boolean
  49432. */
  49433. public static function isIncludeable($path)
  49434. {
  49435. if (file_exists($path) && is_readable($path)) {
  49436. return true;
  49437. }
  49438. $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
  49439. foreach ($ipath as $include) {
  49440. $test = realpath($include . DIRECTORY_SEPARATOR . $path);
  49441. if (file_exists($test) && is_readable($test)) {
  49442. return true;
  49443. }
  49444. }
  49445. return false;
  49446. }
  49447. function _postProcessChecks($pf)
  49448. {
  49449. if (!PEAR::isError($pf)) {
  49450. return $this->_postProcessValidPackagexml($pf);
  49451. }
  49452. $errs = $pf->getUserinfo();
  49453. if (is_array($errs)) {
  49454. foreach ($errs as $error) {
  49455. $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  49456. }
  49457. }
  49458. return $pf;
  49459. }
  49460. /**
  49461. * Returns information about a package file. Expects the name of
  49462. * a gzipped tar file as input.
  49463. *
  49464. * @param string $file name of .tgz file
  49465. *
  49466. * @return array array with package information
  49467. *
  49468. * @access public
  49469. * @deprecated use PEAR_PackageFile->fromTgzFile() instead
  49470. *
  49471. */
  49472. function infoFromTgzFile($file)
  49473. {
  49474. $packagefile = new PEAR_PackageFile($this->config);
  49475. $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
  49476. return $this->_postProcessChecks($pf);
  49477. }
  49478. /**
  49479. * Returns information about a package file. Expects the name of
  49480. * a package xml file as input.
  49481. *
  49482. * @param string $descfile name of package xml file
  49483. *
  49484. * @return array array with package information
  49485. *
  49486. * @access public
  49487. * @deprecated use PEAR_PackageFile->fromPackageFile() instead
  49488. *
  49489. */
  49490. function infoFromDescriptionFile($descfile)
  49491. {
  49492. $packagefile = new PEAR_PackageFile($this->config);
  49493. $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
  49494. return $this->_postProcessChecks($pf);
  49495. }
  49496. /**
  49497. * Returns information about a package file. Expects the contents
  49498. * of a package xml file as input.
  49499. *
  49500. * @param string $data contents of package.xml file
  49501. *
  49502. * @return array array with package information
  49503. *
  49504. * @access public
  49505. * @deprecated use PEAR_PackageFile->fromXmlstring() instead
  49506. *
  49507. */
  49508. function infoFromString($data)
  49509. {
  49510. $packagefile = new PEAR_PackageFile($this->config);
  49511. $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
  49512. return $this->_postProcessChecks($pf);
  49513. }
  49514. /**
  49515. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  49516. * @return array
  49517. */
  49518. function _postProcessValidPackagexml(&$pf)
  49519. {
  49520. if (!is_a($pf, 'PEAR_PackageFile_v2')) {
  49521. $this->pkginfo = $pf->toArray();
  49522. return $this->pkginfo;
  49523. }
  49524. // sort of make this into a package.xml 1.0-style array
  49525. // changelog is not converted to old format.
  49526. $arr = $pf->toArray(true);
  49527. $arr = array_merge($arr, $arr['old']);
  49528. unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'],
  49529. $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'],
  49530. $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'],
  49531. $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'],
  49532. $arr['helper'], $arr['contributor']);
  49533. $arr['filelist'] = $pf->getFilelist();
  49534. $this->pkginfo = $arr;
  49535. return $arr;
  49536. }
  49537. /**
  49538. * Returns package information from different sources
  49539. *
  49540. * This method is able to extract information about a package
  49541. * from a .tgz archive or from a XML package definition file.
  49542. *
  49543. * @access public
  49544. * @param string Filename of the source ('package.xml', '<package>.tgz')
  49545. * @return string
  49546. * @deprecated use PEAR_PackageFile->fromAnyFile() instead
  49547. */
  49548. function infoFromAny($info)
  49549. {
  49550. if (is_string($info) && file_exists($info)) {
  49551. $packagefile = new PEAR_PackageFile($this->config);
  49552. $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  49553. if (PEAR::isError($pf)) {
  49554. $errs = $pf->getUserinfo();
  49555. if (is_array($errs)) {
  49556. foreach ($errs as $error) {
  49557. $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  49558. }
  49559. }
  49560. return $pf;
  49561. }
  49562. return $this->_postProcessValidPackagexml($pf);
  49563. }
  49564. return $info;
  49565. }
  49566. /**
  49567. * Return an XML document based on the package info (as returned
  49568. * by the PEAR_Common::infoFrom* methods).
  49569. *
  49570. * @param array $pkginfo package info
  49571. *
  49572. * @return string XML data
  49573. *
  49574. * @access public
  49575. * @deprecated use a PEAR_PackageFile_v* object's generator instead
  49576. */
  49577. function xmlFromInfo($pkginfo)
  49578. {
  49579. $config = &PEAR_Config::singleton();
  49580. $packagefile = new PEAR_PackageFile($config);
  49581. $pf = &$packagefile->fromArray($pkginfo);
  49582. $gen = &$pf->getDefaultGenerator();
  49583. return $gen->toXml(PEAR_VALIDATE_PACKAGING);
  49584. }
  49585. /**
  49586. * Validate XML package definition file.
  49587. *
  49588. * @param string $info Filename of the package archive or of the
  49589. * package definition file
  49590. * @param array $errors Array that will contain the errors
  49591. * @param array $warnings Array that will contain the warnings
  49592. * @param string $dir_prefix (optional) directory where source files
  49593. * may be found, or empty if they are not available
  49594. * @access public
  49595. * @return boolean
  49596. * @deprecated use the validation of PEAR_PackageFile objects
  49597. */
  49598. function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
  49599. {
  49600. $config = &PEAR_Config::singleton();
  49601. $packagefile = new PEAR_PackageFile($config);
  49602. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  49603. if (strpos($info, '<?xml') !== false) {
  49604. $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
  49605. } else {
  49606. $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  49607. }
  49608. PEAR::staticPopErrorHandling();
  49609. if (PEAR::isError($pf)) {
  49610. $errs = $pf->getUserinfo();
  49611. if (is_array($errs)) {
  49612. foreach ($errs as $error) {
  49613. if ($error['level'] == 'error') {
  49614. $errors[] = $error['message'];
  49615. } else {
  49616. $warnings[] = $error['message'];
  49617. }
  49618. }
  49619. }
  49620. return false;
  49621. }
  49622. return true;
  49623. }
  49624. /**
  49625. * Build a "provides" array from data returned by
  49626. * analyzeSourceCode(). The format of the built array is like
  49627. * this:
  49628. *
  49629. * array(
  49630. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  49631. * ...
  49632. * )
  49633. *
  49634. *
  49635. * @param array $srcinfo array with information about a source file
  49636. * as returned by the analyzeSourceCode() method.
  49637. *
  49638. * @return void
  49639. *
  49640. * @access public
  49641. *
  49642. */
  49643. function buildProvidesArray($srcinfo)
  49644. {
  49645. $file = basename($srcinfo['source_file']);
  49646. $pn = '';
  49647. if (isset($this->_packageName)) {
  49648. $pn = $this->_packageName;
  49649. }
  49650. $pnl = strlen($pn);
  49651. foreach ($srcinfo['declared_classes'] as $class) {
  49652. $key = "class;$class";
  49653. if (isset($this->pkginfo['provides'][$key])) {
  49654. continue;
  49655. }
  49656. $this->pkginfo['provides'][$key] =
  49657. array('file'=> $file, 'type' => 'class', 'name' => $class);
  49658. if (isset($srcinfo['inheritance'][$class])) {
  49659. $this->pkginfo['provides'][$key]['extends'] =
  49660. $srcinfo['inheritance'][$class];
  49661. }
  49662. }
  49663. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  49664. foreach ($methods as $method) {
  49665. $function = "$class::$method";
  49666. $key = "function;$function";
  49667. if ($method[0] == '_' || !strcasecmp($method, $class) ||
  49668. isset($this->pkginfo['provides'][$key])) {
  49669. continue;
  49670. }
  49671. $this->pkginfo['provides'][$key] =
  49672. array('file'=> $file, 'type' => 'function', 'name' => $function);
  49673. }
  49674. }
  49675. foreach ($srcinfo['declared_functions'] as $function) {
  49676. $key = "function;$function";
  49677. if ($function[0] == '_' || isset($this->pkginfo['provides'][$key])) {
  49678. continue;
  49679. }
  49680. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  49681. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  49682. }
  49683. $this->pkginfo['provides'][$key] =
  49684. array('file'=> $file, 'type' => 'function', 'name' => $function);
  49685. }
  49686. }
  49687. /**
  49688. * Analyze the source code of the given PHP file
  49689. *
  49690. * @param string Filename of the PHP file
  49691. * @return mixed
  49692. * @access public
  49693. */
  49694. static function analyzeSourceCode($file)
  49695. {
  49696. if (!class_exists('PEAR_PackageFile_v2_Validator')) {
  49697. require_once 'PEAR/PackageFile/v2/Validator.php';
  49698. }
  49699. $a = new PEAR_PackageFile_v2_Validator;
  49700. return $a->analyzeSourceCode($file);
  49701. }
  49702. function detectDependencies($any, $status_callback = null)
  49703. {
  49704. if (!function_exists("token_get_all")) {
  49705. return false;
  49706. }
  49707. if (PEAR::isError($info = $this->infoFromAny($any))) {
  49708. return $this->raiseError($info);
  49709. }
  49710. if (!is_array($info)) {
  49711. return false;
  49712. }
  49713. $deps = array();
  49714. $used_c = $decl_c = $decl_f = $decl_m = array();
  49715. foreach ($info['filelist'] as $file => $fa) {
  49716. $tmp = $this->analyzeSourceCode($file);
  49717. $used_c = @array_merge($used_c, $tmp['used_classes']);
  49718. $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
  49719. $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
  49720. $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
  49721. $inheri = @array_merge($inheri, $tmp['inheritance']);
  49722. }
  49723. $used_c = array_unique($used_c);
  49724. $decl_c = array_unique($decl_c);
  49725. $undecl_c = array_diff($used_c, $decl_c);
  49726. return array('used_classes' => $used_c,
  49727. 'declared_classes' => $decl_c,
  49728. 'declared_methods' => $decl_m,
  49729. 'declared_functions' => $decl_f,
  49730. 'undeclared_classes' => $undecl_c,
  49731. 'inheritance' => $inheri,
  49732. );
  49733. }
  49734. /**
  49735. * Download a file through HTTP. Considers suggested file name in
  49736. * Content-disposition: header and can run a callback function for
  49737. * different events. The callback will be called with two
  49738. * parameters: the callback type, and parameters. The implemented
  49739. * callback types are:
  49740. *
  49741. * 'setup' called at the very beginning, parameter is a UI object
  49742. * that should be used for all output
  49743. * 'message' the parameter is a string with an informational message
  49744. * 'saveas' may be used to save with a different file name, the
  49745. * parameter is the filename that is about to be used.
  49746. * If a 'saveas' callback returns a non-empty string,
  49747. * that file name will be used as the filename instead.
  49748. * Note that $save_dir will not be affected by this, only
  49749. * the basename of the file.
  49750. * 'start' download is starting, parameter is number of bytes
  49751. * that are expected, or -1 if unknown
  49752. * 'bytesread' parameter is the number of bytes read so far
  49753. * 'done' download is complete, parameter is the total number
  49754. * of bytes read
  49755. * 'connfailed' if the TCP connection fails, this callback is called
  49756. * with array(host,port,errno,errmsg)
  49757. * 'writefailed' if writing to disk fails, this callback is called
  49758. * with array(destfile,errmsg)
  49759. *
  49760. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  49761. * setting), the proxy will be used.
  49762. *
  49763. * @param string $url the URL to download
  49764. * @param object $ui PEAR_Frontend_* instance
  49765. * @param object $config PEAR_Config instance
  49766. * @param string $save_dir (optional) directory to save file in
  49767. * @param mixed $callback (optional) function/method to call for status
  49768. * updates
  49769. * @param false|string|array $lastmodified header values to check against
  49770. * for caching
  49771. * use false to return the header
  49772. * values from this download
  49773. * @param false|array $accept Accept headers to send
  49774. * @param false|string $channel Channel to use for retrieving
  49775. * authentication
  49776. *
  49777. * @return mixed Returns the full path of the downloaded file or a PEAR
  49778. * error on failure. If the error is caused by
  49779. * socket-related errors, the error object will
  49780. * have the fsockopen error code available through
  49781. * getCode(). If caching is requested, then return the header
  49782. * values.
  49783. * If $lastmodified was given and the there are no changes,
  49784. * boolean false is returned.
  49785. *
  49786. * @access public
  49787. */
  49788. function downloadHttp(
  49789. $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
  49790. $accept = false, $channel = false
  49791. ) {
  49792. if (!class_exists('PEAR_Downloader')) {
  49793. require_once 'PEAR/Downloader.php';
  49794. }
  49795. return PEAR_Downloader::_downloadHttp(
  49796. $this, $url, $ui, $save_dir, $callback, $lastmodified,
  49797. $accept, $channel
  49798. );
  49799. }
  49800. }
  49801. require_once 'PEAR/Config.php';
  49802. require_once 'PEAR/PackageFile.php';
  49803. ��������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Config.php������������������������������������������������������������������������0000644�0001750�0001750�00000207551�13565304531�014735� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  49804. /**
  49805. * PEAR_Config, customized configuration handling for the PEAR Installer
  49806. *
  49807. * PHP versions 4 and 5
  49808. *
  49809. * @category pear
  49810. * @package PEAR
  49811. * @author Stig Bakken <ssb@php.net>
  49812. * @author Greg Beaver <cellog@php.net>
  49813. * @copyright 1997-2009 The Authors
  49814. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  49815. * @link http://pear.php.net/package/PEAR
  49816. * @since File available since Release 0.1
  49817. */
  49818. /**
  49819. * Required for error handling
  49820. */
  49821. require_once 'PEAR.php';
  49822. require_once 'PEAR/Registry.php';
  49823. require_once 'PEAR/Installer/Role.php';
  49824. require_once 'System.php';
  49825. /**
  49826. * Last created PEAR_Config instance.
  49827. * @var object
  49828. */
  49829. $GLOBALS['_PEAR_Config_instance'] = null;
  49830. if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
  49831. $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
  49832. } else {
  49833. $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
  49834. }
  49835. // Below we define constants with default values for all configuration
  49836. // parameters except username/password. All of them can have their
  49837. // defaults set through environment variables. The reason we use the
  49838. // PHP_ prefix is for some security, PHP protects environment
  49839. // variables starting with PHP_*.
  49840. // default channel and preferred mirror is based on whether we are invoked through
  49841. // the "pear" or the "pecl" command
  49842. if (!defined('PEAR_RUNTYPE')) {
  49843. define('PEAR_RUNTYPE', 'pear');
  49844. }
  49845. if (PEAR_RUNTYPE == 'pear') {
  49846. define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
  49847. } else {
  49848. define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
  49849. }
  49850. if (getenv('PHP_PEAR_SYSCONF_DIR')) {
  49851. define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
  49852. } elseif (getenv('SystemRoot')) {
  49853. define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
  49854. } else {
  49855. define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
  49856. }
  49857. // Default for master_server
  49858. if (getenv('PHP_PEAR_MASTER_SERVER')) {
  49859. define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
  49860. } else {
  49861. define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
  49862. }
  49863. // Default for http_proxy
  49864. if (getenv('PHP_PEAR_HTTP_PROXY')) {
  49865. define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
  49866. } elseif (getenv('http_proxy')) {
  49867. define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
  49868. } else {
  49869. define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
  49870. }
  49871. // Default for php_dir
  49872. if (getenv('PHP_PEAR_INSTALL_DIR')) {
  49873. define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
  49874. } else {
  49875. if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
  49876. define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
  49877. } else {
  49878. define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
  49879. }
  49880. }
  49881. // Default for metadata_dir
  49882. if (getenv('PHP_PEAR_METADATA_DIR')) {
  49883. define('PEAR_CONFIG_DEFAULT_METADATA_DIR', getenv('PHP_PEAR_METADATA_DIR'));
  49884. } else {
  49885. define('PEAR_CONFIG_DEFAULT_METADATA_DIR', '');
  49886. }
  49887. // Default for ext_dir
  49888. if (getenv('PHP_PEAR_EXTENSION_DIR')) {
  49889. define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
  49890. } else {
  49891. if (ini_get('extension_dir')) {
  49892. define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
  49893. } elseif (defined('PEAR_EXTENSION_DIR') &&
  49894. file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
  49895. define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
  49896. } elseif (defined('PHP_EXTENSION_DIR')) {
  49897. define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
  49898. } else {
  49899. define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
  49900. }
  49901. }
  49902. // Default for doc_dir
  49903. if (getenv('PHP_PEAR_DOC_DIR')) {
  49904. define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
  49905. } else {
  49906. define('PEAR_CONFIG_DEFAULT_DOC_DIR',
  49907. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
  49908. }
  49909. // Default for bin_dir
  49910. if (getenv('PHP_PEAR_BIN_DIR')) {
  49911. define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
  49912. } else {
  49913. define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
  49914. }
  49915. // Default for data_dir
  49916. if (getenv('PHP_PEAR_DATA_DIR')) {
  49917. define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
  49918. } else {
  49919. define('PEAR_CONFIG_DEFAULT_DATA_DIR',
  49920. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
  49921. }
  49922. // Default for cfg_dir
  49923. if (getenv('PHP_PEAR_CFG_DIR')) {
  49924. define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
  49925. } else {
  49926. define('PEAR_CONFIG_DEFAULT_CFG_DIR',
  49927. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
  49928. }
  49929. // Default for www_dir
  49930. if (getenv('PHP_PEAR_WWW_DIR')) {
  49931. define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
  49932. } else {
  49933. define('PEAR_CONFIG_DEFAULT_WWW_DIR',
  49934. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
  49935. }
  49936. // Default for man_dir
  49937. if (getenv('PHP_PEAR_MAN_DIR')) {
  49938. define('PEAR_CONFIG_DEFAULT_MAN_DIR', getenv('PHP_PEAR_MAN_DIR'));
  49939. } else {
  49940. if (defined('PHP_MANDIR')) { // Added in PHP5.3.7
  49941. define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_MANDIR);
  49942. } else {
  49943. define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_PREFIX . DIRECTORY_SEPARATOR .
  49944. 'local' . DIRECTORY_SEPARATOR .'man');
  49945. }
  49946. }
  49947. // Default for test_dir
  49948. if (getenv('PHP_PEAR_TEST_DIR')) {
  49949. define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
  49950. } else {
  49951. define('PEAR_CONFIG_DEFAULT_TEST_DIR',
  49952. $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
  49953. }
  49954. // Default for temp_dir
  49955. if (getenv('PHP_PEAR_TEMP_DIR')) {
  49956. define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
  49957. } else {
  49958. define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
  49959. System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  49960. DIRECTORY_SEPARATOR . 'temp');
  49961. }
  49962. // Default for cache_dir
  49963. if (getenv('PHP_PEAR_CACHE_DIR')) {
  49964. define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
  49965. } else {
  49966. define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
  49967. System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  49968. DIRECTORY_SEPARATOR . 'cache');
  49969. }
  49970. // Default for download_dir
  49971. if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
  49972. define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
  49973. } else {
  49974. define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
  49975. System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  49976. DIRECTORY_SEPARATOR . 'download');
  49977. }
  49978. // Default for php_bin
  49979. if (getenv('PHP_PEAR_PHP_BIN')) {
  49980. define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
  49981. } else {
  49982. define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
  49983. DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
  49984. }
  49985. // Default for verbose
  49986. if (getenv('PHP_PEAR_VERBOSE')) {
  49987. define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
  49988. } else {
  49989. define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
  49990. }
  49991. // Default for preferred_state
  49992. if (getenv('PHP_PEAR_PREFERRED_STATE')) {
  49993. define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
  49994. } else {
  49995. define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
  49996. }
  49997. // Default for umask
  49998. if (getenv('PHP_PEAR_UMASK')) {
  49999. define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
  50000. } else {
  50001. define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
  50002. }
  50003. // Default for cache_ttl
  50004. if (getenv('PHP_PEAR_CACHE_TTL')) {
  50005. define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
  50006. } else {
  50007. define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
  50008. }
  50009. // Default for sig_type
  50010. if (getenv('PHP_PEAR_SIG_TYPE')) {
  50011. define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
  50012. } else {
  50013. define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
  50014. }
  50015. // Default for sig_bin
  50016. if (getenv('PHP_PEAR_SIG_BIN')) {
  50017. define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
  50018. } else {
  50019. define('PEAR_CONFIG_DEFAULT_SIG_BIN',
  50020. System::which(
  50021. 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
  50022. }
  50023. // Default for sig_keydir
  50024. if (getenv('PHP_PEAR_SIG_KEYDIR')) {
  50025. define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
  50026. } else {
  50027. define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
  50028. PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
  50029. }
  50030. /**
  50031. * This is a class for storing configuration data, keeping track of
  50032. * which are system-defined, user-defined or defaulted.
  50033. * @category pear
  50034. * @package PEAR
  50035. * @author Stig Bakken <ssb@php.net>
  50036. * @author Greg Beaver <cellog@php.net>
  50037. * @copyright 1997-2009 The Authors
  50038. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  50039. * @version Release: 1.10.10
  50040. * @link http://pear.php.net/package/PEAR
  50041. * @since Class available since Release 0.1
  50042. */
  50043. class PEAR_Config extends PEAR
  50044. {
  50045. /**
  50046. * Array of config files used.
  50047. *
  50048. * @var array layer => config file
  50049. */
  50050. var $files = array(
  50051. 'system' => '',
  50052. 'user' => '',
  50053. );
  50054. var $layers = array();
  50055. /**
  50056. * Configuration data, two-dimensional array where the first
  50057. * dimension is the config layer ('user', 'system' and 'default'),
  50058. * and the second dimension is keyname => value.
  50059. *
  50060. * The order in the first dimension is important! Earlier
  50061. * layers will shadow later ones when a config value is
  50062. * requested (if a 'user' value exists, it will be returned first,
  50063. * then 'system' and finally 'default').
  50064. *
  50065. * @var array layer => array(keyname => value, ...)
  50066. */
  50067. var $configuration = array(
  50068. 'user' => array(),
  50069. 'system' => array(),
  50070. 'default' => array(),
  50071. );
  50072. /**
  50073. * Configuration values that can be set for a channel
  50074. *
  50075. * All other configuration values can only have a global value
  50076. * @var array
  50077. * @access private
  50078. */
  50079. var $_channelConfigInfo = array(
  50080. 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir',
  50081. 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username',
  50082. 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini'
  50083. );
  50084. /**
  50085. * Channels that can be accessed
  50086. * @see setChannels()
  50087. * @var array
  50088. * @access private
  50089. */
  50090. var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
  50091. /**
  50092. * This variable is used to control the directory values returned
  50093. * @see setInstallRoot();
  50094. * @var string|false
  50095. * @access private
  50096. */
  50097. var $_installRoot = false;
  50098. /**
  50099. * If requested, this will always refer to the registry
  50100. * contained in php_dir
  50101. * @var PEAR_Registry
  50102. */
  50103. var $_registry = array();
  50104. /**
  50105. * @var array
  50106. * @access private
  50107. */
  50108. var $_regInitialized = array();
  50109. /**
  50110. * @var bool
  50111. * @access private
  50112. */
  50113. var $_noRegistry = false;
  50114. /**
  50115. * amount of errors found while parsing config
  50116. * @var integer
  50117. * @access private
  50118. */
  50119. var $_errorsFound = 0;
  50120. var $_lastError = null;
  50121. /**
  50122. * Information about the configuration data. Stores the type,
  50123. * default value and a documentation string for each configuration
  50124. * value.
  50125. *
  50126. * @var array layer => array(infotype => value, ...)
  50127. */
  50128. var $configuration_info = array(
  50129. // Channels/Internet Access
  50130. 'default_channel' => array(
  50131. 'type' => 'string',
  50132. 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  50133. 'doc' => 'the default channel to use for all non explicit commands',
  50134. 'prompt' => 'Default Channel',
  50135. 'group' => 'Internet Access',
  50136. ),
  50137. 'preferred_mirror' => array(
  50138. 'type' => 'string',
  50139. 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  50140. 'doc' => 'the default server or mirror to use for channel actions',
  50141. 'prompt' => 'Default Channel Mirror',
  50142. 'group' => 'Internet Access',
  50143. ),
  50144. 'remote_config' => array(
  50145. 'type' => 'password',
  50146. 'default' => '',
  50147. 'doc' => 'ftp url of remote configuration file to use for synchronized install',
  50148. 'prompt' => 'Remote Configuration File',
  50149. 'group' => 'Internet Access',
  50150. ),
  50151. 'auto_discover' => array(
  50152. 'type' => 'integer',
  50153. 'default' => 0,
  50154. 'doc' => 'whether to automatically discover new channels',
  50155. 'prompt' => 'Auto-discover new Channels',
  50156. 'group' => 'Internet Access',
  50157. ),
  50158. // Internet Access
  50159. 'master_server' => array(
  50160. 'type' => 'string',
  50161. 'default' => 'pear.php.net',
  50162. 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
  50163. 'prompt' => 'PEAR server [DEPRECATED]',
  50164. 'group' => 'Internet Access',
  50165. ),
  50166. 'http_proxy' => array(
  50167. 'type' => 'string',
  50168. 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
  50169. 'doc' => 'HTTP proxy (host:port) to use when downloading packages',
  50170. 'prompt' => 'HTTP Proxy Server Address',
  50171. 'group' => 'Internet Access',
  50172. ),
  50173. // File Locations
  50174. 'php_dir' => array(
  50175. 'type' => 'directory',
  50176. 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
  50177. 'doc' => 'directory where .php files are installed',
  50178. 'prompt' => 'PEAR directory',
  50179. 'group' => 'File Locations',
  50180. ),
  50181. 'ext_dir' => array(
  50182. 'type' => 'directory',
  50183. 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
  50184. 'doc' => 'directory where loadable extensions are installed',
  50185. 'prompt' => 'PHP extension directory',
  50186. 'group' => 'File Locations',
  50187. ),
  50188. 'doc_dir' => array(
  50189. 'type' => 'directory',
  50190. 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
  50191. 'doc' => 'directory where documentation is installed',
  50192. 'prompt' => 'PEAR documentation directory',
  50193. 'group' => 'File Locations',
  50194. ),
  50195. 'bin_dir' => array(
  50196. 'type' => 'directory',
  50197. 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
  50198. 'doc' => 'directory where executables are installed',
  50199. 'prompt' => 'PEAR executables directory',
  50200. 'group' => 'File Locations',
  50201. ),
  50202. 'data_dir' => array(
  50203. 'type' => 'directory',
  50204. 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
  50205. 'doc' => 'directory where data files are installed',
  50206. 'prompt' => 'PEAR data directory',
  50207. 'group' => 'File Locations (Advanced)',
  50208. ),
  50209. 'cfg_dir' => array(
  50210. 'type' => 'directory',
  50211. 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR,
  50212. 'doc' => 'directory where modifiable configuration files are installed',
  50213. 'prompt' => 'PEAR configuration file directory',
  50214. 'group' => 'File Locations (Advanced)',
  50215. ),
  50216. 'www_dir' => array(
  50217. 'type' => 'directory',
  50218. 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR,
  50219. 'doc' => 'directory where www frontend files (html/js) are installed',
  50220. 'prompt' => 'PEAR www files directory',
  50221. 'group' => 'File Locations (Advanced)',
  50222. ),
  50223. 'man_dir' => array(
  50224. 'type' => 'directory',
  50225. 'default' => PEAR_CONFIG_DEFAULT_MAN_DIR,
  50226. 'doc' => 'directory where unix manual pages are installed',
  50227. 'prompt' => 'Systems manpage files directory',
  50228. 'group' => 'File Locations (Advanced)',
  50229. ),
  50230. 'test_dir' => array(
  50231. 'type' => 'directory',
  50232. 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
  50233. 'doc' => 'directory where regression tests are installed',
  50234. 'prompt' => 'PEAR test directory',
  50235. 'group' => 'File Locations (Advanced)',
  50236. ),
  50237. 'cache_dir' => array(
  50238. 'type' => 'directory',
  50239. 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
  50240. 'doc' => 'directory which is used for web service cache',
  50241. 'prompt' => 'PEAR Installer cache directory',
  50242. 'group' => 'File Locations (Advanced)',
  50243. ),
  50244. 'temp_dir' => array(
  50245. 'type' => 'directory',
  50246. 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
  50247. 'doc' => 'directory which is used for all temp files',
  50248. 'prompt' => 'PEAR Installer temp directory',
  50249. 'group' => 'File Locations (Advanced)',
  50250. ),
  50251. 'download_dir' => array(
  50252. 'type' => 'directory',
  50253. 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR,
  50254. 'doc' => 'directory which is used for all downloaded files',
  50255. 'prompt' => 'PEAR Installer download directory',
  50256. 'group' => 'File Locations (Advanced)',
  50257. ),
  50258. 'php_bin' => array(
  50259. 'type' => 'file',
  50260. 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
  50261. 'doc' => 'PHP CLI/CGI binary for executing scripts',
  50262. 'prompt' => 'PHP CLI/CGI binary',
  50263. 'group' => 'File Locations (Advanced)',
  50264. ),
  50265. 'php_prefix' => array(
  50266. 'type' => 'string',
  50267. 'default' => '',
  50268. 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs',
  50269. 'prompt' => '--program-prefix passed to PHP\'s ./configure',
  50270. 'group' => 'File Locations (Advanced)',
  50271. ),
  50272. 'php_suffix' => array(
  50273. 'type' => 'string',
  50274. 'default' => '',
  50275. 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs',
  50276. 'prompt' => '--program-suffix passed to PHP\'s ./configure',
  50277. 'group' => 'File Locations (Advanced)',
  50278. ),
  50279. 'php_ini' => array(
  50280. 'type' => 'file',
  50281. 'default' => '',
  50282. 'doc' => 'location of php.ini in which to enable PECL extensions on install',
  50283. 'prompt' => 'php.ini location',
  50284. 'group' => 'File Locations (Advanced)',
  50285. ),
  50286. 'metadata_dir' => array(
  50287. 'type' => 'directory',
  50288. 'default' => PEAR_CONFIG_DEFAULT_METADATA_DIR,
  50289. 'doc' => 'directory where metadata files are installed (registry, filemap, channels, ...)',
  50290. 'prompt' => 'PEAR metadata directory',
  50291. 'group' => 'File Locations (Advanced)',
  50292. ),
  50293. // Maintainers
  50294. 'username' => array(
  50295. 'type' => 'string',
  50296. 'default' => '',
  50297. 'doc' => '(maintainers) your PEAR account name',
  50298. 'prompt' => 'PEAR username (for maintainers)',
  50299. 'group' => 'Maintainers',
  50300. ),
  50301. 'password' => array(
  50302. 'type' => 'password',
  50303. 'default' => '',
  50304. 'doc' => '(maintainers) your PEAR account password',
  50305. 'prompt' => 'PEAR password (for maintainers)',
  50306. 'group' => 'Maintainers',
  50307. ),
  50308. // Advanced
  50309. 'verbose' => array(
  50310. 'type' => 'integer',
  50311. 'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
  50312. 'doc' => 'verbosity level
  50313. 0: really quiet
  50314. 1: somewhat quiet
  50315. 2: verbose
  50316. 3: debug',
  50317. 'prompt' => 'Debug Log Level',
  50318. 'group' => 'Advanced',
  50319. ),
  50320. 'preferred_state' => array(
  50321. 'type' => 'set',
  50322. 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
  50323. 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
  50324. 'valid_set' => array(
  50325. 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
  50326. 'prompt' => 'Preferred Package State',
  50327. 'group' => 'Advanced',
  50328. ),
  50329. 'umask' => array(
  50330. 'type' => 'mask',
  50331. 'default' => PEAR_CONFIG_DEFAULT_UMASK,
  50332. 'doc' => 'umask used when creating files (Unix-like systems only)',
  50333. 'prompt' => 'Unix file mask',
  50334. 'group' => 'Advanced',
  50335. ),
  50336. 'cache_ttl' => array(
  50337. 'type' => 'integer',
  50338. 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
  50339. 'doc' => 'amount of secs where the local cache is used and not updated',
  50340. 'prompt' => 'Cache TimeToLive',
  50341. 'group' => 'Advanced',
  50342. ),
  50343. 'sig_type' => array(
  50344. 'type' => 'set',
  50345. 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
  50346. 'doc' => 'which package signature mechanism to use',
  50347. 'valid_set' => array('gpg'),
  50348. 'prompt' => 'Package Signature Type',
  50349. 'group' => 'Maintainers',
  50350. ),
  50351. 'sig_bin' => array(
  50352. 'type' => 'string',
  50353. 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
  50354. 'doc' => 'which package signature mechanism to use',
  50355. 'prompt' => 'Signature Handling Program',
  50356. 'group' => 'Maintainers',
  50357. ),
  50358. 'sig_keyid' => array(
  50359. 'type' => 'string',
  50360. 'default' => '',
  50361. 'doc' => 'which key to use for signing with',
  50362. 'prompt' => 'Signature Key Id',
  50363. 'group' => 'Maintainers',
  50364. ),
  50365. 'sig_keydir' => array(
  50366. 'type' => 'directory',
  50367. 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
  50368. 'doc' => 'directory where signature keys are located',
  50369. 'prompt' => 'Signature Key Directory',
  50370. 'group' => 'Maintainers',
  50371. ),
  50372. // __channels is reserved - used for channel-specific configuration
  50373. );
  50374. /**
  50375. * Constructor.
  50376. *
  50377. * @param string file to read user-defined options from
  50378. * @param string file to read system-wide defaults from
  50379. * @param bool determines whether a registry object "follows"
  50380. * the value of php_dir (is automatically created
  50381. * and moved when php_dir is changed)
  50382. * @param bool if true, fails if configuration files cannot be loaded
  50383. *
  50384. * @access public
  50385. *
  50386. * @see PEAR_Config::singleton
  50387. */
  50388. function __construct($user_file = '', $system_file = '', $ftp_file = false,
  50389. $strict = true)
  50390. {
  50391. parent::__construct();
  50392. PEAR_Installer_Role::initializeConfig($this);
  50393. $sl = DIRECTORY_SEPARATOR;
  50394. if (empty($user_file)) {
  50395. if (OS_WINDOWS) {
  50396. $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
  50397. } else {
  50398. $user_file = getenv('HOME') . $sl . '.pearrc';
  50399. }
  50400. }
  50401. if (empty($system_file)) {
  50402. $system_file = PEAR_CONFIG_SYSCONFDIR . $sl;
  50403. if (OS_WINDOWS) {
  50404. $system_file .= 'pearsys.ini';
  50405. } else {
  50406. $system_file .= 'pear.conf';
  50407. }
  50408. }
  50409. $this->layers = array_keys($this->configuration);
  50410. $this->files['user'] = $user_file;
  50411. $this->files['system'] = $system_file;
  50412. if ($user_file && file_exists($user_file)) {
  50413. $this->pushErrorHandling(PEAR_ERROR_RETURN);
  50414. $this->readConfigFile($user_file, 'user', $strict);
  50415. $this->popErrorHandling();
  50416. if ($this->_errorsFound > 0) {
  50417. return;
  50418. }
  50419. }
  50420. if ($system_file && @file_exists($system_file)) {
  50421. $this->mergeConfigFile($system_file, false, 'system', $strict);
  50422. if ($this->_errorsFound > 0) {
  50423. return;
  50424. }
  50425. }
  50426. if (!$ftp_file) {
  50427. $ftp_file = $this->get('remote_config');
  50428. }
  50429. if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
  50430. $this->readFTPConfigFile($ftp_file);
  50431. }
  50432. foreach ($this->configuration_info as $key => $info) {
  50433. $this->configuration['default'][$key] = $info['default'];
  50434. }
  50435. $this->_registry['default'] = new PEAR_Registry(
  50436. $this->configuration['default']['php_dir'], false, false,
  50437. $this->configuration['default']['metadata_dir']);
  50438. $this->_registry['default']->setConfig($this, false);
  50439. $this->_regInitialized['default'] = false;
  50440. //$GLOBALS['_PEAR_Config_instance'] = &$this;
  50441. }
  50442. /**
  50443. * Return the default locations of user and system configuration files
  50444. */
  50445. public static function getDefaultConfigFiles()
  50446. {
  50447. $sl = DIRECTORY_SEPARATOR;
  50448. if (OS_WINDOWS) {
  50449. return array(
  50450. 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
  50451. 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
  50452. );
  50453. }
  50454. return array(
  50455. 'user' => getenv('HOME') . $sl . '.pearrc',
  50456. 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
  50457. );
  50458. }
  50459. /**
  50460. * Static singleton method. If you want to keep only one instance
  50461. * of this class in use, this method will give you a reference to
  50462. * the last created PEAR_Config object if one exists, or create a
  50463. * new object.
  50464. *
  50465. * @param string (optional) file to read user-defined options from
  50466. * @param string (optional) file to read system-wide defaults from
  50467. *
  50468. * @return object an existing or new PEAR_Config instance
  50469. *
  50470. * @see PEAR_Config::PEAR_Config
  50471. */
  50472. public static function &singleton($user_file = '', $system_file = '', $strict = true)
  50473. {
  50474. if (is_object($GLOBALS['_PEAR_Config_instance'])) {
  50475. return $GLOBALS['_PEAR_Config_instance'];
  50476. }
  50477. $t_conf = new PEAR_Config($user_file, $system_file, false, $strict);
  50478. if ($t_conf->_errorsFound > 0) {
  50479. return $t_conf->lastError;
  50480. }
  50481. $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
  50482. return $GLOBALS['_PEAR_Config_instance'];
  50483. }
  50484. /**
  50485. * Determine whether any configuration files have been detected, and whether a
  50486. * registry object can be retrieved from this configuration.
  50487. * @return bool
  50488. * @since PEAR 1.4.0a1
  50489. */
  50490. function validConfiguration()
  50491. {
  50492. if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
  50493. return true;
  50494. }
  50495. return false;
  50496. }
  50497. /**
  50498. * Reads configuration data from a file. All existing values in
  50499. * the config layer are discarded and replaced with data from the
  50500. * file.
  50501. * @param string file to read from, if NULL or not specified, the
  50502. * last-used file for the same layer (second param) is used
  50503. * @param string config layer to insert data into ('user' or 'system')
  50504. * @return bool TRUE on success or a PEAR error on failure
  50505. */
  50506. function readConfigFile($file = null, $layer = 'user', $strict = true)
  50507. {
  50508. if (empty($this->files[$layer])) {
  50509. return $this->raiseError("unknown config layer `$layer'");
  50510. }
  50511. if ($file === null) {
  50512. $file = $this->files[$layer];
  50513. }
  50514. $data = $this->_readConfigDataFrom($file);
  50515. if (PEAR::isError($data)) {
  50516. if (!$strict) {
  50517. return true;
  50518. }
  50519. $this->_errorsFound++;
  50520. $this->lastError = $data;
  50521. return $data;
  50522. }
  50523. $this->files[$layer] = $file;
  50524. $this->_decodeInput($data);
  50525. $this->configuration[$layer] = $data;
  50526. $this->_setupChannels();
  50527. if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  50528. $this->_registry[$layer] = new PEAR_Registry(
  50529. $phpdir, false, false,
  50530. $this->get('metadata_dir', $layer, 'pear.php.net'));
  50531. $this->_registry[$layer]->setConfig($this, false);
  50532. $this->_regInitialized[$layer] = false;
  50533. } else {
  50534. unset($this->_registry[$layer]);
  50535. }
  50536. return true;
  50537. }
  50538. /**
  50539. * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
  50540. * @return true|PEAR_Error
  50541. */
  50542. function readFTPConfigFile($path)
  50543. {
  50544. do { // poor man's try
  50545. if (!class_exists('PEAR_FTP')) {
  50546. if (!class_exists('PEAR_Common')) {
  50547. require_once 'PEAR/Common.php';
  50548. }
  50549. if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
  50550. require_once 'PEAR/FTP.php';
  50551. }
  50552. }
  50553. if (!class_exists('PEAR_FTP')) {
  50554. return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
  50555. }
  50556. $this->_ftp = new PEAR_FTP;
  50557. $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
  50558. $e = $this->_ftp->init($path);
  50559. if (PEAR::isError($e)) {
  50560. $this->_ftp->popErrorHandling();
  50561. return $e;
  50562. }
  50563. $tmp = System::mktemp('-d');
  50564. PEAR_Common::addTempFile($tmp);
  50565. $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
  50566. 'pear.ini', false, FTP_BINARY);
  50567. if (PEAR::isError($e)) {
  50568. $this->_ftp->popErrorHandling();
  50569. return $e;
  50570. }
  50571. PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
  50572. $this->_ftp->disconnect();
  50573. $this->_ftp->popErrorHandling();
  50574. $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
  50575. $e = $this->readConfigFile(null, 'ftp');
  50576. if (PEAR::isError($e)) {
  50577. return $e;
  50578. }
  50579. $fail = array();
  50580. foreach ($this->configuration_info as $key => $val) {
  50581. if (in_array($this->getGroup($key),
  50582. array('File Locations', 'File Locations (Advanced)')) &&
  50583. $this->getType($key) == 'directory') {
  50584. // any directory configs must be set for this to work
  50585. if (!isset($this->configuration['ftp'][$key])) {
  50586. $fail[] = $key;
  50587. }
  50588. }
  50589. }
  50590. if (!count($fail)) {
  50591. return true;
  50592. }
  50593. $fail = '"' . implode('", "', $fail) . '"';
  50594. unset($this->files['ftp']);
  50595. unset($this->configuration['ftp']);
  50596. return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
  50597. 'directory configuration variables. These variables were not set: ' .
  50598. $fail);
  50599. } while (false); // poor man's catch
  50600. unset($this->files['ftp']);
  50601. return PEAR::raiseError('no remote host specified');
  50602. }
  50603. /**
  50604. * Reads the existing configurations and creates the _channels array from it
  50605. */
  50606. function _setupChannels()
  50607. {
  50608. $set = array_flip(array_values($this->_channels));
  50609. foreach ($this->configuration as $layer => $data) {
  50610. $i = 1000;
  50611. if (isset($data['__channels']) && is_array($data['__channels'])) {
  50612. foreach ($data['__channels'] as $channel => $info) {
  50613. $set[$channel] = $i++;
  50614. }
  50615. }
  50616. }
  50617. $this->_channels = array_values(array_flip($set));
  50618. $this->setChannels($this->_channels);
  50619. }
  50620. function deleteChannel($channel)
  50621. {
  50622. $ch = strtolower($channel);
  50623. foreach ($this->configuration as $layer => $data) {
  50624. if (isset($data['__channels']) && isset($data['__channels'][$ch])) {
  50625. unset($this->configuration[$layer]['__channels'][$ch]);
  50626. }
  50627. }
  50628. $this->_channels = array_flip($this->_channels);
  50629. unset($this->_channels[$ch]);
  50630. $this->_channels = array_flip($this->_channels);
  50631. }
  50632. /**
  50633. * Merges data into a config layer from a file. Does the same
  50634. * thing as readConfigFile, except it does not replace all
  50635. * existing values in the config layer.
  50636. * @param string file to read from
  50637. * @param bool whether to overwrite existing data (default TRUE)
  50638. * @param string config layer to insert data into ('user' or 'system')
  50639. * @param string if true, errors are returned if file opening fails
  50640. * @return bool TRUE on success or a PEAR error on failure
  50641. */
  50642. function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
  50643. {
  50644. if (empty($this->files[$layer])) {
  50645. return $this->raiseError("unknown config layer `$layer'");
  50646. }
  50647. if ($file === null) {
  50648. $file = $this->files[$layer];
  50649. }
  50650. $data = $this->_readConfigDataFrom($file);
  50651. if (PEAR::isError($data)) {
  50652. if (!$strict) {
  50653. return true;
  50654. }
  50655. $this->_errorsFound++;
  50656. $this->lastError = $data;
  50657. return $data;
  50658. }
  50659. $this->_decodeInput($data);
  50660. if ($override) {
  50661. $this->configuration[$layer] =
  50662. PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
  50663. } else {
  50664. $this->configuration[$layer] =
  50665. PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
  50666. }
  50667. $this->_setupChannels();
  50668. if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  50669. $this->_registry[$layer] = new PEAR_Registry(
  50670. $phpdir, false, false,
  50671. $this->get('metadata_dir', $layer, 'pear.php.net'));
  50672. $this->_registry[$layer]->setConfig($this, false);
  50673. $this->_regInitialized[$layer] = false;
  50674. } else {
  50675. unset($this->_registry[$layer]);
  50676. }
  50677. return true;
  50678. }
  50679. /**
  50680. * @param array
  50681. * @param array
  50682. * @return array
  50683. */
  50684. public static function arrayMergeRecursive($arr2, $arr1)
  50685. {
  50686. $ret = array();
  50687. foreach ($arr2 as $key => $data) {
  50688. if (!isset($arr1[$key])) {
  50689. $ret[$key] = $data;
  50690. unset($arr1[$key]);
  50691. continue;
  50692. }
  50693. if (is_array($data)) {
  50694. if (!is_array($arr1[$key])) {
  50695. $ret[$key] = $arr1[$key];
  50696. unset($arr1[$key]);
  50697. continue;
  50698. }
  50699. $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
  50700. unset($arr1[$key]);
  50701. }
  50702. }
  50703. return array_merge($ret, $arr1);
  50704. }
  50705. /**
  50706. * Writes data into a config layer from a file.
  50707. *
  50708. * @param string|null file to read from, or null for default
  50709. * @param string config layer to insert data into ('user' or
  50710. * 'system')
  50711. * @param string|null data to write to config file or null for internal data [DEPRECATED]
  50712. * @return bool TRUE on success or a PEAR error on failure
  50713. */
  50714. function writeConfigFile($file = null, $layer = 'user', $data = null)
  50715. {
  50716. $this->_lazyChannelSetup($layer);
  50717. if ($layer == 'both' || $layer == 'all') {
  50718. foreach ($this->files as $type => $file) {
  50719. $err = $this->writeConfigFile($file, $type, $data);
  50720. if (PEAR::isError($err)) {
  50721. return $err;
  50722. }
  50723. }
  50724. return true;
  50725. }
  50726. if (empty($this->files[$layer])) {
  50727. return $this->raiseError("unknown config file type `$layer'");
  50728. }
  50729. if ($file === null) {
  50730. $file = $this->files[$layer];
  50731. }
  50732. $data = ($data === null) ? $this->configuration[$layer] : $data;
  50733. $this->_encodeOutput($data);
  50734. $opt = array('-p', dirname($file));
  50735. if (!@System::mkDir($opt)) {
  50736. return $this->raiseError("could not create directory: " . dirname($file));
  50737. }
  50738. if (file_exists($file) && is_file($file) && !is_writeable($file)) {
  50739. return $this->raiseError("no write access to $file!");
  50740. }
  50741. $fp = @fopen($file, "w");
  50742. if (!$fp) {
  50743. return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
  50744. }
  50745. $contents = "#PEAR_Config 0.9\n" . serialize($data);
  50746. if (!@fwrite($fp, $contents)) {
  50747. return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
  50748. }
  50749. return true;
  50750. }
  50751. /**
  50752. * Reads configuration data from a file and returns the parsed data
  50753. * in an array.
  50754. *
  50755. * @param string file to read from
  50756. * @return array configuration data or a PEAR error on failure
  50757. * @access private
  50758. */
  50759. function _readConfigDataFrom($file)
  50760. {
  50761. $fp = false;
  50762. if (file_exists($file)) {
  50763. $fp = @fopen($file, "r");
  50764. }
  50765. if (!$fp) {
  50766. return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
  50767. }
  50768. $size = filesize($file);
  50769. fclose($fp);
  50770. $contents = file_get_contents($file);
  50771. if (empty($contents)) {
  50772. return $this->raiseError('Configuration file "' . $file . '" is empty');
  50773. }
  50774. $version = false;
  50775. if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
  50776. $version = $matches[1];
  50777. $contents = substr($contents, strlen($matches[0]));
  50778. } else {
  50779. // Museum config file
  50780. if (substr($contents,0,2) == 'a:') {
  50781. $version = '0.1';
  50782. }
  50783. }
  50784. if ($version && version_compare("$version", '1', '<')) {
  50785. // no '@', it is possible that unserialize
  50786. // raises a notice but it seems to block IO to
  50787. // STDOUT if a '@' is used and a notice is raise
  50788. $data = unserialize($contents);
  50789. if (!is_array($data) && !$data) {
  50790. if ($contents == serialize(false)) {
  50791. $data = array();
  50792. } else {
  50793. $err = $this->raiseError("PEAR_Config: bad data in $file");
  50794. return $err;
  50795. }
  50796. }
  50797. if (!is_array($data)) {
  50798. if (strlen(trim($contents)) > 0) {
  50799. $error = "PEAR_Config: bad data in $file";
  50800. $err = $this->raiseError($error);
  50801. return $err;
  50802. }
  50803. $data = array();
  50804. }
  50805. // add parsing of newer formats here...
  50806. } else {
  50807. $err = $this->raiseError("$file: unknown version `$version'");
  50808. return $err;
  50809. }
  50810. return $data;
  50811. }
  50812. /**
  50813. * Gets the file used for storing the config for a layer
  50814. *
  50815. * @param string $layer 'user' or 'system'
  50816. */
  50817. function getConfFile($layer)
  50818. {
  50819. return $this->files[$layer];
  50820. }
  50821. /**
  50822. * @param string Configuration class name, used for detecting duplicate calls
  50823. * @param array information on a role as parsed from its xml file
  50824. * @return true|PEAR_Error
  50825. * @access private
  50826. */
  50827. function _addConfigVars($class, $vars)
  50828. {
  50829. static $called = array();
  50830. if (isset($called[$class])) {
  50831. return;
  50832. }
  50833. $called[$class] = 1;
  50834. if (count($vars) > 3) {
  50835. return $this->raiseError('Roles can only define 3 new config variables or less');
  50836. }
  50837. foreach ($vars as $name => $var) {
  50838. if (!is_array($var)) {
  50839. return $this->raiseError('Configuration information must be an array');
  50840. }
  50841. if (!isset($var['type'])) {
  50842. return $this->raiseError('Configuration information must contain a type');
  50843. } elseif (!in_array($var['type'],
  50844. array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
  50845. return $this->raiseError(
  50846. 'Configuration type must be one of directory, file, string, ' .
  50847. 'mask, set, or password');
  50848. }
  50849. if (!isset($var['default'])) {
  50850. return $this->raiseError(
  50851. 'Configuration information must contain a default value ("default" index)');
  50852. }
  50853. if (is_array($var['default'])) {
  50854. $real_default = '';
  50855. foreach ($var['default'] as $config_var => $val) {
  50856. if (strpos($config_var, 'text') === 0) {
  50857. $real_default .= $val;
  50858. } elseif (strpos($config_var, 'constant') === 0) {
  50859. if (!defined($val)) {
  50860. return $this->raiseError(
  50861. 'Unknown constant "' . $val . '" requested in ' .
  50862. 'default value for configuration variable "' .
  50863. $name . '"');
  50864. }
  50865. $real_default .= constant($val);
  50866. } elseif (isset($this->configuration_info[$config_var])) {
  50867. $real_default .=
  50868. $this->configuration_info[$config_var]['default'];
  50869. } else {
  50870. return $this->raiseError(
  50871. 'Unknown request for "' . $config_var . '" value in ' .
  50872. 'default value for configuration variable "' .
  50873. $name . '"');
  50874. }
  50875. }
  50876. $var['default'] = $real_default;
  50877. }
  50878. if ($var['type'] == 'integer') {
  50879. $var['default'] = (integer) $var['default'];
  50880. }
  50881. if (!isset($var['doc'])) {
  50882. return $this->raiseError(
  50883. 'Configuration information must contain a summary ("doc" index)');
  50884. }
  50885. if (!isset($var['prompt'])) {
  50886. return $this->raiseError(
  50887. 'Configuration information must contain a simple prompt ("prompt" index)');
  50888. }
  50889. if (!isset($var['group'])) {
  50890. return $this->raiseError(
  50891. 'Configuration information must contain a simple group ("group" index)');
  50892. }
  50893. if (isset($this->configuration_info[$name])) {
  50894. return $this->raiseError('Configuration variable "' . $name .
  50895. '" already exists');
  50896. }
  50897. $this->configuration_info[$name] = $var;
  50898. // fix bug #7351: setting custom config variable in a channel fails
  50899. $this->_channelConfigInfo[] = $name;
  50900. }
  50901. return true;
  50902. }
  50903. /**
  50904. * Encodes/scrambles configuration data before writing to files.
  50905. * Currently, 'password' values will be base64-encoded as to avoid
  50906. * that people spot cleartext passwords by accident.
  50907. *
  50908. * @param array (reference) array to encode values in
  50909. * @return bool TRUE on success
  50910. * @access private
  50911. */
  50912. function _encodeOutput(&$data)
  50913. {
  50914. foreach ($data as $key => $value) {
  50915. if ($key == '__channels') {
  50916. foreach ($data['__channels'] as $channel => $blah) {
  50917. $this->_encodeOutput($data['__channels'][$channel]);
  50918. }
  50919. }
  50920. if (!isset($this->configuration_info[$key])) {
  50921. continue;
  50922. }
  50923. $type = $this->configuration_info[$key]['type'];
  50924. switch ($type) {
  50925. // we base64-encode passwords so they are at least
  50926. // not shown in plain by accident
  50927. case 'password': {
  50928. $data[$key] = base64_encode($data[$key]);
  50929. break;
  50930. }
  50931. case 'mask': {
  50932. $data[$key] = octdec($data[$key]);
  50933. break;
  50934. }
  50935. }
  50936. }
  50937. return true;
  50938. }
  50939. /**
  50940. * Decodes/unscrambles configuration data after reading from files.
  50941. *
  50942. * @param array (reference) array to encode values in
  50943. * @return bool TRUE on success
  50944. * @access private
  50945. *
  50946. * @see PEAR_Config::_encodeOutput
  50947. */
  50948. function _decodeInput(&$data)
  50949. {
  50950. if (!is_array($data)) {
  50951. return true;
  50952. }
  50953. foreach ($data as $key => $value) {
  50954. if ($key == '__channels') {
  50955. foreach ($data['__channels'] as $channel => $blah) {
  50956. $this->_decodeInput($data['__channels'][$channel]);
  50957. }
  50958. }
  50959. if (!isset($this->configuration_info[$key])) {
  50960. continue;
  50961. }
  50962. $type = $this->configuration_info[$key]['type'];
  50963. switch ($type) {
  50964. case 'password': {
  50965. $data[$key] = base64_decode($data[$key]);
  50966. break;
  50967. }
  50968. case 'mask': {
  50969. $data[$key] = decoct($data[$key]);
  50970. break;
  50971. }
  50972. }
  50973. }
  50974. return true;
  50975. }
  50976. /**
  50977. * Retrieve the default channel.
  50978. *
  50979. * On startup, channels are not initialized, so if the default channel is not
  50980. * pear.php.net, then initialize the config.
  50981. * @param string registry layer
  50982. * @return string|false
  50983. */
  50984. function getDefaultChannel($layer = null)
  50985. {
  50986. $ret = false;
  50987. if ($layer === null) {
  50988. foreach ($this->layers as $layer) {
  50989. if (isset($this->configuration[$layer]['default_channel'])) {
  50990. $ret = $this->configuration[$layer]['default_channel'];
  50991. break;
  50992. }
  50993. }
  50994. } elseif (isset($this->configuration[$layer]['default_channel'])) {
  50995. $ret = $this->configuration[$layer]['default_channel'];
  50996. }
  50997. if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
  50998. $ret = 'pecl.php.net';
  50999. }
  51000. if ($ret) {
  51001. if ($ret != 'pear.php.net') {
  51002. $this->_lazyChannelSetup();
  51003. }
  51004. return $ret;
  51005. }
  51006. return PEAR_CONFIG_DEFAULT_CHANNEL;
  51007. }
  51008. /**
  51009. * Returns a configuration value, prioritizing layers as per the
  51010. * layers property.
  51011. *
  51012. * @param string config key
  51013. * @return mixed the config value, or NULL if not found
  51014. * @access public
  51015. */
  51016. function get($key, $layer = null, $channel = false)
  51017. {
  51018. if (!isset($this->configuration_info[$key])) {
  51019. return null;
  51020. }
  51021. if ($key == '__channels') {
  51022. return null;
  51023. }
  51024. if ($key == 'default_channel') {
  51025. return $this->getDefaultChannel($layer);
  51026. }
  51027. if (!$channel) {
  51028. $channel = $this->getDefaultChannel();
  51029. } elseif ($channel != 'pear.php.net') {
  51030. $this->_lazyChannelSetup();
  51031. }
  51032. $channel = strtolower($channel);
  51033. $test = (in_array($key, $this->_channelConfigInfo)) ?
  51034. $this->_getChannelValue($key, $layer, $channel) :
  51035. null;
  51036. if ($test !== null) {
  51037. if ($this->_installRoot) {
  51038. if (in_array($this->getGroup($key),
  51039. array('File Locations', 'File Locations (Advanced)')) &&
  51040. $this->getType($key) == 'directory') {
  51041. return $this->_prependPath($test, $this->_installRoot);
  51042. }
  51043. }
  51044. return $test;
  51045. }
  51046. if ($layer === null) {
  51047. foreach ($this->layers as $layer) {
  51048. if (isset($this->configuration[$layer][$key])) {
  51049. $test = $this->configuration[$layer][$key];
  51050. if ($this->_installRoot) {
  51051. if (in_array($this->getGroup($key),
  51052. array('File Locations', 'File Locations (Advanced)')) &&
  51053. $this->getType($key) == 'directory') {
  51054. return $this->_prependPath($test, $this->_installRoot);
  51055. }
  51056. }
  51057. if ($key == 'preferred_mirror') {
  51058. $reg = &$this->getRegistry();
  51059. if (is_object($reg)) {
  51060. $chan = $reg->getChannel($channel);
  51061. if (PEAR::isError($chan)) {
  51062. return $channel;
  51063. }
  51064. if (!$chan->getMirror($test) && $chan->getName() != $test) {
  51065. return $channel; // mirror does not exist
  51066. }
  51067. }
  51068. }
  51069. return $test;
  51070. }
  51071. }
  51072. } elseif (isset($this->configuration[$layer][$key])) {
  51073. $test = $this->configuration[$layer][$key];
  51074. if ($this->_installRoot) {
  51075. if (in_array($this->getGroup($key),
  51076. array('File Locations', 'File Locations (Advanced)')) &&
  51077. $this->getType($key) == 'directory') {
  51078. return $this->_prependPath($test, $this->_installRoot);
  51079. }
  51080. }
  51081. if ($key == 'preferred_mirror') {
  51082. $reg = &$this->getRegistry();
  51083. if (is_object($reg)) {
  51084. $chan = $reg->getChannel($channel);
  51085. if (PEAR::isError($chan)) {
  51086. return $channel;
  51087. }
  51088. if (!$chan->getMirror($test) && $chan->getName() != $test) {
  51089. return $channel; // mirror does not exist
  51090. }
  51091. }
  51092. }
  51093. return $test;
  51094. }
  51095. return null;
  51096. }
  51097. /**
  51098. * Returns a channel-specific configuration value, prioritizing layers as per the
  51099. * layers property.
  51100. *
  51101. * @param string config key
  51102. * @return mixed the config value, or NULL if not found
  51103. * @access private
  51104. */
  51105. function _getChannelValue($key, $layer, $channel)
  51106. {
  51107. if ($key == '__channels' || $channel == 'pear.php.net') {
  51108. return null;
  51109. }
  51110. $ret = null;
  51111. if ($layer === null) {
  51112. foreach ($this->layers as $ilayer) {
  51113. if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
  51114. $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
  51115. break;
  51116. }
  51117. }
  51118. } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  51119. $ret = $this->configuration[$layer]['__channels'][$channel][$key];
  51120. }
  51121. if ($key != 'preferred_mirror') {
  51122. return $ret;
  51123. }
  51124. if ($ret !== null) {
  51125. $reg = &$this->getRegistry($layer);
  51126. if (is_object($reg)) {
  51127. $chan = $reg->getChannel($channel);
  51128. if (PEAR::isError($chan)) {
  51129. return $channel;
  51130. }
  51131. if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
  51132. return $channel; // mirror does not exist
  51133. }
  51134. }
  51135. return $ret;
  51136. }
  51137. if ($channel != $this->getDefaultChannel($layer)) {
  51138. return $channel; // we must use the channel name as the preferred mirror
  51139. // if the user has not chosen an alternate
  51140. }
  51141. return $this->getDefaultChannel($layer);
  51142. }
  51143. /**
  51144. * Set a config value in a specific layer (defaults to 'user').
  51145. * Enforces the types defined in the configuration_info array. An
  51146. * integer config variable will be cast to int, and a set config
  51147. * variable will be validated against its legal values.
  51148. *
  51149. * @param string config key
  51150. * @param string config value
  51151. * @param string (optional) config layer
  51152. * @param string channel to set this value for, or null for global value
  51153. * @return bool TRUE on success, FALSE on failure
  51154. */
  51155. function set($key, $value, $layer = 'user', $channel = false)
  51156. {
  51157. if ($key == '__channels') {
  51158. return false;
  51159. }
  51160. if (!isset($this->configuration[$layer])) {
  51161. return false;
  51162. }
  51163. if ($key == 'default_channel') {
  51164. // can only set this value globally
  51165. $channel = 'pear.php.net';
  51166. if ($value != 'pear.php.net') {
  51167. $this->_lazyChannelSetup($layer);
  51168. }
  51169. }
  51170. if ($key == 'preferred_mirror') {
  51171. if ($channel == '__uri') {
  51172. return false; // can't set the __uri pseudo-channel's mirror
  51173. }
  51174. $reg = &$this->getRegistry($layer);
  51175. if (is_object($reg)) {
  51176. $chan = $reg->getChannel($channel ? $channel : 'pear.php.net');
  51177. if (PEAR::isError($chan)) {
  51178. return false;
  51179. }
  51180. if (!$chan->getMirror($value) && $chan->getName() != $value) {
  51181. return false; // mirror does not exist
  51182. }
  51183. }
  51184. }
  51185. if (!isset($this->configuration_info[$key])) {
  51186. return false;
  51187. }
  51188. extract($this->configuration_info[$key]);
  51189. switch ($type) {
  51190. case 'integer':
  51191. $value = (int)$value;
  51192. break;
  51193. case 'set': {
  51194. // If a valid_set is specified, require the value to
  51195. // be in the set. If there is no valid_set, accept
  51196. // any value.
  51197. if ($valid_set) {
  51198. reset($valid_set);
  51199. if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
  51200. (key($valid_set) !== 0 && empty($valid_set[$value])))
  51201. {
  51202. return false;
  51203. }
  51204. }
  51205. break;
  51206. }
  51207. }
  51208. if (!$channel) {
  51209. $channel = $this->get('default_channel', null, 'pear.php.net');
  51210. }
  51211. if (!in_array($channel, $this->_channels)) {
  51212. $this->_lazyChannelSetup($layer);
  51213. $reg = &$this->getRegistry($layer);
  51214. if ($reg) {
  51215. $channel = $reg->channelName($channel);
  51216. }
  51217. if (!in_array($channel, $this->_channels)) {
  51218. return false;
  51219. }
  51220. }
  51221. if ($channel != 'pear.php.net') {
  51222. if (in_array($key, $this->_channelConfigInfo)) {
  51223. $this->configuration[$layer]['__channels'][$channel][$key] = $value;
  51224. return true;
  51225. }
  51226. return false;
  51227. }
  51228. if ($key == 'default_channel') {
  51229. if (!isset($reg)) {
  51230. $reg = &$this->getRegistry($layer);
  51231. if (!$reg) {
  51232. $reg = &$this->getRegistry();
  51233. }
  51234. }
  51235. if ($reg) {
  51236. $value = $reg->channelName($value);
  51237. }
  51238. if (!$value) {
  51239. return false;
  51240. }
  51241. }
  51242. $this->configuration[$layer][$key] = $value;
  51243. if ($key == 'php_dir' && !$this->_noRegistry) {
  51244. if (!isset($this->_registry[$layer]) ||
  51245. $value != $this->_registry[$layer]->install_dir) {
  51246. $this->_registry[$layer] = new PEAR_Registry($value);
  51247. $this->_regInitialized[$layer] = false;
  51248. $this->_registry[$layer]->setConfig($this, false);
  51249. }
  51250. }
  51251. return true;
  51252. }
  51253. function _lazyChannelSetup($uselayer = false)
  51254. {
  51255. if ($this->_noRegistry) {
  51256. return;
  51257. }
  51258. $merge = false;
  51259. foreach ($this->_registry as $layer => $p) {
  51260. if ($uselayer && $uselayer != $layer) {
  51261. continue;
  51262. }
  51263. if (!$this->_regInitialized[$layer]) {
  51264. if ($layer == 'default' && isset($this->_registry['user']) ||
  51265. isset($this->_registry['system'])) {
  51266. // only use the default registry if there are no alternatives
  51267. continue;
  51268. }
  51269. if (!is_object($this->_registry[$layer])) {
  51270. if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
  51271. $this->_registry[$layer] = new PEAR_Registry(
  51272. $phpdir, false, false,
  51273. $this->get('metadata_dir', $layer, 'pear.php.net'));
  51274. $this->_registry[$layer]->setConfig($this, false);
  51275. $this->_regInitialized[$layer] = false;
  51276. } else {
  51277. unset($this->_registry[$layer]);
  51278. return;
  51279. }
  51280. }
  51281. $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
  51282. $this->_regInitialized[$layer] = true;
  51283. $merge = true;
  51284. }
  51285. }
  51286. }
  51287. /**
  51288. * Set the list of channels.
  51289. *
  51290. * This should be set via a call to {@link PEAR_Registry::listChannels()}
  51291. * @param array
  51292. * @param bool
  51293. * @return bool success of operation
  51294. */
  51295. function setChannels($channels, $merge = false)
  51296. {
  51297. if (!is_array($channels)) {
  51298. return false;
  51299. }
  51300. if ($merge) {
  51301. $this->_channels = array_merge($this->_channels, $channels);
  51302. } else {
  51303. $this->_channels = $channels;
  51304. }
  51305. foreach ($channels as $channel) {
  51306. $channel = strtolower($channel);
  51307. if ($channel == 'pear.php.net') {
  51308. continue;
  51309. }
  51310. foreach ($this->layers as $layer) {
  51311. if (!isset($this->configuration[$layer]['__channels'])) {
  51312. $this->configuration[$layer]['__channels'] = array();
  51313. }
  51314. if (!isset($this->configuration[$layer]['__channels'][$channel])
  51315. || !is_array($this->configuration[$layer]['__channels'][$channel])) {
  51316. $this->configuration[$layer]['__channels'][$channel] = array();
  51317. }
  51318. }
  51319. }
  51320. return true;
  51321. }
  51322. /**
  51323. * Get the type of a config value.
  51324. *
  51325. * @param string config key
  51326. *
  51327. * @return string type, one of "string", "integer", "file",
  51328. * "directory", "set" or "password".
  51329. *
  51330. * @access public
  51331. *
  51332. */
  51333. function getType($key)
  51334. {
  51335. if (isset($this->configuration_info[$key])) {
  51336. return $this->configuration_info[$key]['type'];
  51337. }
  51338. return false;
  51339. }
  51340. /**
  51341. * Get the documentation for a config value.
  51342. *
  51343. * @param string config key
  51344. * @return string documentation string
  51345. *
  51346. * @access public
  51347. *
  51348. */
  51349. function getDocs($key)
  51350. {
  51351. if (isset($this->configuration_info[$key])) {
  51352. return $this->configuration_info[$key]['doc'];
  51353. }
  51354. return false;
  51355. }
  51356. /**
  51357. * Get the short documentation for a config value.
  51358. *
  51359. * @param string config key
  51360. * @return string short documentation string
  51361. *
  51362. * @access public
  51363. *
  51364. */
  51365. function getPrompt($key)
  51366. {
  51367. if (isset($this->configuration_info[$key])) {
  51368. return $this->configuration_info[$key]['prompt'];
  51369. }
  51370. return false;
  51371. }
  51372. /**
  51373. * Get the parameter group for a config key.
  51374. *
  51375. * @param string config key
  51376. * @return string parameter group
  51377. *
  51378. * @access public
  51379. *
  51380. */
  51381. function getGroup($key)
  51382. {
  51383. if (isset($this->configuration_info[$key])) {
  51384. return $this->configuration_info[$key]['group'];
  51385. }
  51386. return false;
  51387. }
  51388. /**
  51389. * Get the list of parameter groups.
  51390. *
  51391. * @return array list of parameter groups
  51392. *
  51393. * @access public
  51394. *
  51395. */
  51396. function getGroups()
  51397. {
  51398. $tmp = array();
  51399. foreach ($this->configuration_info as $key => $info) {
  51400. $tmp[$info['group']] = 1;
  51401. }
  51402. return array_keys($tmp);
  51403. }
  51404. /**
  51405. * Get the list of the parameters in a group.
  51406. *
  51407. * @param string $group parameter group
  51408. * @return array list of parameters in $group
  51409. *
  51410. * @access public
  51411. *
  51412. */
  51413. function getGroupKeys($group)
  51414. {
  51415. $keys = array();
  51416. foreach ($this->configuration_info as $key => $info) {
  51417. if ($info['group'] == $group) {
  51418. $keys[] = $key;
  51419. }
  51420. }
  51421. return $keys;
  51422. }
  51423. /**
  51424. * Get the list of allowed set values for a config value. Returns
  51425. * NULL for config values that are not sets.
  51426. *
  51427. * @param string config key
  51428. * @return array enumerated array of set values, or NULL if the
  51429. * config key is unknown or not a set
  51430. *
  51431. * @access public
  51432. *
  51433. */
  51434. function getSetValues($key)
  51435. {
  51436. if (isset($this->configuration_info[$key]) &&
  51437. isset($this->configuration_info[$key]['type']) &&
  51438. $this->configuration_info[$key]['type'] == 'set')
  51439. {
  51440. $valid_set = $this->configuration_info[$key]['valid_set'];
  51441. reset($valid_set);
  51442. if (key($valid_set) === 0) {
  51443. return $valid_set;
  51444. }
  51445. return array_keys($valid_set);
  51446. }
  51447. return null;
  51448. }
  51449. /**
  51450. * Get all the current config keys.
  51451. *
  51452. * @return array simple array of config keys
  51453. *
  51454. * @access public
  51455. */
  51456. function getKeys()
  51457. {
  51458. $keys = array();
  51459. foreach ($this->layers as $layer) {
  51460. $test = $this->configuration[$layer];
  51461. if (isset($test['__channels'])) {
  51462. foreach ($test['__channels'] as $channel => $configs) {
  51463. $keys = array_merge($keys, $configs);
  51464. }
  51465. }
  51466. unset($test['__channels']);
  51467. $keys = array_merge($keys, $test);
  51468. }
  51469. return array_keys($keys);
  51470. }
  51471. /**
  51472. * Remove the a config key from a specific config layer.
  51473. *
  51474. * @param string config key
  51475. * @param string (optional) config layer
  51476. * @param string (optional) channel (defaults to default channel)
  51477. * @return bool TRUE on success, FALSE on failure
  51478. *
  51479. * @access public
  51480. */
  51481. function remove($key, $layer = 'user', $channel = null)
  51482. {
  51483. if ($channel === null) {
  51484. $channel = $this->getDefaultChannel();
  51485. }
  51486. if ($channel !== 'pear.php.net') {
  51487. if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  51488. unset($this->configuration[$layer]['__channels'][$channel][$key]);
  51489. return true;
  51490. }
  51491. }
  51492. if (isset($this->configuration[$layer][$key])) {
  51493. unset($this->configuration[$layer][$key]);
  51494. return true;
  51495. }
  51496. return false;
  51497. }
  51498. /**
  51499. * Temporarily remove an entire config layer. USE WITH CARE!
  51500. *
  51501. * @param string config key
  51502. * @param string (optional) config layer
  51503. * @return bool TRUE on success, FALSE on failure
  51504. *
  51505. * @access public
  51506. */
  51507. function removeLayer($layer)
  51508. {
  51509. if (isset($this->configuration[$layer])) {
  51510. $this->configuration[$layer] = array();
  51511. return true;
  51512. }
  51513. return false;
  51514. }
  51515. /**
  51516. * Stores configuration data in a layer.
  51517. *
  51518. * @param string config layer to store
  51519. * @return bool TRUE on success, or PEAR error on failure
  51520. *
  51521. * @access public
  51522. */
  51523. function store($layer = 'user', $data = null)
  51524. {
  51525. return $this->writeConfigFile(null, $layer, $data);
  51526. }
  51527. /**
  51528. * Tells what config layer that gets to define a key.
  51529. *
  51530. * @param string config key
  51531. * @param boolean return the defining channel
  51532. *
  51533. * @return string|array the config layer, or an empty string if not found.
  51534. *
  51535. * if $returnchannel, the return is an array array('layer' => layername,
  51536. * 'channel' => channelname), or an empty string if not found
  51537. *
  51538. * @access public
  51539. */
  51540. function definedBy($key, $returnchannel = false)
  51541. {
  51542. foreach ($this->layers as $layer) {
  51543. $channel = $this->getDefaultChannel();
  51544. if ($channel !== 'pear.php.net') {
  51545. if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  51546. if ($returnchannel) {
  51547. return array('layer' => $layer, 'channel' => $channel);
  51548. }
  51549. return $layer;
  51550. }
  51551. }
  51552. if (isset($this->configuration[$layer][$key])) {
  51553. if ($returnchannel) {
  51554. return array('layer' => $layer, 'channel' => 'pear.php.net');
  51555. }
  51556. return $layer;
  51557. }
  51558. }
  51559. return '';
  51560. }
  51561. /**
  51562. * Tells whether a given key exists as a config value.
  51563. *
  51564. * @param string config key
  51565. * @return bool whether <config key> exists in this object
  51566. *
  51567. * @access public
  51568. */
  51569. function isDefined($key)
  51570. {
  51571. foreach ($this->layers as $layer) {
  51572. if (isset($this->configuration[$layer][$key])) {
  51573. return true;
  51574. }
  51575. }
  51576. return false;
  51577. }
  51578. /**
  51579. * Tells whether a given config layer exists.
  51580. *
  51581. * @param string config layer
  51582. * @return bool whether <config layer> exists in this object
  51583. *
  51584. * @access public
  51585. */
  51586. function isDefinedLayer($layer)
  51587. {
  51588. return isset($this->configuration[$layer]);
  51589. }
  51590. /**
  51591. * Returns the layers defined (except the 'default' one)
  51592. *
  51593. * @return array of the defined layers
  51594. */
  51595. function getLayers()
  51596. {
  51597. $cf = $this->configuration;
  51598. unset($cf['default']);
  51599. return array_keys($cf);
  51600. }
  51601. function apiVersion()
  51602. {
  51603. return '1.1';
  51604. }
  51605. /**
  51606. * @return PEAR_Registry
  51607. */
  51608. function &getRegistry($use = null)
  51609. {
  51610. $layer = $use === null ? 'user' : $use;
  51611. if (isset($this->_registry[$layer])) {
  51612. return $this->_registry[$layer];
  51613. } elseif ($use === null && isset($this->_registry['system'])) {
  51614. return $this->_registry['system'];
  51615. } elseif ($use === null && isset($this->_registry['default'])) {
  51616. return $this->_registry['default'];
  51617. } elseif ($use) {
  51618. $a = false;
  51619. return $a;
  51620. }
  51621. // only go here if null was passed in
  51622. echo "CRITICAL ERROR: Registry could not be initialized from any value";
  51623. exit(1);
  51624. }
  51625. /**
  51626. * This is to allow customization like the use of installroot
  51627. * @param PEAR_Registry
  51628. * @return bool
  51629. */
  51630. function setRegistry(&$reg, $layer = 'user')
  51631. {
  51632. if ($this->_noRegistry) {
  51633. return false;
  51634. }
  51635. if (!in_array($layer, array('user', 'system'))) {
  51636. return false;
  51637. }
  51638. $this->_registry[$layer] = &$reg;
  51639. if (is_object($reg)) {
  51640. $this->_registry[$layer]->setConfig($this, false);
  51641. }
  51642. return true;
  51643. }
  51644. function noRegistry()
  51645. {
  51646. $this->_noRegistry = true;
  51647. }
  51648. /**
  51649. * @return PEAR_REST
  51650. */
  51651. function &getREST($version, $options = array())
  51652. {
  51653. $version = str_replace('.', '', $version);
  51654. if (!class_exists($class = 'PEAR_REST_' . $version)) {
  51655. require_once 'PEAR/REST/' . $version . '.php';
  51656. }
  51657. $remote = new $class($this, $options);
  51658. return $remote;
  51659. }
  51660. /**
  51661. * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a
  51662. * remote configuration file has been specified
  51663. * @return PEAR_FTP|false
  51664. */
  51665. function &getFTP()
  51666. {
  51667. if (isset($this->_ftp)) {
  51668. return $this->_ftp;
  51669. }
  51670. $a = false;
  51671. return $a;
  51672. }
  51673. static function _prependPath($path, $prepend)
  51674. {
  51675. if (strlen($prepend) > 0) {
  51676. if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  51677. if (preg_match('/^[a-z]:/i', $prepend)) {
  51678. $prepend = substr($prepend, 2);
  51679. } elseif ($prepend[0] != '\\') {
  51680. $prepend = "\\$prepend";
  51681. }
  51682. $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  51683. } else {
  51684. $path = $prepend . $path;
  51685. }
  51686. }
  51687. return $path;
  51688. }
  51689. /**
  51690. * @param string|false installation directory to prepend to all _dir variables, or false to
  51691. * disable
  51692. */
  51693. function setInstallRoot($root)
  51694. {
  51695. if (substr($root, -1) == DIRECTORY_SEPARATOR) {
  51696. $root = substr($root, 0, -1);
  51697. }
  51698. $old = $this->_installRoot;
  51699. $this->_installRoot = $root;
  51700. if (($old != $root) && !$this->_noRegistry) {
  51701. foreach (array_keys($this->_registry) as $layer) {
  51702. if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
  51703. continue;
  51704. }
  51705. $this->_registry[$layer] =
  51706. new PEAR_Registry(
  51707. $this->get('php_dir', $layer, 'pear.php.net'), false, false,
  51708. $this->get('metadata_dir', $layer, 'pear.php.net'));
  51709. $this->_registry[$layer]->setConfig($this, false);
  51710. $this->_regInitialized[$layer] = false;
  51711. }
  51712. }
  51713. }
  51714. }
  51715. �������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/DependencyDB.php������������������������������������������������������������������0000644�0001750�0001750�00000057070�13565304531�016013� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  51716. /**
  51717. * PEAR_DependencyDB, advanced installed packages dependency database
  51718. *
  51719. * PHP versions 4 and 5
  51720. *
  51721. * @category pear
  51722. * @package PEAR
  51723. * @author Tomas V. V. Cox <cox@idecnet.com>
  51724. * @author Greg Beaver <cellog@php.net>
  51725. * @copyright 1997-2009 The Authors
  51726. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  51727. * @link http://pear.php.net/package/PEAR
  51728. * @since File available since Release 1.4.0a1
  51729. */
  51730. /**
  51731. * Needed for error handling
  51732. */
  51733. require_once 'PEAR.php';
  51734. require_once 'PEAR/Config.php';
  51735. $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
  51736. /**
  51737. * Track dependency relationships between installed packages
  51738. * @category pear
  51739. * @package PEAR
  51740. * @author Greg Beaver <cellog@php.net>
  51741. * @author Tomas V.V.Cox <cox@idec.net.com>
  51742. * @copyright 1997-2009 The Authors
  51743. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  51744. * @version Release: 1.10.10
  51745. * @link http://pear.php.net/package/PEAR
  51746. * @since Class available since Release 1.4.0a1
  51747. */
  51748. class PEAR_DependencyDB
  51749. {
  51750. // {{{ properties
  51751. /**
  51752. * This is initialized by {@link setConfig()}
  51753. * @var PEAR_Config
  51754. * @access private
  51755. */
  51756. var $_config;
  51757. /**
  51758. * This is initialized by {@link setConfig()}
  51759. * @var PEAR_Registry
  51760. * @access private
  51761. */
  51762. var $_registry;
  51763. /**
  51764. * Filename of the dependency DB (usually .depdb)
  51765. * @var string
  51766. * @access private
  51767. */
  51768. var $_depdb = false;
  51769. /**
  51770. * File name of the lockfile (usually .depdblock)
  51771. * @var string
  51772. * @access private
  51773. */
  51774. var $_lockfile = false;
  51775. /**
  51776. * Open file resource for locking the lockfile
  51777. * @var resource|false
  51778. * @access private
  51779. */
  51780. var $_lockFp = false;
  51781. /**
  51782. * API version of this class, used to validate a file on-disk
  51783. * @var string
  51784. * @access private
  51785. */
  51786. var $_version = '1.0';
  51787. /**
  51788. * Cached dependency database file
  51789. * @var array|null
  51790. * @access private
  51791. */
  51792. var $_cache;
  51793. // }}}
  51794. // {{{ & singleton()
  51795. /**
  51796. * Get a raw dependency database. Calls setConfig() and assertDepsDB()
  51797. * @param PEAR_Config
  51798. * @param string|false full path to the dependency database, or false to use default
  51799. * @return PEAR_DependencyDB|PEAR_Error
  51800. */
  51801. public static function &singleton(&$config, $depdb = false)
  51802. {
  51803. $phpdir = $config->get('php_dir', null, 'pear.php.net');
  51804. if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) {
  51805. $a = new PEAR_DependencyDB;
  51806. $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a;
  51807. $a->setConfig($config, $depdb);
  51808. $e = $a->assertDepsDB();
  51809. if (PEAR::isError($e)) {
  51810. return $e;
  51811. }
  51812. }
  51813. return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir];
  51814. }
  51815. /**
  51816. * Set up the registry/location of dependency DB
  51817. * @param PEAR_Config|false
  51818. * @param string|false full path to the dependency database, or false to use default
  51819. */
  51820. function setConfig(&$config, $depdb = false)
  51821. {
  51822. if (!$config) {
  51823. $this->_config = &PEAR_Config::singleton();
  51824. } else {
  51825. $this->_config = &$config;
  51826. }
  51827. $this->_registry = &$this->_config->getRegistry();
  51828. if (!$depdb) {
  51829. $dir = $this->_config->get('metadata_dir', null, 'pear.php.net');
  51830. if (!$dir) {
  51831. $dir = $this->_config->get('php_dir', null, 'pear.php.net');
  51832. }
  51833. $this->_depdb = $dir . DIRECTORY_SEPARATOR . '.depdb';
  51834. } else {
  51835. $this->_depdb = $depdb;
  51836. }
  51837. $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
  51838. }
  51839. // }}}
  51840. function hasWriteAccess()
  51841. {
  51842. if (!file_exists($this->_depdb)) {
  51843. $dir = $this->_depdb;
  51844. while ($dir && $dir != '.') {
  51845. $dir = dirname($dir); // cd ..
  51846. if ($dir != '.' && file_exists($dir)) {
  51847. if (is_writeable($dir)) {
  51848. return true;
  51849. }
  51850. return false;
  51851. }
  51852. }
  51853. return false;
  51854. }
  51855. return is_writeable($this->_depdb);
  51856. }
  51857. // {{{ assertDepsDB()
  51858. /**
  51859. * Create the dependency database, if it doesn't exist. Error if the database is
  51860. * newer than the code reading it.
  51861. * @return void|PEAR_Error
  51862. */
  51863. function assertDepsDB()
  51864. {
  51865. if (!is_file($this->_depdb)) {
  51866. $this->rebuildDB();
  51867. return;
  51868. }
  51869. $depdb = $this->_getDepDB();
  51870. // Datatype format has been changed, rebuild the Deps DB
  51871. if ($depdb['_version'] < $this->_version) {
  51872. $this->rebuildDB();
  51873. }
  51874. if ($depdb['_version'][0] > $this->_version[0]) {
  51875. return PEAR::raiseError('Dependency database is version ' .
  51876. $depdb['_version'] . ', and we are version ' .
  51877. $this->_version . ', cannot continue');
  51878. }
  51879. }
  51880. /**
  51881. * Get a list of installed packages that depend on this package
  51882. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  51883. * @return array|false
  51884. */
  51885. function getDependentPackages(&$pkg)
  51886. {
  51887. $data = $this->_getDepDB();
  51888. if (is_object($pkg)) {
  51889. $channel = strtolower($pkg->getChannel());
  51890. $package = strtolower($pkg->getPackage());
  51891. } else {
  51892. $channel = strtolower($pkg['channel']);
  51893. $package = strtolower($pkg['package']);
  51894. }
  51895. if (isset($data['packages'][$channel][$package])) {
  51896. return $data['packages'][$channel][$package];
  51897. }
  51898. return false;
  51899. }
  51900. /**
  51901. * Get a list of the actual dependencies of installed packages that depend on
  51902. * a package.
  51903. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  51904. * @return array|false
  51905. */
  51906. function getDependentPackageDependencies(&$pkg)
  51907. {
  51908. $data = $this->_getDepDB();
  51909. if (is_object($pkg)) {
  51910. $channel = strtolower($pkg->getChannel());
  51911. $package = strtolower($pkg->getPackage());
  51912. } else if (is_array($pkg)) {
  51913. $channel = strtolower($pkg['channel']);
  51914. $package = strtolower($pkg['package']);
  51915. } else {
  51916. return false;
  51917. }
  51918. $depend = $this->getDependentPackages($pkg);
  51919. if (!$depend) {
  51920. return false;
  51921. }
  51922. $dependencies = array();
  51923. foreach ($depend as $info) {
  51924. $temp = $this->getDependencies($info);
  51925. foreach ($temp as $dep) {
  51926. if (
  51927. isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) &&
  51928. strtolower($dep['dep']['channel']) == $channel &&
  51929. strtolower($dep['dep']['name']) == $package
  51930. ) {
  51931. if (!isset($dependencies[$info['channel']])) {
  51932. $dependencies[$info['channel']] = array();
  51933. }
  51934. if (!isset($dependencies[$info['channel']][$info['package']])) {
  51935. $dependencies[$info['channel']][$info['package']] = array();
  51936. }
  51937. $dependencies[$info['channel']][$info['package']][] = $dep;
  51938. }
  51939. }
  51940. }
  51941. return $dependencies;
  51942. }
  51943. /**
  51944. * Get a list of dependencies of this installed package
  51945. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  51946. * @return array|false
  51947. */
  51948. function getDependencies(&$pkg)
  51949. {
  51950. if (is_object($pkg)) {
  51951. $channel = strtolower($pkg->getChannel());
  51952. $package = strtolower($pkg->getPackage());
  51953. } else {
  51954. $channel = strtolower($pkg['channel']);
  51955. $package = strtolower($pkg['package']);
  51956. }
  51957. $data = $this->_getDepDB();
  51958. if (isset($data['dependencies'][$channel][$package])) {
  51959. return $data['dependencies'][$channel][$package];
  51960. }
  51961. return false;
  51962. }
  51963. /**
  51964. * Determine whether $parent depends on $child, near or deep
  51965. * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  51966. * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  51967. */
  51968. function dependsOn($parent, $child)
  51969. {
  51970. $c = array();
  51971. $this->_getDepDB();
  51972. return $this->_dependsOn($parent, $child, $c);
  51973. }
  51974. function _dependsOn($parent, $child, &$checked)
  51975. {
  51976. if (is_object($parent)) {
  51977. $channel = strtolower($parent->getChannel());
  51978. $package = strtolower($parent->getPackage());
  51979. } else {
  51980. $channel = strtolower($parent['channel']);
  51981. $package = strtolower($parent['package']);
  51982. }
  51983. if (is_object($child)) {
  51984. $depchannel = strtolower($child->getChannel());
  51985. $deppackage = strtolower($child->getPackage());
  51986. } else {
  51987. $depchannel = strtolower($child['channel']);
  51988. $deppackage = strtolower($child['package']);
  51989. }
  51990. if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
  51991. return false; // avoid endless recursion
  51992. }
  51993. $checked[$channel][$package][$depchannel][$deppackage] = true;
  51994. if (!isset($this->_cache['dependencies'][$channel][$package])) {
  51995. return false;
  51996. }
  51997. foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  51998. if (isset($info['dep']['uri'])) {
  51999. if (is_object($child)) {
  52000. if ($info['dep']['uri'] == $child->getURI()) {
  52001. return true;
  52002. }
  52003. } elseif (isset($child['uri'])) {
  52004. if ($info['dep']['uri'] == $child['uri']) {
  52005. return true;
  52006. }
  52007. }
  52008. return false;
  52009. }
  52010. if (strtolower($info['dep']['channel']) == $depchannel &&
  52011. strtolower($info['dep']['name']) == $deppackage) {
  52012. return true;
  52013. }
  52014. }
  52015. foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  52016. if (isset($info['dep']['uri'])) {
  52017. if ($this->_dependsOn(array(
  52018. 'uri' => $info['dep']['uri'],
  52019. 'package' => $info['dep']['name']), $child, $checked)) {
  52020. return true;
  52021. }
  52022. } else {
  52023. if ($this->_dependsOn(array(
  52024. 'channel' => $info['dep']['channel'],
  52025. 'package' => $info['dep']['name']), $child, $checked)) {
  52026. return true;
  52027. }
  52028. }
  52029. }
  52030. return false;
  52031. }
  52032. /**
  52033. * Register dependencies of a package that is being installed or upgraded
  52034. * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
  52035. */
  52036. function installPackage(&$package)
  52037. {
  52038. $data = $this->_getDepDB();
  52039. unset($this->_cache);
  52040. $this->_setPackageDeps($data, $package);
  52041. $this->_writeDepDB($data);
  52042. }
  52043. /**
  52044. * Remove dependencies of a package that is being uninstalled, or upgraded.
  52045. *
  52046. * Upgraded packages first uninstall, then install
  52047. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
  52048. * indices 'channel' and 'package'
  52049. */
  52050. function uninstallPackage(&$pkg)
  52051. {
  52052. $data = $this->_getDepDB();
  52053. unset($this->_cache);
  52054. if (is_object($pkg)) {
  52055. $channel = strtolower($pkg->getChannel());
  52056. $package = strtolower($pkg->getPackage());
  52057. } else {
  52058. $channel = strtolower($pkg['channel']);
  52059. $package = strtolower($pkg['package']);
  52060. }
  52061. if (!isset($data['dependencies'][$channel][$package])) {
  52062. return true;
  52063. }
  52064. foreach ($data['dependencies'][$channel][$package] as $dep) {
  52065. $found = false;
  52066. $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']);
  52067. $depname = strtolower($dep['dep']['name']);
  52068. if (isset($data['packages'][$depchannel][$depname])) {
  52069. foreach ($data['packages'][$depchannel][$depname] as $i => $info) {
  52070. if ($info['channel'] == $channel && $info['package'] == $package) {
  52071. $found = true;
  52072. break;
  52073. }
  52074. }
  52075. }
  52076. if ($found) {
  52077. unset($data['packages'][$depchannel][$depname][$i]);
  52078. if (!count($data['packages'][$depchannel][$depname])) {
  52079. unset($data['packages'][$depchannel][$depname]);
  52080. if (!count($data['packages'][$depchannel])) {
  52081. unset($data['packages'][$depchannel]);
  52082. }
  52083. } else {
  52084. $data['packages'][$depchannel][$depname] =
  52085. array_values($data['packages'][$depchannel][$depname]);
  52086. }
  52087. }
  52088. }
  52089. unset($data['dependencies'][$channel][$package]);
  52090. if (!count($data['dependencies'][$channel])) {
  52091. unset($data['dependencies'][$channel]);
  52092. }
  52093. if (!count($data['dependencies'])) {
  52094. unset($data['dependencies']);
  52095. }
  52096. if (!count($data['packages'])) {
  52097. unset($data['packages']);
  52098. }
  52099. $this->_writeDepDB($data);
  52100. }
  52101. /**
  52102. * Rebuild the dependency DB by reading registry entries.
  52103. * @return true|PEAR_Error
  52104. */
  52105. function rebuildDB()
  52106. {
  52107. $depdb = array('_version' => $this->_version);
  52108. if (!$this->hasWriteAccess()) {
  52109. // allow startup for read-only with older Registry
  52110. return $depdb;
  52111. }
  52112. $packages = $this->_registry->listAllPackages();
  52113. if (PEAR::isError($packages)) {
  52114. return $packages;
  52115. }
  52116. foreach ($packages as $channel => $ps) {
  52117. foreach ($ps as $package) {
  52118. $package = $this->_registry->getPackage($package, $channel);
  52119. if (PEAR::isError($package)) {
  52120. return $package;
  52121. }
  52122. $this->_setPackageDeps($depdb, $package);
  52123. }
  52124. }
  52125. $error = $this->_writeDepDB($depdb);
  52126. if (PEAR::isError($error)) {
  52127. return $error;
  52128. }
  52129. $this->_cache = $depdb;
  52130. return true;
  52131. }
  52132. /**
  52133. * Register usage of the dependency DB to prevent race conditions
  52134. * @param int one of the LOCK_* constants
  52135. * @return true|PEAR_Error
  52136. * @access private
  52137. */
  52138. function _lock($mode = LOCK_EX)
  52139. {
  52140. if (stristr(php_uname(), 'Windows 9')) {
  52141. return true;
  52142. }
  52143. if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
  52144. // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  52145. return true;
  52146. }
  52147. $open_mode = 'w';
  52148. // XXX People reported problems with LOCK_SH and 'w'
  52149. if ($mode === LOCK_SH) {
  52150. if (!file_exists($this->_lockfile)) {
  52151. touch($this->_lockfile);
  52152. } elseif (!is_file($this->_lockfile)) {
  52153. return PEAR::raiseError('could not create Dependency lock file, ' .
  52154. 'it exists and is not a regular file');
  52155. }
  52156. $open_mode = 'r';
  52157. }
  52158. if (!is_resource($this->_lockFp)) {
  52159. $this->_lockFp = @fopen($this->_lockfile, $open_mode);
  52160. }
  52161. if (!is_resource($this->_lockFp)) {
  52162. return PEAR::raiseError("could not create Dependency lock file" .
  52163. (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  52164. }
  52165. if (!(int)flock($this->_lockFp, $mode)) {
  52166. switch ($mode) {
  52167. case LOCK_SH: $str = 'shared'; break;
  52168. case LOCK_EX: $str = 'exclusive'; break;
  52169. case LOCK_UN: $str = 'unlock'; break;
  52170. default: $str = 'unknown'; break;
  52171. }
  52172. return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
  52173. }
  52174. return true;
  52175. }
  52176. /**
  52177. * Release usage of dependency DB
  52178. * @return true|PEAR_Error
  52179. * @access private
  52180. */
  52181. function _unlock()
  52182. {
  52183. $ret = $this->_lock(LOCK_UN);
  52184. if (is_resource($this->_lockFp)) {
  52185. fclose($this->_lockFp);
  52186. }
  52187. $this->_lockFp = null;
  52188. return $ret;
  52189. }
  52190. /**
  52191. * Load the dependency database from disk, or return the cache
  52192. * @return array|PEAR_Error
  52193. */
  52194. function _getDepDB()
  52195. {
  52196. if (!$this->hasWriteAccess()) {
  52197. return array('_version' => $this->_version);
  52198. }
  52199. if (isset($this->_cache)) {
  52200. return $this->_cache;
  52201. }
  52202. if (!$fp = fopen($this->_depdb, 'r')) {
  52203. $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
  52204. return $err;
  52205. }
  52206. clearstatcache();
  52207. fclose($fp);
  52208. $data = unserialize(file_get_contents($this->_depdb));
  52209. $this->_cache = $data;
  52210. return $data;
  52211. }
  52212. /**
  52213. * Write out the dependency database to disk
  52214. * @param array the database
  52215. * @return true|PEAR_Error
  52216. * @access private
  52217. */
  52218. function _writeDepDB(&$deps)
  52219. {
  52220. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  52221. return $e;
  52222. }
  52223. if (!$fp = fopen($this->_depdb, 'wb')) {
  52224. $this->_unlock();
  52225. return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
  52226. }
  52227. fwrite($fp, serialize($deps));
  52228. fclose($fp);
  52229. $this->_unlock();
  52230. $this->_cache = $deps;
  52231. return true;
  52232. }
  52233. /**
  52234. * Register all dependencies from a package in the dependencies database, in essence
  52235. * "installing" the package's dependency information
  52236. * @param array the database
  52237. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  52238. * @access private
  52239. */
  52240. function _setPackageDeps(&$data, &$pkg)
  52241. {
  52242. $pkg->setConfig($this->_config);
  52243. if ($pkg->getPackagexmlVersion() == '1.0') {
  52244. $gen = &$pkg->getDefaultGenerator();
  52245. $deps = $gen->dependenciesToV2();
  52246. } else {
  52247. $deps = $pkg->getDeps(true);
  52248. }
  52249. if (!$deps) {
  52250. return;
  52251. }
  52252. if (!is_array($data)) {
  52253. $data = array();
  52254. }
  52255. if (!isset($data['dependencies'])) {
  52256. $data['dependencies'] = array();
  52257. }
  52258. $channel = strtolower($pkg->getChannel());
  52259. $package = strtolower($pkg->getPackage());
  52260. if (!isset($data['dependencies'][$channel])) {
  52261. $data['dependencies'][$channel] = array();
  52262. }
  52263. $data['dependencies'][$channel][$package] = array();
  52264. if (isset($deps['required']['package'])) {
  52265. if (!isset($deps['required']['package'][0])) {
  52266. $deps['required']['package'] = array($deps['required']['package']);
  52267. }
  52268. foreach ($deps['required']['package'] as $dep) {
  52269. $this->_registerDep($data, $pkg, $dep, 'required');
  52270. }
  52271. }
  52272. if (isset($deps['optional']['package'])) {
  52273. if (!isset($deps['optional']['package'][0])) {
  52274. $deps['optional']['package'] = array($deps['optional']['package']);
  52275. }
  52276. foreach ($deps['optional']['package'] as $dep) {
  52277. $this->_registerDep($data, $pkg, $dep, 'optional');
  52278. }
  52279. }
  52280. if (isset($deps['required']['subpackage'])) {
  52281. if (!isset($deps['required']['subpackage'][0])) {
  52282. $deps['required']['subpackage'] = array($deps['required']['subpackage']);
  52283. }
  52284. foreach ($deps['required']['subpackage'] as $dep) {
  52285. $this->_registerDep($data, $pkg, $dep, 'required');
  52286. }
  52287. }
  52288. if (isset($deps['optional']['subpackage'])) {
  52289. if (!isset($deps['optional']['subpackage'][0])) {
  52290. $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
  52291. }
  52292. foreach ($deps['optional']['subpackage'] as $dep) {
  52293. $this->_registerDep($data, $pkg, $dep, 'optional');
  52294. }
  52295. }
  52296. if (isset($deps['group'])) {
  52297. if (!isset($deps['group'][0])) {
  52298. $deps['group'] = array($deps['group']);
  52299. }
  52300. foreach ($deps['group'] as $group) {
  52301. if (isset($group['package'])) {
  52302. if (!isset($group['package'][0])) {
  52303. $group['package'] = array($group['package']);
  52304. }
  52305. foreach ($group['package'] as $dep) {
  52306. $this->_registerDep($data, $pkg, $dep, 'optional',
  52307. $group['attribs']['name']);
  52308. }
  52309. }
  52310. if (isset($group['subpackage'])) {
  52311. if (!isset($group['subpackage'][0])) {
  52312. $group['subpackage'] = array($group['subpackage']);
  52313. }
  52314. foreach ($group['subpackage'] as $dep) {
  52315. $this->_registerDep($data, $pkg, $dep, 'optional',
  52316. $group['attribs']['name']);
  52317. }
  52318. }
  52319. }
  52320. }
  52321. if ($data['dependencies'][$channel][$package] == array()) {
  52322. unset($data['dependencies'][$channel][$package]);
  52323. if (!count($data['dependencies'][$channel])) {
  52324. unset($data['dependencies'][$channel]);
  52325. }
  52326. }
  52327. }
  52328. /**
  52329. * @param array the database
  52330. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  52331. * @param array the specific dependency
  52332. * @param required|optional whether this is a required or an optional dep
  52333. * @param string|false dependency group this dependency is from, or false for ordinary dep
  52334. */
  52335. function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
  52336. {
  52337. $info = array(
  52338. 'dep' => $dep,
  52339. 'type' => $type,
  52340. 'group' => $group
  52341. );
  52342. $dep = array_map('strtolower', $dep);
  52343. $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
  52344. if (!isset($data['dependencies'])) {
  52345. $data['dependencies'] = array();
  52346. }
  52347. $channel = strtolower($pkg->getChannel());
  52348. $package = strtolower($pkg->getPackage());
  52349. if (!isset($data['dependencies'][$channel])) {
  52350. $data['dependencies'][$channel] = array();
  52351. }
  52352. if (!isset($data['dependencies'][$channel][$package])) {
  52353. $data['dependencies'][$channel][$package] = array();
  52354. }
  52355. $data['dependencies'][$channel][$package][] = $info;
  52356. if (isset($data['packages'][$depchannel][$dep['name']])) {
  52357. $found = false;
  52358. foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) {
  52359. if ($p['channel'] == $channel && $p['package'] == $package) {
  52360. $found = true;
  52361. break;
  52362. }
  52363. }
  52364. } else {
  52365. if (!isset($data['packages'])) {
  52366. $data['packages'] = array();
  52367. }
  52368. if (!isset($data['packages'][$depchannel])) {
  52369. $data['packages'][$depchannel] = array();
  52370. }
  52371. if (!isset($data['packages'][$depchannel][$dep['name']])) {
  52372. $data['packages'][$depchannel][$dep['name']] = array();
  52373. }
  52374. $found = false;
  52375. }
  52376. if (!$found) {
  52377. $data['packages'][$depchannel][$dep['name']][] = array(
  52378. 'channel' => $channel,
  52379. 'package' => $package
  52380. );
  52381. }
  52382. }
  52383. }
  52384. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Dependency2.php�������������������������������������������������������������������0000644�0001750�0001750�00000142416�13565304531�015666� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  52385. /**
  52386. * PEAR_Dependency2, advanced dependency validation
  52387. *
  52388. * PHP versions 4 and 5
  52389. *
  52390. * @category pear
  52391. * @package PEAR
  52392. * @author Greg Beaver <cellog@php.net>
  52393. * @copyright 1997-2009 The Authors
  52394. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  52395. * @link http://pear.php.net/package/PEAR
  52396. * @since File available since Release 1.4.0a1
  52397. */
  52398. /**
  52399. * Required for the PEAR_VALIDATE_* constants
  52400. */
  52401. require_once 'PEAR/Validate.php';
  52402. /**
  52403. * Dependency check for PEAR packages
  52404. *
  52405. * This class handles both version 1.0 and 2.0 dependencies
  52406. * WARNING: *any* changes to this class must be duplicated in the
  52407. * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
  52408. * or unit tests will not actually validate the changes
  52409. * @category pear
  52410. * @package PEAR
  52411. * @author Greg Beaver <cellog@php.net>
  52412. * @copyright 1997-2009 The Authors
  52413. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  52414. * @version Release: 1.10.10
  52415. * @link http://pear.php.net/package/PEAR
  52416. * @since Class available since Release 1.4.0a1
  52417. */
  52418. class PEAR_Dependency2
  52419. {
  52420. /**
  52421. * One of the PEAR_VALIDATE_* states
  52422. * @see PEAR_VALIDATE_NORMAL
  52423. * @var integer
  52424. */
  52425. var $_state;
  52426. /**
  52427. * Command-line options to install/upgrade/uninstall commands
  52428. * @param array
  52429. */
  52430. var $_options;
  52431. /**
  52432. * @var OS_Guess
  52433. */
  52434. var $_os;
  52435. /**
  52436. * @var PEAR_Registry
  52437. */
  52438. var $_registry;
  52439. /**
  52440. * @var PEAR_Config
  52441. */
  52442. var $_config;
  52443. /**
  52444. * @var PEAR_DependencyDB
  52445. */
  52446. var $_dependencydb;
  52447. /**
  52448. * Output of PEAR_Registry::parsedPackageName()
  52449. * @var array
  52450. */
  52451. var $_currentPackage;
  52452. /**
  52453. * @param PEAR_Config
  52454. * @param array installation options
  52455. * @param array format of PEAR_Registry::parsedPackageName()
  52456. * @param int installation state (one of PEAR_VALIDATE_*)
  52457. */
  52458. function __construct(&$config, $installoptions, $package,
  52459. $state = PEAR_VALIDATE_INSTALLING)
  52460. {
  52461. $this->_config = &$config;
  52462. if (!class_exists('PEAR_DependencyDB')) {
  52463. require_once 'PEAR/DependencyDB.php';
  52464. }
  52465. if (isset($installoptions['packagingroot'])) {
  52466. // make sure depdb is in the right location
  52467. $config->setInstallRoot($installoptions['packagingroot']);
  52468. }
  52469. $this->_registry = &$config->getRegistry();
  52470. $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
  52471. if (isset($installoptions['packagingroot'])) {
  52472. $config->setInstallRoot(false);
  52473. }
  52474. $this->_options = $installoptions;
  52475. $this->_state = $state;
  52476. if (!class_exists('OS_Guess')) {
  52477. require_once 'OS/Guess.php';
  52478. }
  52479. $this->_os = new OS_Guess;
  52480. $this->_currentPackage = $package;
  52481. }
  52482. static function _getExtraString($dep)
  52483. {
  52484. $extra = ' (';
  52485. if (isset($dep['uri'])) {
  52486. return '';
  52487. }
  52488. if (isset($dep['recommended'])) {
  52489. $extra .= 'recommended version ' . $dep['recommended'];
  52490. } else {
  52491. if (isset($dep['min'])) {
  52492. $extra .= 'version >= ' . $dep['min'];
  52493. }
  52494. if (isset($dep['max'])) {
  52495. if ($extra != ' (') {
  52496. $extra .= ', ';
  52497. }
  52498. $extra .= 'version <= ' . $dep['max'];
  52499. }
  52500. if (isset($dep['exclude'])) {
  52501. if (!is_array($dep['exclude'])) {
  52502. $dep['exclude'] = array($dep['exclude']);
  52503. }
  52504. if ($extra != ' (') {
  52505. $extra .= ', ';
  52506. }
  52507. $extra .= 'excluded versions: ';
  52508. foreach ($dep['exclude'] as $i => $exclude) {
  52509. if ($i) {
  52510. $extra .= ', ';
  52511. }
  52512. $extra .= $exclude;
  52513. }
  52514. }
  52515. }
  52516. $extra .= ')';
  52517. if ($extra == ' ()') {
  52518. $extra = '';
  52519. }
  52520. return $extra;
  52521. }
  52522. /**
  52523. * This makes unit-testing a heck of a lot easier
  52524. */
  52525. function getPHP_OS()
  52526. {
  52527. return PHP_OS;
  52528. }
  52529. /**
  52530. * This makes unit-testing a heck of a lot easier
  52531. */
  52532. function getsysname()
  52533. {
  52534. return $this->_os->getSysname();
  52535. }
  52536. /**
  52537. * Specify a dependency on an OS. Use arch for detailed os/processor information
  52538. *
  52539. * There are two generic OS dependencies that will be the most common, unix and windows.
  52540. * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
  52541. */
  52542. function validateOsDependency($dep)
  52543. {
  52544. if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  52545. return true;
  52546. }
  52547. if ($dep['name'] == '*') {
  52548. return true;
  52549. }
  52550. $not = isset($dep['conflicts']) ? true : false;
  52551. switch (strtolower($dep['name'])) {
  52552. case 'windows' :
  52553. if ($not) {
  52554. if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
  52555. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52556. return $this->raiseError("Cannot install %s on Windows");
  52557. }
  52558. return $this->warning("warning: Cannot install %s on Windows");
  52559. }
  52560. } else {
  52561. if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
  52562. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52563. return $this->raiseError("Can only install %s on Windows");
  52564. }
  52565. return $this->warning("warning: Can only install %s on Windows");
  52566. }
  52567. }
  52568. break;
  52569. case 'unix' :
  52570. $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
  52571. if ($not) {
  52572. if (in_array($this->getSysname(), $unices)) {
  52573. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52574. return $this->raiseError("Cannot install %s on any Unix system");
  52575. }
  52576. return $this->warning( "warning: Cannot install %s on any Unix system");
  52577. }
  52578. } else {
  52579. if (!in_array($this->getSysname(), $unices)) {
  52580. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52581. return $this->raiseError("Can only install %s on a Unix system");
  52582. }
  52583. return $this->warning("warning: Can only install %s on a Unix system");
  52584. }
  52585. }
  52586. break;
  52587. default :
  52588. if ($not) {
  52589. if (strtolower($dep['name']) == strtolower($this->getSysname())) {
  52590. if (!isset($this->_options['nodeps']) &&
  52591. !isset($this->_options['force'])) {
  52592. return $this->raiseError('Cannot install %s on ' . $dep['name'] .
  52593. ' operating system');
  52594. }
  52595. return $this->warning('warning: Cannot install %s on ' .
  52596. $dep['name'] . ' operating system');
  52597. }
  52598. } else {
  52599. if (strtolower($dep['name']) != strtolower($this->getSysname())) {
  52600. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52601. return $this->raiseError('Cannot install %s on ' .
  52602. $this->getSysname() .
  52603. ' operating system, can only install on ' . $dep['name']);
  52604. }
  52605. return $this->warning('warning: Cannot install %s on ' .
  52606. $this->getSysname() .
  52607. ' operating system, can only install on ' . $dep['name']);
  52608. }
  52609. }
  52610. }
  52611. return true;
  52612. }
  52613. /**
  52614. * This makes unit-testing a heck of a lot easier
  52615. */
  52616. function matchSignature($pattern)
  52617. {
  52618. return $this->_os->matchSignature($pattern);
  52619. }
  52620. /**
  52621. * Specify a complex dependency on an OS/processor/kernel version,
  52622. * Use OS for simple operating system dependency.
  52623. *
  52624. * This is the only dependency that accepts an eregable pattern. The pattern
  52625. * will be matched against the php_uname() output parsed by OS_Guess
  52626. */
  52627. function validateArchDependency($dep)
  52628. {
  52629. if ($this->_state != PEAR_VALIDATE_INSTALLING) {
  52630. return true;
  52631. }
  52632. $not = isset($dep['conflicts']) ? true : false;
  52633. if (!$this->matchSignature($dep['pattern'])) {
  52634. if (!$not) {
  52635. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52636. return $this->raiseError('%s Architecture dependency failed, does not ' .
  52637. 'match "' . $dep['pattern'] . '"');
  52638. }
  52639. return $this->warning('warning: %s Architecture dependency failed, does ' .
  52640. 'not match "' . $dep['pattern'] . '"');
  52641. }
  52642. return true;
  52643. }
  52644. if ($not) {
  52645. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52646. return $this->raiseError('%s Architecture dependency failed, required "' .
  52647. $dep['pattern'] . '"');
  52648. }
  52649. return $this->warning('warning: %s Architecture dependency failed, ' .
  52650. 'required "' . $dep['pattern'] . '"');
  52651. }
  52652. return true;
  52653. }
  52654. /**
  52655. * This makes unit-testing a heck of a lot easier
  52656. */
  52657. function extension_loaded($name)
  52658. {
  52659. return extension_loaded($name);
  52660. }
  52661. /**
  52662. * This makes unit-testing a heck of a lot easier
  52663. */
  52664. function phpversion($name = null)
  52665. {
  52666. if ($name !== null) {
  52667. return phpversion($name);
  52668. }
  52669. return phpversion();
  52670. }
  52671. function validateExtensionDependency($dep, $required = true)
  52672. {
  52673. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  52674. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  52675. return true;
  52676. }
  52677. $loaded = $this->extension_loaded($dep['name']);
  52678. $extra = self::_getExtraString($dep);
  52679. if (isset($dep['exclude'])) {
  52680. if (!is_array($dep['exclude'])) {
  52681. $dep['exclude'] = array($dep['exclude']);
  52682. }
  52683. }
  52684. if (!isset($dep['min']) && !isset($dep['max']) &&
  52685. !isset($dep['recommended']) && !isset($dep['exclude'])
  52686. ) {
  52687. if ($loaded) {
  52688. if (isset($dep['conflicts'])) {
  52689. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52690. return $this->raiseError('%s conflicts with PHP extension "' .
  52691. $dep['name'] . '"' . $extra);
  52692. }
  52693. return $this->warning('warning: %s conflicts with PHP extension "' .
  52694. $dep['name'] . '"' . $extra);
  52695. }
  52696. return true;
  52697. }
  52698. if (isset($dep['conflicts'])) {
  52699. return true;
  52700. }
  52701. if ($required) {
  52702. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52703. return $this->raiseError('%s requires PHP extension "' .
  52704. $dep['name'] . '"' . $extra);
  52705. }
  52706. return $this->warning('warning: %s requires PHP extension "' .
  52707. $dep['name'] . '"' . $extra);
  52708. }
  52709. return $this->warning('%s can optionally use PHP extension "' .
  52710. $dep['name'] . '"' . $extra);
  52711. }
  52712. if (!$loaded) {
  52713. if (isset($dep['conflicts'])) {
  52714. return true;
  52715. }
  52716. if (!$required) {
  52717. return $this->warning('%s can optionally use PHP extension "' .
  52718. $dep['name'] . '"' . $extra);
  52719. }
  52720. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52721. return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  52722. '"' . $extra);
  52723. }
  52724. return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  52725. '"' . $extra);
  52726. }
  52727. $version = (string) $this->phpversion($dep['name']);
  52728. if (empty($version)) {
  52729. $version = '0';
  52730. }
  52731. $fail = false;
  52732. if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) {
  52733. $fail = true;
  52734. }
  52735. if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) {
  52736. $fail = true;
  52737. }
  52738. if ($fail && !isset($dep['conflicts'])) {
  52739. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52740. return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  52741. '"' . $extra . ', installed version is ' . $version);
  52742. }
  52743. return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  52744. '"' . $extra . ', installed version is ' . $version);
  52745. } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
  52746. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52747. return $this->raiseError('%s conflicts with PHP extension "' .
  52748. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  52749. }
  52750. return $this->warning('warning: %s conflicts with PHP extension "' .
  52751. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  52752. }
  52753. if (isset($dep['exclude'])) {
  52754. foreach ($dep['exclude'] as $exclude) {
  52755. if (version_compare($version, $exclude, '==')) {
  52756. if (isset($dep['conflicts'])) {
  52757. continue;
  52758. }
  52759. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52760. return $this->raiseError('%s is not compatible with PHP extension "' .
  52761. $dep['name'] . '" version ' .
  52762. $exclude);
  52763. }
  52764. return $this->warning('warning: %s is not compatible with PHP extension "' .
  52765. $dep['name'] . '" version ' .
  52766. $exclude);
  52767. } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  52768. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52769. return $this->raiseError('%s conflicts with PHP extension "' .
  52770. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  52771. }
  52772. return $this->warning('warning: %s conflicts with PHP extension "' .
  52773. $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  52774. }
  52775. }
  52776. }
  52777. if (isset($dep['recommended'])) {
  52778. if (version_compare($version, $dep['recommended'], '==')) {
  52779. return true;
  52780. }
  52781. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52782. return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
  52783. ' version "' . $version . '"' .
  52784. ' is not the recommended version "' . $dep['recommended'] .
  52785. '", but may be compatible, use --force to install');
  52786. }
  52787. return $this->warning('warning: %s dependency: PHP extension ' .
  52788. $dep['name'] . ' version "' . $version . '"' .
  52789. ' is not the recommended version "' . $dep['recommended'].'"');
  52790. }
  52791. return true;
  52792. }
  52793. function validatePhpDependency($dep)
  52794. {
  52795. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  52796. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  52797. return true;
  52798. }
  52799. $version = $this->phpversion();
  52800. $extra = self::_getExtraString($dep);
  52801. if (isset($dep['exclude'])) {
  52802. if (!is_array($dep['exclude'])) {
  52803. $dep['exclude'] = array($dep['exclude']);
  52804. }
  52805. }
  52806. if (isset($dep['min'])) {
  52807. if (!version_compare($version, $dep['min'], '>=')) {
  52808. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52809. return $this->raiseError('%s requires PHP' .
  52810. $extra . ', installed version is ' . $version);
  52811. }
  52812. return $this->warning('warning: %s requires PHP' .
  52813. $extra . ', installed version is ' . $version);
  52814. }
  52815. }
  52816. if (isset($dep['max'])) {
  52817. if (!version_compare($version, $dep['max'], '<=')) {
  52818. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52819. return $this->raiseError('%s requires PHP' .
  52820. $extra . ', installed version is ' . $version);
  52821. }
  52822. return $this->warning('warning: %s requires PHP' .
  52823. $extra . ', installed version is ' . $version);
  52824. }
  52825. }
  52826. if (isset($dep['exclude'])) {
  52827. foreach ($dep['exclude'] as $exclude) {
  52828. if (version_compare($version, $exclude, '==')) {
  52829. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52830. return $this->raiseError('%s is not compatible with PHP version ' .
  52831. $exclude);
  52832. }
  52833. return $this->warning(
  52834. 'warning: %s is not compatible with PHP version ' .
  52835. $exclude);
  52836. }
  52837. }
  52838. }
  52839. return true;
  52840. }
  52841. /**
  52842. * This makes unit-testing a heck of a lot easier
  52843. */
  52844. function getPEARVersion()
  52845. {
  52846. return '1.10.10';
  52847. }
  52848. function validatePearinstallerDependency($dep)
  52849. {
  52850. $pearversion = $this->getPEARVersion();
  52851. $extra = self::_getExtraString($dep);
  52852. if (isset($dep['exclude'])) {
  52853. if (!is_array($dep['exclude'])) {
  52854. $dep['exclude'] = array($dep['exclude']);
  52855. }
  52856. }
  52857. if (version_compare($pearversion, $dep['min'], '<')) {
  52858. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52859. return $this->raiseError('%s requires PEAR Installer' . $extra .
  52860. ', installed version is ' . $pearversion);
  52861. }
  52862. return $this->warning('warning: %s requires PEAR Installer' . $extra .
  52863. ', installed version is ' . $pearversion);
  52864. }
  52865. if (isset($dep['max'])) {
  52866. if (version_compare($pearversion, $dep['max'], '>')) {
  52867. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52868. return $this->raiseError('%s requires PEAR Installer' . $extra .
  52869. ', installed version is ' . $pearversion);
  52870. }
  52871. return $this->warning('warning: %s requires PEAR Installer' . $extra .
  52872. ', installed version is ' . $pearversion);
  52873. }
  52874. }
  52875. if (isset($dep['exclude'])) {
  52876. if (!isset($dep['exclude'][0])) {
  52877. $dep['exclude'] = array($dep['exclude']);
  52878. }
  52879. foreach ($dep['exclude'] as $exclude) {
  52880. if (version_compare($exclude, $pearversion, '==')) {
  52881. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  52882. return $this->raiseError('%s is not compatible with PEAR Installer ' .
  52883. 'version ' . $exclude);
  52884. }
  52885. return $this->warning('warning: %s is not compatible with PEAR ' .
  52886. 'Installer version ' . $exclude);
  52887. }
  52888. }
  52889. }
  52890. return true;
  52891. }
  52892. function validateSubpackageDependency($dep, $required, $params)
  52893. {
  52894. return $this->validatePackageDependency($dep, $required, $params);
  52895. }
  52896. /**
  52897. * @param array dependency information (2.0 format)
  52898. * @param boolean whether this is a required dependency
  52899. * @param array a list of downloaded packages to be installed, if any
  52900. * @param boolean if true, then deps on pear.php.net that fail will also check
  52901. * against pecl.php.net packages to accommodate extensions that have
  52902. * moved to pecl.php.net from pear.php.net
  52903. */
  52904. function validatePackageDependency($dep, $required, $params, $depv1 = false)
  52905. {
  52906. if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  52907. $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  52908. return true;
  52909. }
  52910. if (isset($dep['providesextension'])) {
  52911. if ($this->extension_loaded($dep['providesextension'])) {
  52912. $save = $dep;
  52913. $subdep = $dep;
  52914. $subdep['name'] = $subdep['providesextension'];
  52915. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  52916. $ret = $this->validateExtensionDependency($subdep, $required);
  52917. PEAR::popErrorHandling();
  52918. if (!PEAR::isError($ret)) {
  52919. return true;
  52920. }
  52921. }
  52922. }
  52923. if ($this->_state == PEAR_VALIDATE_INSTALLING) {
  52924. return $this->_validatePackageInstall($dep, $required, $depv1);
  52925. }
  52926. if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
  52927. return $this->_validatePackageDownload($dep, $required, $params, $depv1);
  52928. }
  52929. }
  52930. function _validatePackageDownload($dep, $required, $params, $depv1 = false)
  52931. {
  52932. $dep['package'] = $dep['name'];
  52933. if (isset($dep['uri'])) {
  52934. $dep['channel'] = '__uri';
  52935. }
  52936. $depname = $this->_registry->parsedPackageNameToString($dep, true);
  52937. $found = false;
  52938. foreach ($params as $param) {
  52939. if ($param->isEqual(
  52940. array('package' => $dep['name'],
  52941. 'channel' => $dep['channel']))) {
  52942. $found = true;
  52943. break;
  52944. }
  52945. if ($depv1 && $dep['channel'] == 'pear.php.net') {
  52946. if ($param->isEqual(
  52947. array('package' => $dep['name'],
  52948. 'channel' => 'pecl.php.net'))) {
  52949. $found = true;
  52950. break;
  52951. }
  52952. }
  52953. }
  52954. if (!$found && isset($dep['providesextension'])) {
  52955. foreach ($params as $param) {
  52956. if ($param->isExtension($dep['providesextension'])) {
  52957. $found = true;
  52958. break;
  52959. }
  52960. }
  52961. }
  52962. if ($found) {
  52963. $version = $param->getVersion();
  52964. $installed = false;
  52965. $downloaded = true;
  52966. } else {
  52967. if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
  52968. $installed = true;
  52969. $downloaded = false;
  52970. $version = $this->_registry->packageinfo($dep['name'], 'version',
  52971. $dep['channel']);
  52972. } else {
  52973. if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
  52974. 'pear.php.net')) {
  52975. $installed = true;
  52976. $downloaded = false;
  52977. $version = $this->_registry->packageinfo($dep['name'], 'version',
  52978. 'pear.php.net');
  52979. } else {
  52980. $version = 'not installed or downloaded';
  52981. $installed = false;
  52982. $downloaded = false;
  52983. }
  52984. }
  52985. }
  52986. $extra = self::_getExtraString($dep);
  52987. if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
  52988. $dep['exclude'] = array($dep['exclude']);
  52989. }
  52990. if (!isset($dep['min']) && !isset($dep['max']) &&
  52991. !isset($dep['recommended']) && !isset($dep['exclude'])
  52992. ) {
  52993. if ($installed || $downloaded) {
  52994. $installed = $installed ? 'installed' : 'downloaded';
  52995. if (isset($dep['conflicts'])) {
  52996. $rest = '';
  52997. if ($version) {
  52998. $rest = ", $installed version is " . $version;
  52999. }
  53000. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53001. return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest);
  53002. }
  53003. return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest);
  53004. }
  53005. return true;
  53006. }
  53007. if (isset($dep['conflicts'])) {
  53008. return true;
  53009. }
  53010. if ($required) {
  53011. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53012. return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
  53013. }
  53014. return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
  53015. }
  53016. return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
  53017. }
  53018. if (!$installed && !$downloaded) {
  53019. if (isset($dep['conflicts'])) {
  53020. return true;
  53021. }
  53022. if ($required) {
  53023. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53024. return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
  53025. }
  53026. return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
  53027. }
  53028. return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
  53029. }
  53030. $fail = false;
  53031. if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) {
  53032. $fail = true;
  53033. }
  53034. if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) {
  53035. $fail = true;
  53036. }
  53037. if ($fail && !isset($dep['conflicts'])) {
  53038. $installed = $installed ? 'installed' : 'downloaded';
  53039. $dep['package'] = $dep['name'];
  53040. $dep = $this->_registry->parsedPackageNameToString($dep, true);
  53041. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53042. return $this->raiseError('%s requires package "' . $depname . '"' .
  53043. $extra . ", $installed version is " . $version);
  53044. }
  53045. return $this->warning('warning: %s requires package "' . $depname . '"' .
  53046. $extra . ", $installed version is " . $version);
  53047. } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
  53048. isset($dep['conflicts']) && !isset($dep['exclude'])) {
  53049. $installed = $installed ? 'installed' : 'downloaded';
  53050. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53051. return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
  53052. ", $installed version is " . $version);
  53053. }
  53054. return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  53055. $extra . ", $installed version is " . $version);
  53056. }
  53057. if (isset($dep['exclude'])) {
  53058. $installed = $installed ? 'installed' : 'downloaded';
  53059. foreach ($dep['exclude'] as $exclude) {
  53060. if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
  53061. if (!isset($this->_options['nodeps']) &&
  53062. !isset($this->_options['force'])
  53063. ) {
  53064. return $this->raiseError('%s is not compatible with ' .
  53065. $installed . ' package "' .
  53066. $depname . '" version ' .
  53067. $exclude);
  53068. }
  53069. return $this->warning('warning: %s is not compatible with ' .
  53070. $installed . ' package "' .
  53071. $depname . '" version ' .
  53072. $exclude);
  53073. } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  53074. $installed = $installed ? 'installed' : 'downloaded';
  53075. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53076. return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  53077. $extra . ", $installed version is " . $version);
  53078. }
  53079. return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  53080. $extra . ", $installed version is " . $version);
  53081. }
  53082. }
  53083. }
  53084. if (isset($dep['recommended'])) {
  53085. $installed = $installed ? 'installed' : 'downloaded';
  53086. if (version_compare($version, $dep['recommended'], '==')) {
  53087. return true;
  53088. }
  53089. if (!$found && $installed) {
  53090. $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
  53091. }
  53092. if ($param) {
  53093. $found = false;
  53094. foreach ($params as $parent) {
  53095. if ($parent->isEqual($this->_currentPackage)) {
  53096. $found = true;
  53097. break;
  53098. }
  53099. }
  53100. if ($found) {
  53101. if ($param->isCompatible($parent)) {
  53102. return true;
  53103. }
  53104. } else { // this is for validPackage() calls
  53105. $parent = $this->_registry->getPackage($this->_currentPackage['package'],
  53106. $this->_currentPackage['channel']);
  53107. if ($parent !== null && $param->isCompatible($parent)) {
  53108. return true;
  53109. }
  53110. }
  53111. }
  53112. if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
  53113. !isset($this->_options['loose'])
  53114. ) {
  53115. return $this->raiseError('%s dependency package "' . $depname .
  53116. '" ' . $installed . ' version ' . $version .
  53117. ' is not the recommended version ' . $dep['recommended'] .
  53118. ', but may be compatible, use --force to install');
  53119. }
  53120. return $this->warning('warning: %s dependency package "' . $depname .
  53121. '" ' . $installed . ' version ' . $version .
  53122. ' is not the recommended version ' . $dep['recommended']);
  53123. }
  53124. return true;
  53125. }
  53126. function _validatePackageInstall($dep, $required, $depv1 = false)
  53127. {
  53128. return $this->_validatePackageDownload($dep, $required, array(), $depv1);
  53129. }
  53130. /**
  53131. * Verify that uninstalling packages passed in to command line is OK.
  53132. *
  53133. * @param PEAR_Installer $dl
  53134. * @return PEAR_Error|true
  53135. */
  53136. function validatePackageUninstall(&$dl)
  53137. {
  53138. if (PEAR::isError($this->_dependencydb)) {
  53139. return $this->_dependencydb;
  53140. }
  53141. $params = array();
  53142. // construct an array of "downloaded" packages to fool the package dependency checker
  53143. // into using these to validate uninstalls of circular dependencies
  53144. $downloaded = &$dl->getUninstallPackages();
  53145. foreach ($downloaded as $i => $pf) {
  53146. if (!class_exists('PEAR_Downloader_Package')) {
  53147. require_once 'PEAR/Downloader/Package.php';
  53148. }
  53149. $dp = new PEAR_Downloader_Package($dl);
  53150. $dp->setPackageFile($downloaded[$i]);
  53151. $params[$i] = $dp;
  53152. }
  53153. // check cache
  53154. $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' .
  53155. strtolower($this->_currentPackage['package']);
  53156. if (isset($dl->___uninstall_package_cache)) {
  53157. $badpackages = $dl->___uninstall_package_cache;
  53158. if (isset($badpackages[$memyselfandI]['warnings'])) {
  53159. foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  53160. $dl->log(0, $warning[0]);
  53161. }
  53162. }
  53163. if (isset($badpackages[$memyselfandI]['errors'])) {
  53164. foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  53165. if (is_array($error)) {
  53166. $dl->log(0, $error[0]);
  53167. } else {
  53168. $dl->log(0, $error->getMessage());
  53169. }
  53170. }
  53171. if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  53172. return $this->warning(
  53173. 'warning: %s should not be uninstalled, other installed packages depend ' .
  53174. 'on this package');
  53175. }
  53176. return $this->raiseError(
  53177. '%s cannot be uninstalled, other installed packages depend on this package');
  53178. }
  53179. return true;
  53180. }
  53181. // first, list the immediate parents of each package to be uninstalled
  53182. $perpackagelist = array();
  53183. $allparents = array();
  53184. foreach ($params as $i => $param) {
  53185. $a = array(
  53186. 'channel' => strtolower($param->getChannel()),
  53187. 'package' => strtolower($param->getPackage())
  53188. );
  53189. $deps = $this->_dependencydb->getDependentPackages($a);
  53190. if ($deps) {
  53191. foreach ($deps as $d) {
  53192. $pardeps = $this->_dependencydb->getDependencies($d);
  53193. foreach ($pardeps as $dep) {
  53194. if (strtolower($dep['dep']['channel']) == $a['channel'] &&
  53195. strtolower($dep['dep']['name']) == $a['package']) {
  53196. if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) {
  53197. $perpackagelist[$a['channel'] . '/' . $a['package']] = array();
  53198. }
  53199. $perpackagelist[$a['channel'] . '/' . $a['package']][]
  53200. = array($d['channel'] . '/' . $d['package'], $dep);
  53201. if (!isset($allparents[$d['channel'] . '/' . $d['package']])) {
  53202. $allparents[$d['channel'] . '/' . $d['package']] = array();
  53203. }
  53204. if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) {
  53205. $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array();
  53206. }
  53207. $allparents[$d['channel'] . '/' . $d['package']]
  53208. [$a['channel'] . '/' . $a['package']][]
  53209. = array($d, $dep);
  53210. }
  53211. }
  53212. }
  53213. }
  53214. }
  53215. // next, remove any packages from the parents list that are not installed
  53216. $remove = array();
  53217. foreach ($allparents as $parent => $d1) {
  53218. foreach ($d1 as $d) {
  53219. if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) {
  53220. continue;
  53221. }
  53222. $remove[$parent] = true;
  53223. }
  53224. }
  53225. // next remove any packages from the parents list that are not passed in for
  53226. // uninstallation
  53227. foreach ($allparents as $parent => $d1) {
  53228. foreach ($d1 as $d) {
  53229. foreach ($params as $param) {
  53230. if (strtolower($param->getChannel()) == $d[0][0]['channel'] &&
  53231. strtolower($param->getPackage()) == $d[0][0]['package']) {
  53232. // found it
  53233. continue 3;
  53234. }
  53235. }
  53236. $remove[$parent] = true;
  53237. }
  53238. }
  53239. // remove all packages whose dependencies fail
  53240. // save which ones failed for error reporting
  53241. $badchildren = array();
  53242. do {
  53243. $fail = false;
  53244. foreach ($remove as $package => $unused) {
  53245. if (!isset($allparents[$package])) {
  53246. continue;
  53247. }
  53248. foreach ($allparents[$package] as $kid => $d1) {
  53249. foreach ($d1 as $depinfo) {
  53250. if ($depinfo[1]['type'] != 'optional') {
  53251. if (isset($badchildren[$kid])) {
  53252. continue;
  53253. }
  53254. $badchildren[$kid] = true;
  53255. $remove[$kid] = true;
  53256. $fail = true;
  53257. continue 2;
  53258. }
  53259. }
  53260. }
  53261. if ($fail) {
  53262. // start over, we removed some children
  53263. continue 2;
  53264. }
  53265. }
  53266. } while ($fail);
  53267. // next, construct the list of packages that can't be uninstalled
  53268. $badpackages = array();
  53269. $save = $this->_currentPackage;
  53270. foreach ($perpackagelist as $package => $packagedeps) {
  53271. foreach ($packagedeps as $parent) {
  53272. if (!isset($remove[$parent[0]])) {
  53273. continue;
  53274. }
  53275. $packagename = $this->_registry->parsePackageName($parent[0]);
  53276. $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']);
  53277. $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']);
  53278. $packagename['package'] = $pa->getPackage();
  53279. $this->_currentPackage = $packagename;
  53280. // parent is not present in uninstall list, make sure we can actually
  53281. // uninstall it (parent dep is optional)
  53282. $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']);
  53283. $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']);
  53284. $parentname['package'] = $pa->getPackage();
  53285. $parent[1]['dep']['package'] = $parentname['package'];
  53286. $parent[1]['dep']['channel'] = $parentname['channel'];
  53287. if ($parent[1]['type'] == 'optional') {
  53288. $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl);
  53289. if ($test !== true) {
  53290. $badpackages[$package]['warnings'][] = $test;
  53291. }
  53292. } else {
  53293. $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl);
  53294. if ($test !== true) {
  53295. $badpackages[$package]['errors'][] = $test;
  53296. }
  53297. }
  53298. }
  53299. }
  53300. $this->_currentPackage = $save;
  53301. $dl->___uninstall_package_cache = $badpackages;
  53302. if (isset($badpackages[$memyselfandI])) {
  53303. if (isset($badpackages[$memyselfandI]['warnings'])) {
  53304. foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
  53305. $dl->log(0, $warning[0]);
  53306. }
  53307. }
  53308. if (isset($badpackages[$memyselfandI]['errors'])) {
  53309. foreach ($badpackages[$memyselfandI]['errors'] as $error) {
  53310. if (is_array($error)) {
  53311. $dl->log(0, $error[0]);
  53312. } else {
  53313. $dl->log(0, $error->getMessage());
  53314. }
  53315. }
  53316. if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  53317. return $this->warning(
  53318. 'warning: %s should not be uninstalled, other installed packages depend ' .
  53319. 'on this package');
  53320. }
  53321. return $this->raiseError(
  53322. '%s cannot be uninstalled, other installed packages depend on this package');
  53323. }
  53324. }
  53325. return true;
  53326. }
  53327. function _validatePackageUninstall($dep, $required, $dl)
  53328. {
  53329. $depname = $this->_registry->parsedPackageNameToString($dep, true);
  53330. $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']);
  53331. if (!$version) {
  53332. return true;
  53333. }
  53334. $extra = self::_getExtraString($dep);
  53335. if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
  53336. $dep['exclude'] = array($dep['exclude']);
  53337. }
  53338. if (isset($dep['conflicts'])) {
  53339. return true; // uninstall OK - these packages conflict (probably installed with --force)
  53340. }
  53341. if (!isset($dep['min']) && !isset($dep['max'])) {
  53342. if (!$required) {
  53343. return $this->warning('"' . $depname . '" can be optionally used by ' .
  53344. 'installed package %s' . $extra);
  53345. }
  53346. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53347. return $this->raiseError('"' . $depname . '" is required by ' .
  53348. 'installed package %s' . $extra);
  53349. }
  53350. return $this->warning('warning: "' . $depname . '" is required by ' .
  53351. 'installed package %s' . $extra);
  53352. }
  53353. $fail = false;
  53354. if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) {
  53355. $fail = true;
  53356. }
  53357. if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) {
  53358. $fail = true;
  53359. }
  53360. // we re-use this variable, preserve the original value
  53361. $saverequired = $required;
  53362. if (!$required) {
  53363. return $this->warning($depname . $extra . ' can be optionally used by installed package' .
  53364. ' "%s"');
  53365. }
  53366. if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  53367. return $this->raiseError($depname . $extra . ' is required by installed package' .
  53368. ' "%s"');
  53369. }
  53370. return $this->raiseError('warning: ' . $depname . $extra .
  53371. ' is required by installed package "%s"');
  53372. }
  53373. /**
  53374. * validate a downloaded package against installed packages
  53375. *
  53376. * As of PEAR 1.4.3, this will only validate
  53377. *
  53378. * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  53379. * $pkg package identifier (either
  53380. * array('package' => blah, 'channel' => blah) or an array with
  53381. * index 'info' referencing an object)
  53382. * @param PEAR_Downloader $dl
  53383. * @param array $params full list of packages to install
  53384. * @return true|PEAR_Error
  53385. */
  53386. function validatePackage($pkg, &$dl, $params = array())
  53387. {
  53388. if (is_array($pkg) && isset($pkg['info'])) {
  53389. $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
  53390. } else {
  53391. $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
  53392. }
  53393. $fail = false;
  53394. if ($deps) {
  53395. if (!class_exists('PEAR_Downloader_Package')) {
  53396. require_once 'PEAR/Downloader/Package.php';
  53397. }
  53398. $dp = new PEAR_Downloader_Package($dl);
  53399. if (is_object($pkg)) {
  53400. $dp->setPackageFile($pkg);
  53401. } else {
  53402. $dp->setDownloadURL($pkg);
  53403. }
  53404. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  53405. foreach ($deps as $channel => $info) {
  53406. foreach ($info as $package => $ds) {
  53407. foreach ($params as $packd) {
  53408. if (strtolower($packd->getPackage()) == strtolower($package) &&
  53409. $packd->getChannel() == $channel) {
  53410. $dl->log(3, 'skipping installed package check of "' .
  53411. $this->_registry->parsedPackageNameToString(
  53412. array('channel' => $channel, 'package' => $package),
  53413. true) .
  53414. '", version "' . $packd->getVersion() . '" will be ' .
  53415. 'downloaded and installed');
  53416. continue 2; // jump to next package
  53417. }
  53418. }
  53419. foreach ($ds as $d) {
  53420. $checker = new PEAR_Dependency2($this->_config, $this->_options,
  53421. array('channel' => $channel, 'package' => $package), $this->_state);
  53422. $dep = $d['dep'];
  53423. $required = $d['type'] == 'required';
  53424. $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
  53425. if (is_array($ret)) {
  53426. $dl->log(0, $ret[0]);
  53427. } elseif (PEAR::isError($ret)) {
  53428. $dl->log(0, $ret->getMessage());
  53429. $fail = true;
  53430. }
  53431. }
  53432. }
  53433. }
  53434. PEAR::popErrorHandling();
  53435. }
  53436. if ($fail) {
  53437. return $this->raiseError(
  53438. '%s cannot be installed, conflicts with installed packages');
  53439. }
  53440. return true;
  53441. }
  53442. /**
  53443. * validate a package.xml 1.0 dependency
  53444. */
  53445. function validateDependency1($dep, $params = array())
  53446. {
  53447. if (!isset($dep['optional'])) {
  53448. $dep['optional'] = 'no';
  53449. }
  53450. list($newdep, $type) = self::normalizeDep($dep);
  53451. if (!$newdep) {
  53452. return $this->raiseError("Invalid Dependency");
  53453. }
  53454. if (method_exists($this, "validate{$type}Dependency")) {
  53455. return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
  53456. $params, true);
  53457. }
  53458. }
  53459. /**
  53460. * Convert a 1.0 dep into a 2.0 dep
  53461. */
  53462. static function normalizeDep($dep)
  53463. {
  53464. $types = array(
  53465. 'pkg' => 'Package',
  53466. 'ext' => 'Extension',
  53467. 'os' => 'Os',
  53468. 'php' => 'Php'
  53469. );
  53470. if (!isset($types[$dep['type']])) {
  53471. return array(false, false);
  53472. }
  53473. $type = $types[$dep['type']];
  53474. $newdep = array();
  53475. switch ($type) {
  53476. case 'Package' :
  53477. $newdep['channel'] = 'pear.php.net';
  53478. case 'Extension' :
  53479. case 'Os' :
  53480. $newdep['name'] = $dep['name'];
  53481. break;
  53482. }
  53483. $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
  53484. switch ($dep['rel']) {
  53485. case 'has' :
  53486. return array($newdep, $type);
  53487. break;
  53488. case 'not' :
  53489. $newdep['conflicts'] = true;
  53490. break;
  53491. case '>=' :
  53492. case '>' :
  53493. $newdep['min'] = $dep['version'];
  53494. if ($dep['rel'] == '>') {
  53495. $newdep['exclude'] = $dep['version'];
  53496. }
  53497. break;
  53498. case '<=' :
  53499. case '<' :
  53500. $newdep['max'] = $dep['version'];
  53501. if ($dep['rel'] == '<') {
  53502. $newdep['exclude'] = $dep['version'];
  53503. }
  53504. break;
  53505. case 'ne' :
  53506. case '!=' :
  53507. $newdep['min'] = '0';
  53508. $newdep['max'] = '100000';
  53509. $newdep['exclude'] = $dep['version'];
  53510. break;
  53511. case '==' :
  53512. $newdep['min'] = $dep['version'];
  53513. $newdep['max'] = $dep['version'];
  53514. break;
  53515. }
  53516. if ($type == 'Php') {
  53517. if (!isset($newdep['min'])) {
  53518. $newdep['min'] = '4.4.0';
  53519. }
  53520. if (!isset($newdep['max'])) {
  53521. $newdep['max'] = '6.0.0';
  53522. }
  53523. }
  53524. return array($newdep, $type);
  53525. }
  53526. /**
  53527. * Converts text comparing operators to them sign equivalents
  53528. *
  53529. * Example: 'ge' to '>='
  53530. *
  53531. * @access public
  53532. * @param string Operator
  53533. * @return string Sign equivalent
  53534. */
  53535. static function signOperator($operator)
  53536. {
  53537. switch($operator) {
  53538. case 'lt': return '<';
  53539. case 'le': return '<=';
  53540. case 'gt': return '>';
  53541. case 'ge': return '>=';
  53542. case 'eq': return '==';
  53543. case 'ne': return '!=';
  53544. default:
  53545. return $operator;
  53546. }
  53547. }
  53548. function raiseError($msg)
  53549. {
  53550. if (isset($this->_options['ignore-errors'])) {
  53551. return $this->warning($msg);
  53552. }
  53553. return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
  53554. $this->_currentPackage, true)));
  53555. }
  53556. function warning($msg)
  53557. {
  53558. return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
  53559. $this->_currentPackage, true)));
  53560. }
  53561. }
  53562. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Downloader.php��������������������������������������������������������������������0000644�0001750�0001750�00000200700�13565304531�015613� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  53563. /**
  53564. * PEAR_Downloader, the PEAR Installer's download utility class
  53565. *
  53566. * PHP versions 4 and 5
  53567. *
  53568. * @category pear
  53569. * @package PEAR
  53570. * @author Greg Beaver <cellog@php.net>
  53571. * @author Stig Bakken <ssb@php.net>
  53572. * @author Tomas V. V. Cox <cox@idecnet.com>
  53573. * @author Martin Jansen <mj@php.net>
  53574. * @copyright 1997-2009 The Authors
  53575. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  53576. * @link http://pear.php.net/package/PEAR
  53577. * @since File available since Release 1.3.0
  53578. */
  53579. /**
  53580. * Needed for constants, extending
  53581. */
  53582. require_once 'PEAR/Common.php';
  53583. require_once 'PEAR/Proxy.php';
  53584. define('PEAR_INSTALLER_OK', 1);
  53585. define('PEAR_INSTALLER_FAILED', 0);
  53586. define('PEAR_INSTALLER_SKIPPED', -1);
  53587. define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
  53588. /**
  53589. * Administration class used to download anything from the internet (PEAR Packages,
  53590. * static URLs, xml files)
  53591. *
  53592. * @category pear
  53593. * @package PEAR
  53594. * @author Greg Beaver <cellog@php.net>
  53595. * @author Stig Bakken <ssb@php.net>
  53596. * @author Tomas V. V. Cox <cox@idecnet.com>
  53597. * @author Martin Jansen <mj@php.net>
  53598. * @copyright 1997-2009 The Authors
  53599. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  53600. * @version Release: 1.10.10
  53601. * @link http://pear.php.net/package/PEAR
  53602. * @since Class available since Release 1.3.0
  53603. */
  53604. class PEAR_Downloader extends PEAR_Common
  53605. {
  53606. /**
  53607. * @var PEAR_Registry
  53608. * @access private
  53609. */
  53610. var $_registry;
  53611. /**
  53612. * Preferred Installation State (snapshot, devel, alpha, beta, stable)
  53613. * @var string|null
  53614. * @access private
  53615. */
  53616. var $_preferredState;
  53617. /**
  53618. * Options from command-line passed to Install.
  53619. *
  53620. * Recognized options:<br />
  53621. * - onlyreqdeps : install all required dependencies as well
  53622. * - alldeps : install all dependencies, including optional
  53623. * - installroot : base relative path to install files in
  53624. * - force : force a download even if warnings would prevent it
  53625. * - nocompress : download uncompressed tarballs
  53626. * - configureoptions : additional configure options
  53627. * @see PEAR_Command_Install
  53628. * @access private
  53629. * @var array
  53630. */
  53631. var $_options;
  53632. /**
  53633. * Downloaded Packages after a call to download().
  53634. *
  53635. * Format of each entry:
  53636. *
  53637. * <code>
  53638. * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
  53639. * 'info' => array() // parsed package.xml
  53640. * );
  53641. * </code>
  53642. * @access private
  53643. * @var array
  53644. */
  53645. var $_downloadedPackages = array();
  53646. /**
  53647. * Packages slated for download.
  53648. *
  53649. * This is used to prevent downloading a package more than once should it be a dependency
  53650. * for two packages to be installed.
  53651. * Format of each entry:
  53652. *
  53653. * <pre>
  53654. * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
  53655. * );
  53656. * </pre>
  53657. * @access private
  53658. * @var array
  53659. */
  53660. var $_toDownload = array();
  53661. /**
  53662. * Array of every package installed, with names lower-cased.
  53663. *
  53664. * Format:
  53665. * <code>
  53666. * array('package1' => 0, 'package2' => 1, );
  53667. * </code>
  53668. * @var array
  53669. */
  53670. var $_installed = array();
  53671. /**
  53672. * @var array
  53673. * @access private
  53674. */
  53675. var $_errorStack = array();
  53676. /**
  53677. * @var boolean
  53678. * @access private
  53679. */
  53680. var $_internalDownload = false;
  53681. /**
  53682. * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
  53683. * @var array
  53684. * @access private
  53685. */
  53686. var $_packageSortTree;
  53687. /**
  53688. * Temporary directory, or configuration value where downloads will occur
  53689. * @var string
  53690. */
  53691. var $_downloadDir;
  53692. /**
  53693. * List of methods that can be called both statically and non-statically.
  53694. * @var array
  53695. */
  53696. protected static $bivalentMethods = array(
  53697. 'setErrorHandling' => true,
  53698. 'raiseError' => true,
  53699. 'throwError' => true,
  53700. 'pushErrorHandling' => true,
  53701. 'popErrorHandling' => true,
  53702. 'downloadHttp' => true,
  53703. );
  53704. /**
  53705. * @param PEAR_Frontend_*
  53706. * @param array
  53707. * @param PEAR_Config
  53708. */
  53709. function __construct($ui = null, $options = array(), $config = null)
  53710. {
  53711. parent::__construct();
  53712. $this->_options = $options;
  53713. if ($config !== null) {
  53714. $this->config = &$config;
  53715. $this->_preferredState = $this->config->get('preferred_state');
  53716. }
  53717. $this->ui = &$ui;
  53718. if (!$this->_preferredState) {
  53719. // don't inadvertently use a non-set preferred_state
  53720. $this->_preferredState = null;
  53721. }
  53722. if ($config !== null) {
  53723. if (isset($this->_options['installroot'])) {
  53724. $this->config->setInstallRoot($this->_options['installroot']);
  53725. }
  53726. $this->_registry = &$config->getRegistry();
  53727. }
  53728. if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
  53729. $this->_installed = $this->_registry->listAllPackages();
  53730. foreach ($this->_installed as $key => $unused) {
  53731. if (!count($unused)) {
  53732. continue;
  53733. }
  53734. $strtolower = function($a) { return strtolower($a); };
  53735. array_walk($this->_installed[$key], $strtolower);
  53736. }
  53737. }
  53738. }
  53739. /**
  53740. * Attempt to discover a channel's remote capabilities from
  53741. * its server name
  53742. * @param string
  53743. * @return boolean
  53744. */
  53745. function discover($channel)
  53746. {
  53747. $this->log(1, 'Attempting to discover channel "' . $channel . '"...');
  53748. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  53749. $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
  53750. if (!class_exists('System')) {
  53751. require_once 'System.php';
  53752. }
  53753. $tmpdir = $this->config->get('temp_dir');
  53754. $tmp = System::mktemp('-d -t "' . $tmpdir . '"');
  53755. $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false);
  53756. PEAR::popErrorHandling();
  53757. if (PEAR::isError($a)) {
  53758. // Attempt to fallback to https automatically.
  53759. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  53760. $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...');
  53761. $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false);
  53762. PEAR::popErrorHandling();
  53763. if (PEAR::isError($a)) {
  53764. return false;
  53765. }
  53766. }
  53767. list($a, $lastmodified) = $a;
  53768. if (!class_exists('PEAR_ChannelFile')) {
  53769. require_once 'PEAR/ChannelFile.php';
  53770. }
  53771. $b = new PEAR_ChannelFile;
  53772. if ($b->fromXmlFile($a)) {
  53773. unlink($a);
  53774. if ($this->config->get('auto_discover')) {
  53775. $this->_registry->addChannel($b, $lastmodified);
  53776. $alias = $b->getName();
  53777. if ($b->getName() == $this->_registry->channelName($b->getAlias())) {
  53778. $alias = $b->getAlias();
  53779. }
  53780. $this->log(1, 'Auto-discovered channel "' . $channel .
  53781. '", alias "' . $alias . '", adding to registry');
  53782. }
  53783. return true;
  53784. }
  53785. unlink($a);
  53786. return false;
  53787. }
  53788. /**
  53789. * For simpler unit-testing
  53790. * @param PEAR_Downloader
  53791. * @return PEAR_Downloader_Package
  53792. */
  53793. function newDownloaderPackage(&$t)
  53794. {
  53795. if (!class_exists('PEAR_Downloader_Package')) {
  53796. require_once 'PEAR/Downloader/Package.php';
  53797. }
  53798. $a = new PEAR_Downloader_Package($t);
  53799. return $a;
  53800. }
  53801. /**
  53802. * For simpler unit-testing
  53803. * @param PEAR_Config
  53804. * @param array
  53805. * @param array
  53806. * @param int
  53807. */
  53808. function &getDependency2Object(&$c, $i, $p, $s)
  53809. {
  53810. if (!class_exists('PEAR_Dependency2')) {
  53811. require_once 'PEAR/Dependency2.php';
  53812. }
  53813. $z = new PEAR_Dependency2($c, $i, $p, $s);
  53814. return $z;
  53815. }
  53816. function &download($params)
  53817. {
  53818. if (!count($params)) {
  53819. $a = array();
  53820. return $a;
  53821. }
  53822. if (!isset($this->_registry)) {
  53823. $this->_registry = &$this->config->getRegistry();
  53824. }
  53825. $channelschecked = array();
  53826. // convert all parameters into PEAR_Downloader_Package objects
  53827. foreach ($params as $i => $param) {
  53828. $params[$i] = $this->newDownloaderPackage($this);
  53829. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  53830. $err = $params[$i]->initialize($param);
  53831. PEAR::staticPopErrorHandling();
  53832. if (!$err) {
  53833. // skip parameters that were missed by preferred_state
  53834. continue;
  53835. }
  53836. if (PEAR::isError($err)) {
  53837. if (!isset($this->_options['soft']) && $err->getMessage() !== '') {
  53838. $this->log(0, $err->getMessage());
  53839. }
  53840. $params[$i] = false;
  53841. if (is_object($param)) {
  53842. $param = $param->getChannel() . '/' . $param->getPackage();
  53843. }
  53844. if (!isset($this->_options['soft'])) {
  53845. $this->log(2, 'Package "' . $param . '" is not valid');
  53846. }
  53847. // Message logged above in a specific verbose mode, passing null to not show up on CLI
  53848. $this->pushError(null, PEAR_INSTALLER_SKIPPED);
  53849. } else {
  53850. do {
  53851. if ($params[$i] && $params[$i]->getType() == 'local') {
  53852. // bug #7090 skip channel.xml check for local packages
  53853. break;
  53854. }
  53855. if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) &&
  53856. !isset($this->_options['offline'])
  53857. ) {
  53858. $channelschecked[$params[$i]->getChannel()] = true;
  53859. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  53860. if (!class_exists('System')) {
  53861. require_once 'System.php';
  53862. }
  53863. $curchannel = $this->_registry->getChannel($params[$i]->getChannel());
  53864. if (PEAR::isError($curchannel)) {
  53865. PEAR::staticPopErrorHandling();
  53866. return $this->raiseError($curchannel);
  53867. }
  53868. if (PEAR::isError($dir = $this->getDownloadDir())) {
  53869. PEAR::staticPopErrorHandling();
  53870. break;
  53871. }
  53872. $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel());
  53873. $url = 'http://' . $mirror . '/channel.xml';
  53874. $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified());
  53875. PEAR::staticPopErrorHandling();
  53876. if ($a === false) {
  53877. //channel.xml not modified
  53878. break;
  53879. } else if (PEAR::isError($a)) {
  53880. // Attempt fallback to https automatically
  53881. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  53882. $a = $this->downloadHttp('https://' . $mirror .
  53883. '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified());
  53884. PEAR::staticPopErrorHandling();
  53885. if (PEAR::isError($a) || !$a) {
  53886. break;
  53887. }
  53888. }
  53889. $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' .
  53890. 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() .
  53891. '" to update');
  53892. }
  53893. } while (false);
  53894. if ($params[$i] && !isset($this->_options['downloadonly'])) {
  53895. if (isset($this->_options['packagingroot'])) {
  53896. $checkdir = $this->_prependPath(
  53897. $this->config->get('php_dir', null, $params[$i]->getChannel()),
  53898. $this->_options['packagingroot']);
  53899. } else {
  53900. $checkdir = $this->config->get('php_dir',
  53901. null, $params[$i]->getChannel());
  53902. }
  53903. while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) {
  53904. $checkdir = dirname($checkdir);
  53905. }
  53906. if ($checkdir == '.') {
  53907. $checkdir = '/';
  53908. }
  53909. if (!is_writeable($checkdir)) {
  53910. return PEAR::raiseError('Cannot install, php_dir for channel "' .
  53911. $params[$i]->getChannel() . '" is not writeable by the current user');
  53912. }
  53913. }
  53914. }
  53915. }
  53916. unset($channelschecked);
  53917. PEAR_Downloader_Package::removeDuplicates($params);
  53918. if (!count($params)) {
  53919. $a = array();
  53920. return $a;
  53921. }
  53922. if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) {
  53923. $reverify = true;
  53924. while ($reverify) {
  53925. $reverify = false;
  53926. foreach ($params as $i => $param) {
  53927. //PHP Bug 40768 / PEAR Bug #10944
  53928. //Nested foreaches fail in PHP 5.2.1
  53929. key($params);
  53930. $ret = $params[$i]->detectDependencies($params);
  53931. if (PEAR::isError($ret)) {
  53932. $reverify = true;
  53933. $params[$i] = false;
  53934. PEAR_Downloader_Package::removeDuplicates($params);
  53935. if (!isset($this->_options['soft'])) {
  53936. $this->log(0, $ret->getMessage());
  53937. }
  53938. continue 2;
  53939. }
  53940. }
  53941. }
  53942. }
  53943. if (isset($this->_options['offline'])) {
  53944. $this->log(3, 'Skipping dependency download check, --offline specified');
  53945. }
  53946. if (!count($params)) {
  53947. $a = array();
  53948. return $a;
  53949. }
  53950. while (PEAR_Downloader_Package::mergeDependencies($params));
  53951. PEAR_Downloader_Package::removeDuplicates($params, true);
  53952. $errorparams = array();
  53953. if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) {
  53954. if (count($errorparams)) {
  53955. foreach ($errorparams as $param) {
  53956. $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage());
  53957. $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED);
  53958. }
  53959. $a = array();
  53960. return $a;
  53961. }
  53962. }
  53963. PEAR_Downloader_Package::removeInstalled($params);
  53964. if (!count($params)) {
  53965. $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  53966. $a = array();
  53967. return $a;
  53968. }
  53969. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  53970. $err = $this->analyzeDependencies($params);
  53971. PEAR::popErrorHandling();
  53972. if (!count($params)) {
  53973. $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  53974. $a = array();
  53975. return $a;
  53976. }
  53977. $ret = array();
  53978. $newparams = array();
  53979. if (isset($this->_options['pretend'])) {
  53980. return $params;
  53981. }
  53982. $somefailed = false;
  53983. foreach ($params as $i => $package) {
  53984. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  53985. $pf = &$params[$i]->download();
  53986. PEAR::staticPopErrorHandling();
  53987. if (PEAR::isError($pf)) {
  53988. if (!isset($this->_options['soft'])) {
  53989. $this->log(1, $pf->getMessage());
  53990. $this->log(0, 'Error: cannot download "' .
  53991. $this->_registry->parsedPackageNameToString($package->getParsedPackage(),
  53992. true) .
  53993. '"');
  53994. }
  53995. $somefailed = true;
  53996. continue;
  53997. }
  53998. $newparams[] = &$params[$i];
  53999. $ret[] = array(
  54000. 'file' => $pf->getArchiveFile(),
  54001. 'info' => &$pf,
  54002. 'pkg' => $pf->getPackage()
  54003. );
  54004. }
  54005. if ($somefailed) {
  54006. // remove params that did not download successfully
  54007. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  54008. $err = $this->analyzeDependencies($newparams, true);
  54009. PEAR::popErrorHandling();
  54010. if (!count($newparams)) {
  54011. $this->pushError('Download failed', PEAR_INSTALLER_FAILED);
  54012. $a = array();
  54013. return $a;
  54014. }
  54015. }
  54016. $this->_downloadedPackages = $ret;
  54017. return $newparams;
  54018. }
  54019. /**
  54020. * @param array all packages to be installed
  54021. */
  54022. function analyzeDependencies(&$params, $force = false)
  54023. {
  54024. if (isset($this->_options['downloadonly'])) {
  54025. return;
  54026. }
  54027. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  54028. $redo = true;
  54029. $reset = $hasfailed = $failed = false;
  54030. while ($redo) {
  54031. $redo = false;
  54032. foreach ($params as $i => $param) {
  54033. $deps = $param->getDeps();
  54034. if (!$deps) {
  54035. $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  54036. $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  54037. $send = $param->getPackageFile();
  54038. $installcheck = $depchecker->validatePackage($send, $this, $params);
  54039. if (PEAR::isError($installcheck)) {
  54040. if (!isset($this->_options['soft'])) {
  54041. $this->log(0, $installcheck->getMessage());
  54042. }
  54043. $hasfailed = true;
  54044. $params[$i] = false;
  54045. $reset = true;
  54046. $redo = true;
  54047. $failed = false;
  54048. PEAR_Downloader_Package::removeDuplicates($params);
  54049. continue 2;
  54050. }
  54051. continue;
  54052. }
  54053. if (!$reset && $param->alreadyValidated() && !$force) {
  54054. continue;
  54055. }
  54056. if (count($deps)) {
  54057. $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  54058. $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  54059. $send = $param->getPackageFile();
  54060. if ($send === null) {
  54061. $send = $param->getDownloadURL();
  54062. }
  54063. $installcheck = $depchecker->validatePackage($send, $this, $params);
  54064. if (PEAR::isError($installcheck)) {
  54065. if (!isset($this->_options['soft'])) {
  54066. $this->log(0, $installcheck->getMessage());
  54067. }
  54068. $hasfailed = true;
  54069. $params[$i] = false;
  54070. $reset = true;
  54071. $redo = true;
  54072. $failed = false;
  54073. PEAR_Downloader_Package::removeDuplicates($params);
  54074. continue 2;
  54075. }
  54076. $failed = false;
  54077. if (isset($deps['required']) && is_array($deps['required'])) {
  54078. foreach ($deps['required'] as $type => $dep) {
  54079. // note: Dependency2 will never return a PEAR_Error if ignore-errors
  54080. // is specified, so soft is needed to turn off logging
  54081. if (!isset($dep[0])) {
  54082. if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep,
  54083. true, $params))) {
  54084. $failed = true;
  54085. if (!isset($this->_options['soft'])) {
  54086. $this->log(0, $e->getMessage());
  54087. }
  54088. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54089. if (!isset($this->_options['soft'])) {
  54090. $this->log(0, $e[0]);
  54091. }
  54092. }
  54093. } else {
  54094. foreach ($dep as $d) {
  54095. if (PEAR::isError($e =
  54096. $depchecker->{"validate{$type}Dependency"}($d,
  54097. true, $params))) {
  54098. $failed = true;
  54099. if (!isset($this->_options['soft'])) {
  54100. $this->log(0, $e->getMessage());
  54101. }
  54102. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54103. if (!isset($this->_options['soft'])) {
  54104. $this->log(0, $e[0]);
  54105. }
  54106. }
  54107. }
  54108. }
  54109. }
  54110. if (isset($deps['optional']) && is_array($deps['optional'])) {
  54111. foreach ($deps['optional'] as $type => $dep) {
  54112. if (!isset($dep[0])) {
  54113. if (PEAR::isError($e =
  54114. $depchecker->{"validate{$type}Dependency"}($dep,
  54115. false, $params))) {
  54116. $failed = true;
  54117. if (!isset($this->_options['soft'])) {
  54118. $this->log(0, $e->getMessage());
  54119. }
  54120. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54121. if (!isset($this->_options['soft'])) {
  54122. $this->log(0, $e[0]);
  54123. }
  54124. }
  54125. } else {
  54126. foreach ($dep as $d) {
  54127. if (PEAR::isError($e =
  54128. $depchecker->{"validate{$type}Dependency"}($d,
  54129. false, $params))) {
  54130. $failed = true;
  54131. if (!isset($this->_options['soft'])) {
  54132. $this->log(0, $e->getMessage());
  54133. }
  54134. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54135. if (!isset($this->_options['soft'])) {
  54136. $this->log(0, $e[0]);
  54137. }
  54138. }
  54139. }
  54140. }
  54141. }
  54142. }
  54143. $groupname = $param->getGroup();
  54144. if (isset($deps['group']) && $groupname) {
  54145. if (!isset($deps['group'][0])) {
  54146. $deps['group'] = array($deps['group']);
  54147. }
  54148. $found = false;
  54149. foreach ($deps['group'] as $group) {
  54150. if ($group['attribs']['name'] == $groupname) {
  54151. $found = true;
  54152. break;
  54153. }
  54154. }
  54155. if ($found) {
  54156. unset($group['attribs']);
  54157. foreach ($group as $type => $dep) {
  54158. if (!isset($dep[0])) {
  54159. if (PEAR::isError($e =
  54160. $depchecker->{"validate{$type}Dependency"}($dep,
  54161. false, $params))) {
  54162. $failed = true;
  54163. if (!isset($this->_options['soft'])) {
  54164. $this->log(0, $e->getMessage());
  54165. }
  54166. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54167. if (!isset($this->_options['soft'])) {
  54168. $this->log(0, $e[0]);
  54169. }
  54170. }
  54171. } else {
  54172. foreach ($dep as $d) {
  54173. if (PEAR::isError($e =
  54174. $depchecker->{"validate{$type}Dependency"}($d,
  54175. false, $params))) {
  54176. $failed = true;
  54177. if (!isset($this->_options['soft'])) {
  54178. $this->log(0, $e->getMessage());
  54179. }
  54180. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54181. if (!isset($this->_options['soft'])) {
  54182. $this->log(0, $e[0]);
  54183. }
  54184. }
  54185. }
  54186. }
  54187. }
  54188. }
  54189. }
  54190. } else {
  54191. foreach ($deps as $dep) {
  54192. if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
  54193. $failed = true;
  54194. if (!isset($this->_options['soft'])) {
  54195. $this->log(0, $e->getMessage());
  54196. }
  54197. } elseif (is_array($e) && !$param->alreadyValidated()) {
  54198. if (!isset($this->_options['soft'])) {
  54199. $this->log(0, $e[0]);
  54200. }
  54201. }
  54202. }
  54203. }
  54204. $params[$i]->setValidated();
  54205. }
  54206. if ($failed) {
  54207. $hasfailed = true;
  54208. $params[$i] = false;
  54209. $reset = true;
  54210. $redo = true;
  54211. $failed = false;
  54212. PEAR_Downloader_Package::removeDuplicates($params);
  54213. continue 2;
  54214. }
  54215. }
  54216. }
  54217. PEAR::staticPopErrorHandling();
  54218. if ($hasfailed && (isset($this->_options['ignore-errors']) ||
  54219. isset($this->_options['nodeps']))) {
  54220. // this is probably not needed, but just in case
  54221. if (!isset($this->_options['soft'])) {
  54222. $this->log(0, 'WARNING: dependencies failed');
  54223. }
  54224. }
  54225. }
  54226. /**
  54227. * Retrieve the directory that downloads will happen in
  54228. * @access private
  54229. * @return string
  54230. */
  54231. function getDownloadDir()
  54232. {
  54233. if (isset($this->_downloadDir)) {
  54234. return $this->_downloadDir;
  54235. }
  54236. $downloaddir = $this->config->get('download_dir');
  54237. if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) {
  54238. if (is_dir($downloaddir) && !is_writable($downloaddir)) {
  54239. $this->log(0, 'WARNING: configuration download directory "' . $downloaddir .
  54240. '" is not writeable. Change download_dir config variable to ' .
  54241. 'a writeable dir to avoid this warning');
  54242. }
  54243. if (!class_exists('System')) {
  54244. require_once 'System.php';
  54245. }
  54246. if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
  54247. return $downloaddir;
  54248. }
  54249. $this->log(3, '+ tmp dir created at ' . $downloaddir);
  54250. }
  54251. if (!is_writable($downloaddir)) {
  54252. if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) ||
  54253. !is_writable($downloaddir)) {
  54254. return PEAR::raiseError('download directory "' . $downloaddir .
  54255. '" is not writeable. Change download_dir config variable to ' .
  54256. 'a writeable dir');
  54257. }
  54258. }
  54259. return $this->_downloadDir = $downloaddir;
  54260. }
  54261. function setDownloadDir($dir)
  54262. {
  54263. if (!@is_writable($dir)) {
  54264. if (PEAR::isError(System::mkdir(array('-p', $dir)))) {
  54265. return PEAR::raiseError('download directory "' . $dir .
  54266. '" is not writeable. Change download_dir config variable to ' .
  54267. 'a writeable dir');
  54268. }
  54269. }
  54270. $this->_downloadDir = $dir;
  54271. }
  54272. function configSet($key, $value, $layer = 'user', $channel = false)
  54273. {
  54274. $this->config->set($key, $value, $layer, $channel);
  54275. $this->_preferredState = $this->config->get('preferred_state', null, $channel);
  54276. if (!$this->_preferredState) {
  54277. // don't inadvertently use a non-set preferred_state
  54278. $this->_preferredState = null;
  54279. }
  54280. }
  54281. function setOptions($options)
  54282. {
  54283. $this->_options = $options;
  54284. }
  54285. function getOptions()
  54286. {
  54287. return $this->_options;
  54288. }
  54289. /**
  54290. * @param array output of {@link parsePackageName()}
  54291. * @access private
  54292. */
  54293. function _getPackageDownloadUrl($parr)
  54294. {
  54295. $curchannel = $this->config->get('default_channel');
  54296. $this->configSet('default_channel', $parr['channel']);
  54297. // getDownloadURL returns an array. On error, it only contains information
  54298. // on the latest release as array(version, info). On success it contains
  54299. // array(version, info, download url string)
  54300. $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  54301. if (!$this->_registry->channelExists($parr['channel'])) {
  54302. do {
  54303. if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) {
  54304. break;
  54305. }
  54306. $this->configSet('default_channel', $curchannel);
  54307. return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']);
  54308. } while (false);
  54309. }
  54310. $chan = $this->_registry->getChannel($parr['channel']);
  54311. if (PEAR::isError($chan)) {
  54312. return $chan;
  54313. }
  54314. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  54315. $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']);
  54316. $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']);
  54317. // package is installed - use the installed release stability level
  54318. if (!isset($parr['state']) && $stability !== null) {
  54319. $state = $stability['release'];
  54320. }
  54321. PEAR::staticPopErrorHandling();
  54322. $base2 = false;
  54323. $preferred_mirror = $this->config->get('preferred_mirror');
  54324. if (!$chan->supportsREST($preferred_mirror) ||
  54325. (
  54326. !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror))
  54327. &&
  54328. !($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
  54329. )
  54330. ) {
  54331. return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.');
  54332. }
  54333. if ($base2) {
  54334. $rest = &$this->config->getREST('1.3', $this->_options);
  54335. $base = $base2;
  54336. } else {
  54337. $rest = &$this->config->getREST('1.0', $this->_options);
  54338. }
  54339. $downloadVersion = false;
  54340. if (!isset($parr['version']) && !isset($parr['state']) && $version
  54341. && !PEAR::isError($version)
  54342. && !isset($this->_options['downloadonly'])
  54343. ) {
  54344. $downloadVersion = $version;
  54345. }
  54346. $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName());
  54347. if (PEAR::isError($url)) {
  54348. $this->configSet('default_channel', $curchannel);
  54349. return $url;
  54350. }
  54351. if ($parr['channel'] != $curchannel) {
  54352. $this->configSet('default_channel', $curchannel);
  54353. }
  54354. if (!is_array($url)) {
  54355. return $url;
  54356. }
  54357. $url['raw'] = false; // no checking is necessary for REST
  54358. if (!is_array($url['info'])) {
  54359. return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  54360. 'this should never happen');
  54361. }
  54362. if (!isset($this->_options['force']) &&
  54363. !isset($this->_options['downloadonly']) &&
  54364. $version &&
  54365. !PEAR::isError($version) &&
  54366. !isset($parr['group'])
  54367. ) {
  54368. if (version_compare($version, $url['version'], '=')) {
  54369. return PEAR::raiseError($this->_registry->parsedPackageNameToString(
  54370. $parr, true) . ' is already installed and is the same as the ' .
  54371. 'released version ' . $url['version'], -976);
  54372. }
  54373. if (version_compare($version, $url['version'], '>')) {
  54374. return PEAR::raiseError($this->_registry->parsedPackageNameToString(
  54375. $parr, true) . ' is already installed and is newer than detected ' .
  54376. 'released version ' . $url['version'], -976);
  54377. }
  54378. }
  54379. if (isset($url['info']['required']) || $url['compatible']) {
  54380. require_once 'PEAR/PackageFile/v2.php';
  54381. $pf = new PEAR_PackageFile_v2;
  54382. $pf->setRawChannel($parr['channel']);
  54383. if ($url['compatible']) {
  54384. $pf->setRawCompatible($url['compatible']);
  54385. }
  54386. } else {
  54387. require_once 'PEAR/PackageFile/v1.php';
  54388. $pf = new PEAR_PackageFile_v1;
  54389. }
  54390. $pf->setRawPackage($url['package']);
  54391. $pf->setDeps($url['info']);
  54392. if ($url['compatible']) {
  54393. $pf->setCompatible($url['compatible']);
  54394. }
  54395. $pf->setRawState($url['stability']);
  54396. $url['info'] = &$pf;
  54397. if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  54398. $ext = '.tar';
  54399. } else {
  54400. $ext = '.tgz';
  54401. }
  54402. if (is_array($url) && isset($url['url'])) {
  54403. $url['url'] .= $ext;
  54404. }
  54405. return $url;
  54406. }
  54407. /**
  54408. * @param array dependency array
  54409. * @access private
  54410. */
  54411. function _getDepPackageDownloadUrl($dep, $parr)
  54412. {
  54413. $xsdversion = isset($dep['rel']) ? '1.0' : '2.0';
  54414. $curchannel = $this->config->get('default_channel');
  54415. if (isset($dep['uri'])) {
  54416. $xsdversion = '2.0';
  54417. $chan = $this->_registry->getChannel('__uri');
  54418. if (PEAR::isError($chan)) {
  54419. return $chan;
  54420. }
  54421. $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri');
  54422. $this->configSet('default_channel', '__uri');
  54423. } else {
  54424. if (isset($dep['channel'])) {
  54425. $remotechannel = $dep['channel'];
  54426. } else {
  54427. $remotechannel = 'pear.php.net';
  54428. }
  54429. if (!$this->_registry->channelExists($remotechannel)) {
  54430. do {
  54431. if ($this->config->get('auto_discover')) {
  54432. if ($this->discover($remotechannel)) {
  54433. break;
  54434. }
  54435. }
  54436. return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
  54437. } while (false);
  54438. }
  54439. $chan = $this->_registry->getChannel($remotechannel);
  54440. if (PEAR::isError($chan)) {
  54441. return $chan;
  54442. }
  54443. $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel);
  54444. $this->configSet('default_channel', $remotechannel);
  54445. }
  54446. $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  54447. if (isset($parr['state']) && isset($parr['version'])) {
  54448. unset($parr['state']);
  54449. }
  54450. if (isset($dep['uri'])) {
  54451. $info = $this->newDownloaderPackage($this);
  54452. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  54453. $err = $info->initialize($dep);
  54454. PEAR::staticPopErrorHandling();
  54455. if (!$err) {
  54456. // skip parameters that were missed by preferred_state
  54457. return PEAR::raiseError('Cannot initialize dependency');
  54458. }
  54459. if (PEAR::isError($err)) {
  54460. if (!isset($this->_options['soft'])) {
  54461. $this->log(0, $err->getMessage());
  54462. }
  54463. if (is_object($info)) {
  54464. $param = $info->getChannel() . '/' . $info->getPackage();
  54465. }
  54466. return PEAR::raiseError('Package "' . $param . '" is not valid');
  54467. }
  54468. return $info;
  54469. } elseif ($chan->supportsREST($this->config->get('preferred_mirror'))
  54470. &&
  54471. (
  54472. ($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror')))
  54473. ||
  54474. ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')))
  54475. )
  54476. ) {
  54477. if ($base2) {
  54478. $base = $base2;
  54479. $rest = &$this->config->getREST('1.3', $this->_options);
  54480. } else {
  54481. $rest = &$this->config->getREST('1.0', $this->_options);
  54482. }
  54483. $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr,
  54484. $state, $version, $chan->getName());
  54485. if (PEAR::isError($url)) {
  54486. return $url;
  54487. }
  54488. if ($parr['channel'] != $curchannel) {
  54489. $this->configSet('default_channel', $curchannel);
  54490. }
  54491. if (!is_array($url)) {
  54492. return $url;
  54493. }
  54494. $url['raw'] = false; // no checking is necessary for REST
  54495. if (!is_array($url['info'])) {
  54496. return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  54497. 'this should never happen');
  54498. }
  54499. if (isset($url['info']['required'])) {
  54500. if (!class_exists('PEAR_PackageFile_v2')) {
  54501. require_once 'PEAR/PackageFile/v2.php';
  54502. }
  54503. $pf = new PEAR_PackageFile_v2;
  54504. $pf->setRawChannel($remotechannel);
  54505. } else {
  54506. if (!class_exists('PEAR_PackageFile_v1')) {
  54507. require_once 'PEAR/PackageFile/v1.php';
  54508. }
  54509. $pf = new PEAR_PackageFile_v1;
  54510. }
  54511. $pf->setRawPackage($url['package']);
  54512. $pf->setDeps($url['info']);
  54513. if ($url['compatible']) {
  54514. $pf->setCompatible($url['compatible']);
  54515. }
  54516. $pf->setRawState($url['stability']);
  54517. $url['info'] = &$pf;
  54518. if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  54519. $ext = '.tar';
  54520. } else {
  54521. $ext = '.tgz';
  54522. }
  54523. if (is_array($url) && isset($url['url'])) {
  54524. $url['url'] .= $ext;
  54525. }
  54526. return $url;
  54527. }
  54528. return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.');
  54529. }
  54530. /**
  54531. * @deprecated in favor of _getPackageDownloadUrl
  54532. */
  54533. function getPackageDownloadUrl($package, $version = null, $channel = false)
  54534. {
  54535. if ($version) {
  54536. $package .= "-$version";
  54537. }
  54538. if ($this === null || $this->_registry === null) {
  54539. $package = "http://pear.php.net/get/$package";
  54540. } else {
  54541. $chan = $this->_registry->getChannel($channel);
  54542. if (PEAR::isError($chan)) {
  54543. return '';
  54544. }
  54545. $package = "http://" . $chan->getServer() . "/get/$package";
  54546. }
  54547. if (!extension_loaded("zlib")) {
  54548. $package .= '?uncompress=yes';
  54549. }
  54550. return $package;
  54551. }
  54552. /**
  54553. * Retrieve a list of downloaded packages after a call to {@link download()}.
  54554. *
  54555. * Also resets the list of downloaded packages.
  54556. * @return array
  54557. */
  54558. function getDownloadedPackages()
  54559. {
  54560. $ret = $this->_downloadedPackages;
  54561. $this->_downloadedPackages = array();
  54562. $this->_toDownload = array();
  54563. return $ret;
  54564. }
  54565. function _downloadCallback($msg, $params = null)
  54566. {
  54567. switch ($msg) {
  54568. case 'saveas':
  54569. $this->log(1, "downloading $params ...");
  54570. break;
  54571. case 'done':
  54572. $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes');
  54573. break;
  54574. case 'bytesread':
  54575. static $bytes;
  54576. if (empty($bytes)) {
  54577. $bytes = 0;
  54578. }
  54579. if (!($bytes % 10240)) {
  54580. $this->log(1, '.', false);
  54581. }
  54582. $bytes += $params;
  54583. break;
  54584. case 'start':
  54585. if($params[1] == -1) {
  54586. $length = "Unknown size";
  54587. } else {
  54588. $length = number_format($params[1], 0, '', ',')." bytes";
  54589. }
  54590. $this->log(1, "Starting to download {$params[0]} ($length)");
  54591. break;
  54592. }
  54593. if (method_exists($this->ui, '_downloadCallback'))
  54594. $this->ui->_downloadCallback($msg, $params);
  54595. }
  54596. function _prependPath($path, $prepend)
  54597. {
  54598. if (strlen($prepend) > 0) {
  54599. if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  54600. if (preg_match('/^[a-z]:/i', $prepend)) {
  54601. $prepend = substr($prepend, 2);
  54602. } elseif ($prepend[0] != '\\') {
  54603. $prepend = "\\$prepend";
  54604. }
  54605. $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  54606. } else {
  54607. $path = $prepend . $path;
  54608. }
  54609. }
  54610. return $path;
  54611. }
  54612. /**
  54613. * @param string
  54614. * @param integer
  54615. */
  54616. function pushError($errmsg, $code = -1)
  54617. {
  54618. array_push($this->_errorStack, array($errmsg, $code));
  54619. }
  54620. function getErrorMsgs()
  54621. {
  54622. $msgs = array();
  54623. $errs = $this->_errorStack;
  54624. foreach ($errs as $err) {
  54625. $msgs[] = $err[0];
  54626. }
  54627. $this->_errorStack = array();
  54628. return $msgs;
  54629. }
  54630. /**
  54631. * for BC
  54632. *
  54633. * @deprecated
  54634. */
  54635. function sortPkgDeps(&$packages, $uninstall = false)
  54636. {
  54637. $uninstall ?
  54638. $this->sortPackagesForUninstall($packages) :
  54639. $this->sortPackagesForInstall($packages);
  54640. }
  54641. /**
  54642. * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  54643. *
  54644. * This uses the topological sort method from graph theory, and the
  54645. * Structures_Graph package to properly sort dependencies for installation.
  54646. * @param array an array of downloaded PEAR_Downloader_Packages
  54647. * @return array array of array(packagefilename, package.xml contents)
  54648. */
  54649. function sortPackagesForInstall(&$packages)
  54650. {
  54651. require_once 'Structures/Graph.php';
  54652. require_once 'Structures/Graph/Node.php';
  54653. require_once 'Structures/Graph/Manipulator/TopologicalSorter.php';
  54654. $depgraph = new Structures_Graph(true);
  54655. $nodes = array();
  54656. $reg = &$this->config->getRegistry();
  54657. foreach ($packages as $i => $package) {
  54658. $pname = $reg->parsedPackageNameToString(
  54659. array(
  54660. 'channel' => $package->getChannel(),
  54661. 'package' => strtolower($package->getPackage()),
  54662. ));
  54663. $nodes[$pname] = new Structures_Graph_Node;
  54664. $nodes[$pname]->setData($packages[$i]);
  54665. $depgraph->addNode($nodes[$pname]);
  54666. }
  54667. $deplinks = array();
  54668. foreach ($nodes as $package => $node) {
  54669. $pf = &$node->getData();
  54670. $pdeps = $pf->getDeps(true);
  54671. if (!$pdeps) {
  54672. continue;
  54673. }
  54674. if ($pf->getPackagexmlVersion() == '1.0') {
  54675. foreach ($pdeps as $dep) {
  54676. if ($dep['type'] != 'pkg' ||
  54677. (isset($dep['optional']) && $dep['optional'] == 'yes')) {
  54678. continue;
  54679. }
  54680. $dname = $reg->parsedPackageNameToString(
  54681. array(
  54682. 'channel' => 'pear.php.net',
  54683. 'package' => strtolower($dep['name']),
  54684. ));
  54685. if (isset($nodes[$dname])) {
  54686. if (!isset($deplinks[$dname])) {
  54687. $deplinks[$dname] = array();
  54688. }
  54689. $deplinks[$dname][$package] = 1;
  54690. // dependency is in installed packages
  54691. continue;
  54692. }
  54693. $dname = $reg->parsedPackageNameToString(
  54694. array(
  54695. 'channel' => 'pecl.php.net',
  54696. 'package' => strtolower($dep['name']),
  54697. ));
  54698. if (isset($nodes[$dname])) {
  54699. if (!isset($deplinks[$dname])) {
  54700. $deplinks[$dname] = array();
  54701. }
  54702. $deplinks[$dname][$package] = 1;
  54703. // dependency is in installed packages
  54704. continue;
  54705. }
  54706. }
  54707. } else {
  54708. // the only ordering we care about is:
  54709. // 1) subpackages must be installed before packages that depend on them
  54710. // 2) required deps must be installed before packages that depend on them
  54711. if (isset($pdeps['required']['subpackage'])) {
  54712. $t = $pdeps['required']['subpackage'];
  54713. if (!isset($t[0])) {
  54714. $t = array($t);
  54715. }
  54716. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  54717. }
  54718. if (isset($pdeps['group'])) {
  54719. if (!isset($pdeps['group'][0])) {
  54720. $pdeps['group'] = array($pdeps['group']);
  54721. }
  54722. foreach ($pdeps['group'] as $group) {
  54723. if (isset($group['subpackage'])) {
  54724. $t = $group['subpackage'];
  54725. if (!isset($t[0])) {
  54726. $t = array($t);
  54727. }
  54728. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  54729. }
  54730. }
  54731. }
  54732. if (isset($pdeps['optional']['subpackage'])) {
  54733. $t = $pdeps['optional']['subpackage'];
  54734. if (!isset($t[0])) {
  54735. $t = array($t);
  54736. }
  54737. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  54738. }
  54739. if (isset($pdeps['required']['package'])) {
  54740. $t = $pdeps['required']['package'];
  54741. if (!isset($t[0])) {
  54742. $t = array($t);
  54743. }
  54744. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  54745. }
  54746. if (isset($pdeps['group'])) {
  54747. if (!isset($pdeps['group'][0])) {
  54748. $pdeps['group'] = array($pdeps['group']);
  54749. }
  54750. foreach ($pdeps['group'] as $group) {
  54751. if (isset($group['package'])) {
  54752. $t = $group['package'];
  54753. if (!isset($t[0])) {
  54754. $t = array($t);
  54755. }
  54756. $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
  54757. }
  54758. }
  54759. }
  54760. }
  54761. }
  54762. $this->_detectDepCycle($deplinks);
  54763. foreach ($deplinks as $dependent => $parents) {
  54764. foreach ($parents as $parent => $unused) {
  54765. $nodes[$dependent]->connectTo($nodes[$parent]);
  54766. }
  54767. }
  54768. $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph);
  54769. $ret = array();
  54770. for ($i = 0, $count = count($installOrder); $i < $count; $i++) {
  54771. foreach ($installOrder[$i] as $index => $sortedpackage) {
  54772. $data = &$installOrder[$i][$index]->getData();
  54773. $ret[] = &$nodes[$reg->parsedPackageNameToString(
  54774. array(
  54775. 'channel' => $data->getChannel(),
  54776. 'package' => strtolower($data->getPackage()),
  54777. ))]->getData();
  54778. }
  54779. }
  54780. $packages = $ret;
  54781. return;
  54782. }
  54783. /**
  54784. * Detect recursive links between dependencies and break the cycles
  54785. *
  54786. * @param array
  54787. * @access private
  54788. */
  54789. function _detectDepCycle(&$deplinks)
  54790. {
  54791. do {
  54792. $keepgoing = false;
  54793. foreach ($deplinks as $dep => $parents) {
  54794. foreach ($parents as $parent => $unused) {
  54795. // reset the parent cycle detector
  54796. $this->_testCycle(null, null, null);
  54797. if ($this->_testCycle($dep, $deplinks, $parent)) {
  54798. $keepgoing = true;
  54799. unset($deplinks[$dep][$parent]);
  54800. if (count($deplinks[$dep]) == 0) {
  54801. unset($deplinks[$dep]);
  54802. }
  54803. continue 3;
  54804. }
  54805. }
  54806. }
  54807. } while ($keepgoing);
  54808. }
  54809. function _testCycle($test, $deplinks, $dep)
  54810. {
  54811. static $visited = array();
  54812. if ($test === null) {
  54813. $visited = array();
  54814. return;
  54815. }
  54816. // this happens when a parent has a dep cycle on another dependency
  54817. // but the child is not part of the cycle
  54818. if (isset($visited[$dep])) {
  54819. return false;
  54820. }
  54821. $visited[$dep] = 1;
  54822. if ($test == $dep) {
  54823. return true;
  54824. }
  54825. if (isset($deplinks[$dep])) {
  54826. if (in_array($test, array_keys($deplinks[$dep]), true)) {
  54827. return true;
  54828. }
  54829. foreach ($deplinks[$dep] as $parent => $unused) {
  54830. if ($this->_testCycle($test, $deplinks, $parent)) {
  54831. return true;
  54832. }
  54833. }
  54834. }
  54835. return false;
  54836. }
  54837. /**
  54838. * Set up the dependency for installation parsing
  54839. *
  54840. * @param array $t dependency information
  54841. * @param PEAR_Registry $reg
  54842. * @param array $deplinks list of dependency links already established
  54843. * @param array $nodes all existing package nodes
  54844. * @param string $package parent package name
  54845. * @access private
  54846. */
  54847. function _setupGraph($t, $reg, &$deplinks, &$nodes, $package)
  54848. {
  54849. foreach ($t as $dep) {
  54850. $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel'];
  54851. $dname = $reg->parsedPackageNameToString(
  54852. array(
  54853. 'channel' => $depchannel,
  54854. 'package' => strtolower($dep['name']),
  54855. ));
  54856. if (isset($nodes[$dname])) {
  54857. if (!isset($deplinks[$dname])) {
  54858. $deplinks[$dname] = array();
  54859. }
  54860. $deplinks[$dname][$package] = 1;
  54861. }
  54862. }
  54863. }
  54864. function _dependsOn($a, $b)
  54865. {
  54866. return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b);
  54867. }
  54868. function _checkDepTree($channel, $package, $b, $checked = array())
  54869. {
  54870. $checked[$channel][$package] = true;
  54871. if (!isset($this->_depTree[$channel][$package])) {
  54872. return false;
  54873. }
  54874. if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())]
  54875. [strtolower($b->getPackage())])) {
  54876. return true;
  54877. }
  54878. foreach ($this->_depTree[$channel][$package] as $ch => $packages) {
  54879. foreach ($packages as $pa => $true) {
  54880. if ($this->_checkDepTree($ch, $pa, $b, $checked)) {
  54881. return true;
  54882. }
  54883. }
  54884. }
  54885. return false;
  54886. }
  54887. function _sortInstall($a, $b)
  54888. {
  54889. if (!$a->getDeps() && !$b->getDeps()) {
  54890. return 0; // neither package has dependencies, order is insignificant
  54891. }
  54892. if ($a->getDeps() && !$b->getDeps()) {
  54893. return 1; // $a must be installed after $b because $a has dependencies
  54894. }
  54895. if (!$a->getDeps() && $b->getDeps()) {
  54896. return -1; // $b must be installed after $a because $b has dependencies
  54897. }
  54898. // both packages have dependencies
  54899. if ($this->_dependsOn($a, $b)) {
  54900. return 1;
  54901. }
  54902. if ($this->_dependsOn($b, $a)) {
  54903. return -1;
  54904. }
  54905. return 0;
  54906. }
  54907. /**
  54908. * Download a file through HTTP. Considers suggested file name in
  54909. * Content-disposition: header and can run a callback function for
  54910. * different events. The callback will be called with two
  54911. * parameters: the callback type, and parameters. The implemented
  54912. * callback types are:
  54913. *
  54914. * 'setup' called at the very beginning, parameter is a UI object
  54915. * that should be used for all output
  54916. * 'message' the parameter is a string with an informational message
  54917. * 'saveas' may be used to save with a different file name, the
  54918. * parameter is the filename that is about to be used.
  54919. * If a 'saveas' callback returns a non-empty string,
  54920. * that file name will be used as the filename instead.
  54921. * Note that $save_dir will not be affected by this, only
  54922. * the basename of the file.
  54923. * 'start' download is starting, parameter is number of bytes
  54924. * that are expected, or -1 if unknown
  54925. * 'bytesread' parameter is the number of bytes read so far
  54926. * 'done' download is complete, parameter is the total number
  54927. * of bytes read
  54928. * 'connfailed' if the TCP/SSL connection fails, this callback is called
  54929. * with array(host,port,errno,errmsg)
  54930. * 'writefailed' if writing to disk fails, this callback is called
  54931. * with array(destfile,errmsg)
  54932. *
  54933. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  54934. * setting), the proxy will be used.
  54935. *
  54936. * @param string $url the URL to download
  54937. * @param object $ui PEAR_Frontend_* instance
  54938. * @param object $config PEAR_Config instance
  54939. * @param string $save_dir directory to save file in
  54940. * @param mixed $callback function/method to call for status
  54941. * updates
  54942. * @param false|string|array $lastmodified header values to check against for caching
  54943. * use false to return the header values from this download
  54944. * @param false|array $accept Accept headers to send
  54945. * @param false|string $channel Channel to use for retrieving authentication
  54946. * @return mixed Returns the full path of the downloaded file or a PEAR
  54947. * error on failure. If the error is caused by
  54948. * socket-related errors, the error object will
  54949. * have the fsockopen error code available through
  54950. * getCode(). If caching is requested, then return the header
  54951. * values.
  54952. * If $lastmodified was given and the there are no changes,
  54953. * boolean false is returned.
  54954. *
  54955. * @access public
  54956. */
  54957. public static function _downloadHttp(
  54958. $object, $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
  54959. $accept = false, $channel = false
  54960. ) {
  54961. static $redirect = 0;
  54962. // always reset , so we are clean case of error
  54963. $wasredirect = $redirect;
  54964. $redirect = 0;
  54965. if ($callback) {
  54966. call_user_func($callback, 'setup', array(&$ui));
  54967. }
  54968. $info = parse_url($url);
  54969. if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
  54970. return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
  54971. }
  54972. if (!isset($info['host'])) {
  54973. return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
  54974. }
  54975. $host = isset($info['host']) ? $info['host'] : null;
  54976. $port = isset($info['port']) ? $info['port'] : null;
  54977. $path = isset($info['path']) ? $info['path'] : null;
  54978. if ($object !== null) {
  54979. $config = $object->config;
  54980. } else {
  54981. $config = &PEAR_Config::singleton();
  54982. }
  54983. $proxy = new PEAR_Proxy($config);
  54984. if ($proxy->isProxyConfigured() && $callback) {
  54985. call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
  54986. }
  54987. if (empty($port)) {
  54988. $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
  54989. }
  54990. $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
  54991. $secure = ($scheme == 'https');
  54992. $fp = $proxy->openSocket($host, $port, $secure);
  54993. if (PEAR::isError($fp)) {
  54994. if ($callback) {
  54995. $errno = $fp->getCode();
  54996. $errstr = $fp->getMessage();
  54997. call_user_func($callback, 'connfailed', array($host, $port,
  54998. $errno, $errstr));
  54999. }
  55000. return $fp;
  55001. }
  55002. $requestPath = $path;
  55003. if ($proxy->isProxyConfigured()) {
  55004. $requestPath = $url;
  55005. }
  55006. if ($lastmodified === false || $lastmodified) {
  55007. $request = "GET $requestPath HTTP/1.1\r\n";
  55008. } else {
  55009. $request = "GET $requestPath HTTP/1.0\r\n";
  55010. }
  55011. $request .= "Host: $host\r\n";
  55012. $ifmodifiedsince = '';
  55013. if (is_array($lastmodified)) {
  55014. if (isset($lastmodified['Last-Modified'])) {
  55015. $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
  55016. }
  55017. if (isset($lastmodified['ETag'])) {
  55018. $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
  55019. }
  55020. } else {
  55021. $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
  55022. }
  55023. $request .= $ifmodifiedsince .
  55024. "User-Agent: PEAR/1.10.10/PHP/" . PHP_VERSION . "\r\n";
  55025. if ($object !== null) { // only pass in authentication for non-static calls
  55026. $username = $config->get('username', null, $channel);
  55027. $password = $config->get('password', null, $channel);
  55028. if ($username && $password) {
  55029. $tmp = base64_encode("$username:$password");
  55030. $request .= "Authorization: Basic $tmp\r\n";
  55031. }
  55032. }
  55033. $proxyAuth = $proxy->getProxyAuth();
  55034. if ($proxyAuth) {
  55035. $request .= 'Proxy-Authorization: Basic ' .
  55036. $proxyAuth . "\r\n";
  55037. }
  55038. if ($accept) {
  55039. $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
  55040. }
  55041. $request .= "Connection: close\r\n";
  55042. $request .= "\r\n";
  55043. fwrite($fp, $request);
  55044. $headers = array();
  55045. $reply = 0;
  55046. while (trim($line = fgets($fp, 1024))) {
  55047. if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
  55048. $headers[strtolower($matches[1])] = trim($matches[2]);
  55049. } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  55050. $reply = (int)$matches[1];
  55051. if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
  55052. return false;
  55053. }
  55054. if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
  55055. return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)");
  55056. }
  55057. }
  55058. }
  55059. if ($reply != 200) {
  55060. if (!isset($headers['location'])) {
  55061. return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)");
  55062. }
  55063. if ($wasredirect > 4) {
  55064. return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)");
  55065. }
  55066. $redirect = $wasredirect + 1;
  55067. return static::_downloadHttp($object, $headers['location'],
  55068. $ui, $save_dir, $callback, $lastmodified, $accept);
  55069. }
  55070. if (isset($headers['content-disposition']) &&
  55071. preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) {
  55072. $save_as = basename($matches[1]);
  55073. } else {
  55074. $save_as = basename($url);
  55075. }
  55076. if ($callback) {
  55077. $tmp = call_user_func($callback, 'saveas', $save_as);
  55078. if ($tmp) {
  55079. $save_as = $tmp;
  55080. }
  55081. }
  55082. $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
  55083. if (is_link($dest_file)) {
  55084. return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $dest_file . ' as it is symlinked to ' . readlink($dest_file) . ' - Possible symlink attack');
  55085. }
  55086. if (!$wp = @fopen($dest_file, 'wb')) {
  55087. fclose($fp);
  55088. if ($callback) {
  55089. call_user_func($callback, 'writefailed',
  55090. array($dest_file, error_get_last()["message"]));
  55091. }
  55092. return PEAR::raiseError("could not open $dest_file for writing");
  55093. }
  55094. $length = isset($headers['content-length']) ? $headers['content-length'] : -1;
  55095. $bytes = 0;
  55096. if ($callback) {
  55097. call_user_func($callback, 'start', array(basename($dest_file), $length));
  55098. }
  55099. while ($data = fread($fp, 1024)) {
  55100. $bytes += strlen($data);
  55101. if ($callback) {
  55102. call_user_func($callback, 'bytesread', $bytes);
  55103. }
  55104. if (!@fwrite($wp, $data)) {
  55105. fclose($fp);
  55106. if ($callback) {
  55107. call_user_func($callback, 'writefailed',
  55108. array($dest_file, error_get_last()["message"]));
  55109. }
  55110. return PEAR::raiseError(
  55111. "$dest_file: write failed (" . error_get_last()["message"] . ")");
  55112. }
  55113. }
  55114. fclose($fp);
  55115. fclose($wp);
  55116. if ($callback) {
  55117. call_user_func($callback, 'done', $bytes);
  55118. }
  55119. if ($lastmodified === false || $lastmodified) {
  55120. if (isset($headers['etag'])) {
  55121. $lastmodified = array('ETag' => $headers['etag']);
  55122. }
  55123. if (isset($headers['last-modified'])) {
  55124. if (is_array($lastmodified)) {
  55125. $lastmodified['Last-Modified'] = $headers['last-modified'];
  55126. } else {
  55127. $lastmodified = $headers['last-modified'];
  55128. }
  55129. }
  55130. return array($dest_file, $lastmodified, $headers);
  55131. }
  55132. return $dest_file;
  55133. }
  55134. }
  55135. ����������������������������������������������������������������PEAR-1.10.10/PEAR/ErrorStack.php��������������������������������������������������������������������0000644�0001750�0001750�00000102014�13565304531�015573� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  55136. /**
  55137. * Error Stack Implementation
  55138. *
  55139. * This is an incredibly simple implementation of a very complex error handling
  55140. * facility. It contains the ability
  55141. * to track multiple errors from multiple packages simultaneously. In addition,
  55142. * it can track errors of many levels, save data along with the error, context
  55143. * information such as the exact file, line number, class and function that
  55144. * generated the error, and if necessary, it can raise a traditional PEAR_Error.
  55145. * It has built-in support for PEAR::Log, to log errors as they occur
  55146. *
  55147. * Since version 0.2alpha, it is also possible to selectively ignore errors,
  55148. * through the use of an error callback, see {@link pushCallback()}
  55149. *
  55150. * Since version 0.3alpha, it is possible to specify the exception class
  55151. * returned from {@link push()}
  55152. *
  55153. * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can
  55154. * still be done quite handily in an error callback or by manipulating the returned array
  55155. * @category Debugging
  55156. * @package PEAR_ErrorStack
  55157. * @author Greg Beaver <cellog@php.net>
  55158. * @copyright 2004-2008 Greg Beaver
  55159. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  55160. * @link http://pear.php.net/package/PEAR_ErrorStack
  55161. */
  55162. /**
  55163. * Singleton storage
  55164. *
  55165. * Format:
  55166. * <pre>
  55167. * array(
  55168. * 'package1' => PEAR_ErrorStack object,
  55169. * 'package2' => PEAR_ErrorStack object,
  55170. * ...
  55171. * )
  55172. * </pre>
  55173. * @access private
  55174. * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
  55175. */
  55176. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
  55177. /**
  55178. * Global error callback (default)
  55179. *
  55180. * This is only used if set to non-false. * is the default callback for
  55181. * all packages, whereas specific packages may set a default callback
  55182. * for all instances, regardless of whether they are a singleton or not.
  55183. *
  55184. * To exclude non-singletons, only set the local callback for the singleton
  55185. * @see PEAR_ErrorStack::setDefaultCallback()
  55186. * @access private
  55187. * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
  55188. */
  55189. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
  55190. '*' => false,
  55191. );
  55192. /**
  55193. * Global Log object (default)
  55194. *
  55195. * This is only used if set to non-false. Use to set a default log object for
  55196. * all stacks, regardless of instantiation order or location
  55197. * @see PEAR_ErrorStack::setDefaultLogger()
  55198. * @access private
  55199. * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  55200. */
  55201. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
  55202. /**
  55203. * Global Overriding Callback
  55204. *
  55205. * This callback will override any error callbacks that specific loggers have set.
  55206. * Use with EXTREME caution
  55207. * @see PEAR_ErrorStack::staticPushCallback()
  55208. * @access private
  55209. * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  55210. */
  55211. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  55212. /**#@+
  55213. * One of four possible return values from the error Callback
  55214. * @see PEAR_ErrorStack::_errorCallback()
  55215. */
  55216. /**
  55217. * If this is returned, then the error will be both pushed onto the stack
  55218. * and logged.
  55219. */
  55220. define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
  55221. /**
  55222. * If this is returned, then the error will only be pushed onto the stack,
  55223. * and not logged.
  55224. */
  55225. define('PEAR_ERRORSTACK_PUSH', 2);
  55226. /**
  55227. * If this is returned, then the error will only be logged, but not pushed
  55228. * onto the error stack.
  55229. */
  55230. define('PEAR_ERRORSTACK_LOG', 3);
  55231. /**
  55232. * If this is returned, then the error is completely ignored.
  55233. */
  55234. define('PEAR_ERRORSTACK_IGNORE', 4);
  55235. /**
  55236. * If this is returned, then the error is logged and die() is called.
  55237. */
  55238. define('PEAR_ERRORSTACK_DIE', 5);
  55239. /**#@-*/
  55240. /**
  55241. * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
  55242. * the singleton method.
  55243. */
  55244. define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
  55245. /**
  55246. * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
  55247. * that has no __toString() method
  55248. */
  55249. define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  55250. /**
  55251. * Error Stack Implementation
  55252. *
  55253. * Usage:
  55254. * <code>
  55255. * // global error stack
  55256. * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
  55257. * // local error stack
  55258. * $local_stack = new PEAR_ErrorStack('MyPackage');
  55259. * </code>
  55260. * @author Greg Beaver <cellog@php.net>
  55261. * @version 1.10.10
  55262. * @package PEAR_ErrorStack
  55263. * @category Debugging
  55264. * @copyright 2004-2008 Greg Beaver
  55265. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  55266. * @link http://pear.php.net/package/PEAR_ErrorStack
  55267. */
  55268. class PEAR_ErrorStack {
  55269. /**
  55270. * Errors are stored in the order that they are pushed on the stack.
  55271. * @since 0.4alpha Errors are no longer organized by error level.
  55272. * This renders pop() nearly unusable, and levels could be more easily
  55273. * handled in a callback anyway
  55274. * @var array
  55275. * @access private
  55276. */
  55277. var $_errors = array();
  55278. /**
  55279. * Storage of errors by level.
  55280. *
  55281. * Allows easy retrieval and deletion of only errors from a particular level
  55282. * @since PEAR 1.4.0dev
  55283. * @var array
  55284. * @access private
  55285. */
  55286. var $_errorsByLevel = array();
  55287. /**
  55288. * Package name this error stack represents
  55289. * @var string
  55290. * @access protected
  55291. */
  55292. var $_package;
  55293. /**
  55294. * Determines whether a PEAR_Error is thrown upon every error addition
  55295. * @var boolean
  55296. * @access private
  55297. */
  55298. var $_compat = false;
  55299. /**
  55300. * If set to a valid callback, this will be used to generate the error
  55301. * message from the error code, otherwise the message passed in will be
  55302. * used
  55303. * @var false|string|array
  55304. * @access private
  55305. */
  55306. var $_msgCallback = false;
  55307. /**
  55308. * If set to a valid callback, this will be used to generate the error
  55309. * context for an error. For PHP-related errors, this will be a file
  55310. * and line number as retrieved from debug_backtrace(), but can be
  55311. * customized for other purposes. The error might actually be in a separate
  55312. * configuration file, or in a database query.
  55313. * @var false|string|array
  55314. * @access protected
  55315. */
  55316. var $_contextCallback = false;
  55317. /**
  55318. * If set to a valid callback, this will be called every time an error
  55319. * is pushed onto the stack. The return value will be used to determine
  55320. * whether to allow an error to be pushed or logged.
  55321. *
  55322. * The return value must be one an PEAR_ERRORSTACK_* constant
  55323. * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  55324. * @var false|string|array
  55325. * @access protected
  55326. */
  55327. var $_errorCallback = array();
  55328. /**
  55329. * PEAR::Log object for logging errors
  55330. * @var false|Log
  55331. * @access protected
  55332. */
  55333. var $_logger = false;
  55334. /**
  55335. * Error messages - designed to be overridden
  55336. * @var array
  55337. * @abstract
  55338. */
  55339. var $_errorMsgs = array();
  55340. /**
  55341. * Set up a new error stack
  55342. *
  55343. * @param string $package name of the package this error stack represents
  55344. * @param callback $msgCallback callback used for error message generation
  55345. * @param callback $contextCallback callback used for context generation,
  55346. * defaults to {@link getFileLine()}
  55347. * @param boolean $throwPEAR_Error
  55348. */
  55349. function __construct($package, $msgCallback = false, $contextCallback = false,
  55350. $throwPEAR_Error = false)
  55351. {
  55352. $this->_package = $package;
  55353. $this->setMessageCallback($msgCallback);
  55354. $this->setContextCallback($contextCallback);
  55355. $this->_compat = $throwPEAR_Error;
  55356. }
  55357. /**
  55358. * Return a single error stack for this package.
  55359. *
  55360. * Note that all parameters are ignored if the stack for package $package
  55361. * has already been instantiated
  55362. * @param string $package name of the package this error stack represents
  55363. * @param callback $msgCallback callback used for error message generation
  55364. * @param callback $contextCallback callback used for context generation,
  55365. * defaults to {@link getFileLine()}
  55366. * @param boolean $throwPEAR_Error
  55367. * @param string $stackClass class to instantiate
  55368. *
  55369. * @return PEAR_ErrorStack
  55370. */
  55371. public static function &singleton(
  55372. $package, $msgCallback = false, $contextCallback = false,
  55373. $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack'
  55374. ) {
  55375. if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  55376. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  55377. }
  55378. if (!class_exists($stackClass)) {
  55379. if (function_exists('debug_backtrace')) {
  55380. $trace = debug_backtrace();
  55381. }
  55382. PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
  55383. 'exception', array('stackclass' => $stackClass),
  55384. 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
  55385. false, $trace);
  55386. }
  55387. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
  55388. new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
  55389. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  55390. }
  55391. /**
  55392. * Internal error handler for PEAR_ErrorStack class
  55393. *
  55394. * Dies if the error is an exception (and would have died anyway)
  55395. * @access private
  55396. */
  55397. function _handleError($err)
  55398. {
  55399. if ($err['level'] == 'exception') {
  55400. $message = $err['message'];
  55401. if (isset($_SERVER['REQUEST_URI'])) {
  55402. echo '<br />';
  55403. } else {
  55404. echo "\n";
  55405. }
  55406. var_dump($err['context']);
  55407. die($message);
  55408. }
  55409. }
  55410. /**
  55411. * Set up a PEAR::Log object for all error stacks that don't have one
  55412. * @param Log $log
  55413. */
  55414. public static function setDefaultLogger(&$log)
  55415. {
  55416. if (is_object($log) && method_exists($log, 'log') ) {
  55417. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  55418. } elseif (is_callable($log)) {
  55419. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  55420. }
  55421. }
  55422. /**
  55423. * Set up a PEAR::Log object for this error stack
  55424. * @param Log $log
  55425. */
  55426. function setLogger(&$log)
  55427. {
  55428. if (is_object($log) && method_exists($log, 'log') ) {
  55429. $this->_logger = &$log;
  55430. } elseif (is_callable($log)) {
  55431. $this->_logger = &$log;
  55432. }
  55433. }
  55434. /**
  55435. * Set an error code => error message mapping callback
  55436. *
  55437. * This method sets the callback that can be used to generate error
  55438. * messages for any instance
  55439. * @param array|string Callback function/method
  55440. */
  55441. function setMessageCallback($msgCallback)
  55442. {
  55443. if (!$msgCallback) {
  55444. $this->_msgCallback = array(&$this, 'getErrorMessage');
  55445. } else {
  55446. if (is_callable($msgCallback)) {
  55447. $this->_msgCallback = $msgCallback;
  55448. }
  55449. }
  55450. }
  55451. /**
  55452. * Get an error code => error message mapping callback
  55453. *
  55454. * This method returns the current callback that can be used to generate error
  55455. * messages
  55456. * @return array|string|false Callback function/method or false if none
  55457. */
  55458. function getMessageCallback()
  55459. {
  55460. return $this->_msgCallback;
  55461. }
  55462. /**
  55463. * Sets a default callback to be used by all error stacks
  55464. *
  55465. * This method sets the callback that can be used to generate error
  55466. * messages for a singleton
  55467. * @param array|string Callback function/method
  55468. * @param string Package name, or false for all packages
  55469. */
  55470. public static function setDefaultCallback($callback = false, $package = false)
  55471. {
  55472. if (!is_callable($callback)) {
  55473. $callback = false;
  55474. }
  55475. $package = $package ? $package : '*';
  55476. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
  55477. }
  55478. /**
  55479. * Set a callback that generates context information (location of error) for an error stack
  55480. *
  55481. * This method sets the callback that can be used to generate context
  55482. * information for an error. Passing in NULL will disable context generation
  55483. * and remove the expensive call to debug_backtrace()
  55484. * @param array|string|null Callback function/method
  55485. */
  55486. function setContextCallback($contextCallback)
  55487. {
  55488. if ($contextCallback === null) {
  55489. return $this->_contextCallback = false;
  55490. }
  55491. if (!$contextCallback) {
  55492. $this->_contextCallback = array(&$this, 'getFileLine');
  55493. } else {
  55494. if (is_callable($contextCallback)) {
  55495. $this->_contextCallback = $contextCallback;
  55496. }
  55497. }
  55498. }
  55499. /**
  55500. * Set an error Callback
  55501. * If set to a valid callback, this will be called every time an error
  55502. * is pushed onto the stack. The return value will be used to determine
  55503. * whether to allow an error to be pushed or logged.
  55504. *
  55505. * The return value must be one of the ERRORSTACK_* constants.
  55506. *
  55507. * This functionality can be used to emulate PEAR's pushErrorHandling, and
  55508. * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
  55509. * the error stack or logging
  55510. * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  55511. * @see popCallback()
  55512. * @param string|array $cb
  55513. */
  55514. function pushCallback($cb)
  55515. {
  55516. array_push($this->_errorCallback, $cb);
  55517. }
  55518. /**
  55519. * Remove a callback from the error callback stack
  55520. * @see pushCallback()
  55521. * @return array|string|false
  55522. */
  55523. function popCallback()
  55524. {
  55525. if (!count($this->_errorCallback)) {
  55526. return false;
  55527. }
  55528. return array_pop($this->_errorCallback);
  55529. }
  55530. /**
  55531. * Set a temporary overriding error callback for every package error stack
  55532. *
  55533. * Use this to temporarily disable all existing callbacks (can be used
  55534. * to emulate the @ operator, for instance)
  55535. * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  55536. * @see staticPopCallback(), pushCallback()
  55537. * @param string|array $cb
  55538. */
  55539. public static function staticPushCallback($cb)
  55540. {
  55541. array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
  55542. }
  55543. /**
  55544. * Remove a temporary overriding error callback
  55545. * @see staticPushCallback()
  55546. * @return array|string|false
  55547. */
  55548. public static function staticPopCallback()
  55549. {
  55550. $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
  55551. if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
  55552. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  55553. }
  55554. return $ret;
  55555. }
  55556. /**
  55557. * Add an error to the stack
  55558. *
  55559. * If the message generator exists, it is called with 2 parameters.
  55560. * - the current Error Stack object
  55561. * - an array that is in the same format as an error. Available indices
  55562. * are 'code', 'package', 'time', 'params', 'level', and 'context'
  55563. *
  55564. * Next, if the error should contain context information, this is
  55565. * handled by the context grabbing method.
  55566. * Finally, the error is pushed onto the proper error stack
  55567. * @param int $code Package-specific error code
  55568. * @param string $level Error level. This is NOT spell-checked
  55569. * @param array $params associative array of error parameters
  55570. * @param string $msg Error message, or a portion of it if the message
  55571. * is to be generated
  55572. * @param array $repackage If this error re-packages an error pushed by
  55573. * another package, place the array returned from
  55574. * {@link pop()} in this parameter
  55575. * @param array $backtrace Protected parameter: use this to pass in the
  55576. * {@link debug_backtrace()} that should be used
  55577. * to find error context
  55578. * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  55579. * thrown. If a PEAR_Error is returned, the userinfo
  55580. * property is set to the following array:
  55581. *
  55582. * <code>
  55583. * array(
  55584. * 'code' => $code,
  55585. * 'params' => $params,
  55586. * 'package' => $this->_package,
  55587. * 'level' => $level,
  55588. * 'time' => time(),
  55589. * 'context' => $context,
  55590. * 'message' => $msg,
  55591. * //['repackage' => $err] repackaged error array/Exception class
  55592. * );
  55593. * </code>
  55594. *
  55595. * Normally, the previous array is returned.
  55596. */
  55597. function push($code, $level = 'error', $params = array(), $msg = false,
  55598. $repackage = false, $backtrace = false)
  55599. {
  55600. $context = false;
  55601. // grab error context
  55602. if ($this->_contextCallback) {
  55603. if (!$backtrace) {
  55604. $backtrace = debug_backtrace();
  55605. }
  55606. $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
  55607. }
  55608. // save error
  55609. $time = explode(' ', microtime());
  55610. $time = $time[1] + $time[0];
  55611. $err = array(
  55612. 'code' => $code,
  55613. 'params' => $params,
  55614. 'package' => $this->_package,
  55615. 'level' => $level,
  55616. 'time' => $time,
  55617. 'context' => $context,
  55618. 'message' => $msg,
  55619. );
  55620. if ($repackage) {
  55621. $err['repackage'] = $repackage;
  55622. }
  55623. // set up the error message, if necessary
  55624. if ($this->_msgCallback) {
  55625. $msg = call_user_func_array($this->_msgCallback,
  55626. array(&$this, $err));
  55627. $err['message'] = $msg;
  55628. }
  55629. $push = $log = true;
  55630. $die = false;
  55631. // try the overriding callback first
  55632. $callback = $this->staticPopCallback();
  55633. if ($callback) {
  55634. $this->staticPushCallback($callback);
  55635. }
  55636. if (!is_callable($callback)) {
  55637. // try the local callback next
  55638. $callback = $this->popCallback();
  55639. if (is_callable($callback)) {
  55640. $this->pushCallback($callback);
  55641. } else {
  55642. // try the default callback
  55643. $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
  55644. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
  55645. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
  55646. }
  55647. }
  55648. if (is_callable($callback)) {
  55649. switch(call_user_func($callback, $err)){
  55650. case PEAR_ERRORSTACK_IGNORE:
  55651. return $err;
  55652. break;
  55653. case PEAR_ERRORSTACK_PUSH:
  55654. $log = false;
  55655. break;
  55656. case PEAR_ERRORSTACK_LOG:
  55657. $push = false;
  55658. break;
  55659. case PEAR_ERRORSTACK_DIE:
  55660. $die = true;
  55661. break;
  55662. // anything else returned has the same effect as pushandlog
  55663. }
  55664. }
  55665. if ($push) {
  55666. array_unshift($this->_errors, $err);
  55667. if (!isset($this->_errorsByLevel[$err['level']])) {
  55668. $this->_errorsByLevel[$err['level']] = array();
  55669. }
  55670. $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
  55671. }
  55672. if ($log) {
  55673. if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
  55674. $this->_log($err);
  55675. }
  55676. }
  55677. if ($die) {
  55678. die();
  55679. }
  55680. if ($this->_compat && $push) {
  55681. return $this->raiseError($msg, $code, null, null, $err);
  55682. }
  55683. return $err;
  55684. }
  55685. /**
  55686. * Static version of {@link push()}
  55687. *
  55688. * @param string $package Package name this error belongs to
  55689. * @param int $code Package-specific error code
  55690. * @param string $level Error level. This is NOT spell-checked
  55691. * @param array $params associative array of error parameters
  55692. * @param string $msg Error message, or a portion of it if the message
  55693. * is to be generated
  55694. * @param array $repackage If this error re-packages an error pushed by
  55695. * another package, place the array returned from
  55696. * {@link pop()} in this parameter
  55697. * @param array $backtrace Protected parameter: use this to pass in the
  55698. * {@link debug_backtrace()} that should be used
  55699. * to find error context
  55700. * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  55701. * thrown. see docs for {@link push()}
  55702. */
  55703. public static function staticPush(
  55704. $package, $code, $level = 'error', $params = array(),
  55705. $msg = false, $repackage = false, $backtrace = false
  55706. ) {
  55707. $s = &PEAR_ErrorStack::singleton($package);
  55708. if ($s->_contextCallback) {
  55709. if (!$backtrace) {
  55710. if (function_exists('debug_backtrace')) {
  55711. $backtrace = debug_backtrace();
  55712. }
  55713. }
  55714. }
  55715. return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
  55716. }
  55717. /**
  55718. * Log an error using PEAR::Log
  55719. * @param array $err Error array
  55720. * @param array $levels Error level => Log constant map
  55721. * @access protected
  55722. */
  55723. function _log($err)
  55724. {
  55725. if ($this->_logger) {
  55726. $logger = &$this->_logger;
  55727. } else {
  55728. $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
  55729. }
  55730. if (is_a($logger, 'Log')) {
  55731. $levels = array(
  55732. 'exception' => PEAR_LOG_CRIT,
  55733. 'alert' => PEAR_LOG_ALERT,
  55734. 'critical' => PEAR_LOG_CRIT,
  55735. 'error' => PEAR_LOG_ERR,
  55736. 'warning' => PEAR_LOG_WARNING,
  55737. 'notice' => PEAR_LOG_NOTICE,
  55738. 'info' => PEAR_LOG_INFO,
  55739. 'debug' => PEAR_LOG_DEBUG);
  55740. if (isset($levels[$err['level']])) {
  55741. $level = $levels[$err['level']];
  55742. } else {
  55743. $level = PEAR_LOG_INFO;
  55744. }
  55745. $logger->log($err['message'], $level, $err);
  55746. } else { // support non-standard logs
  55747. call_user_func($logger, $err);
  55748. }
  55749. }
  55750. /**
  55751. * Pop an error off of the error stack
  55752. *
  55753. * @return false|array
  55754. * @since 0.4alpha it is no longer possible to specify a specific error
  55755. * level to return - the last error pushed will be returned, instead
  55756. */
  55757. function pop()
  55758. {
  55759. $err = @array_shift($this->_errors);
  55760. if (!is_null($err)) {
  55761. @array_pop($this->_errorsByLevel[$err['level']]);
  55762. if (!count($this->_errorsByLevel[$err['level']])) {
  55763. unset($this->_errorsByLevel[$err['level']]);
  55764. }
  55765. }
  55766. return $err;
  55767. }
  55768. /**
  55769. * Pop an error off of the error stack, static method
  55770. *
  55771. * @param string package name
  55772. * @return boolean
  55773. * @since PEAR1.5.0a1
  55774. */
  55775. static function staticPop($package)
  55776. {
  55777. if ($package) {
  55778. if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  55779. return false;
  55780. }
  55781. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
  55782. }
  55783. }
  55784. /**
  55785. * Determine whether there are any errors on the stack
  55786. * @param string|array Level name. Use to determine if any errors
  55787. * of level (string), or levels (array) have been pushed
  55788. * @return boolean
  55789. */
  55790. function hasErrors($level = false)
  55791. {
  55792. if ($level) {
  55793. return isset($this->_errorsByLevel[$level]);
  55794. }
  55795. return count($this->_errors);
  55796. }
  55797. /**
  55798. * Retrieve all errors since last purge
  55799. *
  55800. * @param boolean set in order to empty the error stack
  55801. * @param string level name, to return only errors of a particular severity
  55802. * @return array
  55803. */
  55804. function getErrors($purge = false, $level = false)
  55805. {
  55806. if (!$purge) {
  55807. if ($level) {
  55808. if (!isset($this->_errorsByLevel[$level])) {
  55809. return array();
  55810. } else {
  55811. return $this->_errorsByLevel[$level];
  55812. }
  55813. } else {
  55814. return $this->_errors;
  55815. }
  55816. }
  55817. if ($level) {
  55818. $ret = $this->_errorsByLevel[$level];
  55819. foreach ($this->_errorsByLevel[$level] as $i => $unused) {
  55820. // entries are references to the $_errors array
  55821. $this->_errorsByLevel[$level][$i] = false;
  55822. }
  55823. // array_filter removes all entries === false
  55824. $this->_errors = array_filter($this->_errors);
  55825. unset($this->_errorsByLevel[$level]);
  55826. return $ret;
  55827. }
  55828. $ret = $this->_errors;
  55829. $this->_errors = array();
  55830. $this->_errorsByLevel = array();
  55831. return $ret;
  55832. }
  55833. /**
  55834. * Determine whether there are any errors on a single error stack, or on any error stack
  55835. *
  55836. * The optional parameter can be used to test the existence of any errors without the need of
  55837. * singleton instantiation
  55838. * @param string|false Package name to check for errors
  55839. * @param string Level name to check for a particular severity
  55840. * @return boolean
  55841. */
  55842. public static function staticHasErrors($package = false, $level = false)
  55843. {
  55844. if ($package) {
  55845. if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  55846. return false;
  55847. }
  55848. return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
  55849. }
  55850. foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  55851. if ($obj->hasErrors($level)) {
  55852. return true;
  55853. }
  55854. }
  55855. return false;
  55856. }
  55857. /**
  55858. * Get a list of all errors since last purge, organized by package
  55859. * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
  55860. * @param boolean $purge Set to purge the error stack of existing errors
  55861. * @param string $level Set to a level name in order to retrieve only errors of a particular level
  55862. * @param boolean $merge Set to return a flat array, not organized by package
  55863. * @param array $sortfunc Function used to sort a merged array - default
  55864. * sorts by time, and should be good for most cases
  55865. *
  55866. * @return array
  55867. */
  55868. public static function staticGetErrors(
  55869. $purge = false, $level = false, $merge = false,
  55870. $sortfunc = array('PEAR_ErrorStack', '_sortErrors')
  55871. ) {
  55872. $ret = array();
  55873. if (!is_callable($sortfunc)) {
  55874. $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
  55875. }
  55876. foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  55877. $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
  55878. if ($test) {
  55879. if ($merge) {
  55880. $ret = array_merge($ret, $test);
  55881. } else {
  55882. $ret[$package] = $test;
  55883. }
  55884. }
  55885. }
  55886. if ($merge) {
  55887. usort($ret, $sortfunc);
  55888. }
  55889. return $ret;
  55890. }
  55891. /**
  55892. * Error sorting function, sorts by time
  55893. * @access private
  55894. */
  55895. public static function _sortErrors($a, $b)
  55896. {
  55897. if ($a['time'] == $b['time']) {
  55898. return 0;
  55899. }
  55900. if ($a['time'] < $b['time']) {
  55901. return 1;
  55902. }
  55903. return -1;
  55904. }
  55905. /**
  55906. * Standard file/line number/function/class context callback
  55907. *
  55908. * This function uses a backtrace generated from {@link debug_backtrace()}
  55909. * and so will not work at all in PHP < 4.3.0. The frame should
  55910. * reference the frame that contains the source of the error.
  55911. * @return array|false either array('file' => file, 'line' => line,
  55912. * 'function' => function name, 'class' => class name) or
  55913. * if this doesn't work, then false
  55914. * @param unused
  55915. * @param integer backtrace frame.
  55916. * @param array Results of debug_backtrace()
  55917. */
  55918. public static function getFileLine($code, $params, $backtrace = null)
  55919. {
  55920. if ($backtrace === null) {
  55921. return false;
  55922. }
  55923. $frame = 0;
  55924. $functionframe = 1;
  55925. if (!isset($backtrace[1])) {
  55926. $functionframe = 0;
  55927. } else {
  55928. while (isset($backtrace[$functionframe]['function']) &&
  55929. $backtrace[$functionframe]['function'] == 'eval' &&
  55930. isset($backtrace[$functionframe + 1])) {
  55931. $functionframe++;
  55932. }
  55933. }
  55934. if (isset($backtrace[$frame])) {
  55935. if (!isset($backtrace[$frame]['file'])) {
  55936. $frame++;
  55937. }
  55938. $funcbacktrace = $backtrace[$functionframe];
  55939. $filebacktrace = $backtrace[$frame];
  55940. $ret = array('file' => $filebacktrace['file'],
  55941. 'line' => $filebacktrace['line']);
  55942. // rearrange for eval'd code or create function errors
  55943. if (strpos($filebacktrace['file'], '(') &&
  55944. preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
  55945. $matches)) {
  55946. $ret['file'] = $matches[1];
  55947. $ret['line'] = $matches[2] + 0;
  55948. }
  55949. if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
  55950. if ($funcbacktrace['function'] != 'eval') {
  55951. if ($funcbacktrace['function'] == '__lambda_func') {
  55952. $ret['function'] = 'create_function() code';
  55953. } else {
  55954. $ret['function'] = $funcbacktrace['function'];
  55955. }
  55956. }
  55957. }
  55958. if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
  55959. $ret['class'] = $funcbacktrace['class'];
  55960. }
  55961. return $ret;
  55962. }
  55963. return false;
  55964. }
  55965. /**
  55966. * Standard error message generation callback
  55967. *
  55968. * This method may also be called by a custom error message generator
  55969. * to fill in template values from the params array, simply
  55970. * set the third parameter to the error message template string to use
  55971. *
  55972. * The special variable %__msg% is reserved: use it only to specify
  55973. * where a message passed in by the user should be placed in the template,
  55974. * like so:
  55975. *
  55976. * Error message: %msg% - internal error
  55977. *
  55978. * If the message passed like so:
  55979. *
  55980. * <code>
  55981. * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
  55982. * </code>
  55983. *
  55984. * The returned error message will be "Error message: server error 500 -
  55985. * internal error"
  55986. * @param PEAR_ErrorStack
  55987. * @param array
  55988. * @param string|false Pre-generated error message template
  55989. *
  55990. * @return string
  55991. */
  55992. public static function getErrorMessage(&$stack, $err, $template = false)
  55993. {
  55994. if ($template) {
  55995. $mainmsg = $template;
  55996. } else {
  55997. $mainmsg = $stack->getErrorMessageTemplate($err['code']);
  55998. }
  55999. $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
  56000. if (is_array($err['params']) && count($err['params'])) {
  56001. foreach ($err['params'] as $name => $val) {
  56002. if (is_array($val)) {
  56003. // @ is needed in case $val is a multi-dimensional array
  56004. $val = @implode(', ', $val);
  56005. }
  56006. if (is_object($val)) {
  56007. if (method_exists($val, '__toString')) {
  56008. $val = $val->__toString();
  56009. } else {
  56010. PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
  56011. 'warning', array('obj' => get_class($val)),
  56012. 'object %obj% passed into getErrorMessage, but has no __toString() method');
  56013. $val = 'Object';
  56014. }
  56015. }
  56016. $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
  56017. }
  56018. }
  56019. return $mainmsg;
  56020. }
  56021. /**
  56022. * Standard Error Message Template generator from code
  56023. * @return string
  56024. */
  56025. function getErrorMessageTemplate($code)
  56026. {
  56027. if (!isset($this->_errorMsgs[$code])) {
  56028. return '%__msg%';
  56029. }
  56030. return $this->_errorMsgs[$code];
  56031. }
  56032. /**
  56033. * Set the Error Message Template array
  56034. *
  56035. * The array format must be:
  56036. * <pre>
  56037. * array(error code => 'message template',...)
  56038. * </pre>
  56039. *
  56040. * Error message parameters passed into {@link push()} will be used as input
  56041. * for the error message. If the template is 'message %foo% was %bar%', and the
  56042. * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
  56043. * be 'message one was six'
  56044. * @return string
  56045. */
  56046. function setErrorMessageTemplate($template)
  56047. {
  56048. $this->_errorMsgs = $template;
  56049. }
  56050. /**
  56051. * emulate PEAR::raiseError()
  56052. *
  56053. * @return PEAR_Error
  56054. */
  56055. function raiseError()
  56056. {
  56057. require_once 'PEAR.php';
  56058. $args = func_get_args();
  56059. return call_user_func_array(array('PEAR', 'raiseError'), $args);
  56060. }
  56061. }
  56062. $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
  56063. $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
  56064. ?>
  56065. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Exception.php���������������������������������������������������������������������0000644�0001750�0001750�00000033155�13565304531�015463� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  56066. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  56067. /**
  56068. * PEAR_Exception
  56069. *
  56070. * PHP versions 4 and 5
  56071. *
  56072. * @category pear
  56073. * @package PEAR
  56074. * @author Tomas V. V. Cox <cox@idecnet.com>
  56075. * @author Hans Lellelid <hans@velum.net>
  56076. * @author Bertrand Mansion <bmansion@mamasam.com>
  56077. * @author Greg Beaver <cellog@php.net>
  56078. * @copyright 1997-2009 The Authors
  56079. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  56080. * @link http://pear.php.net/package/PEAR
  56081. * @since File available since Release 1.3.3
  56082. */
  56083. /**
  56084. * Base PEAR_Exception Class
  56085. *
  56086. * 1) Features:
  56087. *
  56088. * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception))
  56089. * - Definable triggers, shot when exceptions occur
  56090. * - Pretty and informative error messages
  56091. * - Added more context info available (like class, method or cause)
  56092. * - cause can be a PEAR_Exception or an array of mixed
  56093. * PEAR_Exceptions/PEAR_ErrorStack warnings
  56094. * - callbacks for specific exception classes and their children
  56095. *
  56096. * 2) Ideas:
  56097. *
  56098. * - Maybe a way to define a 'template' for the output
  56099. *
  56100. * 3) Inherited properties from PHP Exception Class:
  56101. *
  56102. * protected $message
  56103. * protected $code
  56104. * protected $line
  56105. * protected $file
  56106. * private $trace
  56107. *
  56108. * 4) Inherited methods from PHP Exception Class:
  56109. *
  56110. * __clone
  56111. * __construct
  56112. * getMessage
  56113. * getCode
  56114. * getFile
  56115. * getLine
  56116. * getTraceSafe
  56117. * getTraceSafeAsString
  56118. * __toString
  56119. *
  56120. * 5) Usage example
  56121. *
  56122. * <code>
  56123. * require_once 'PEAR/Exception.php';
  56124. *
  56125. * class Test {
  56126. * function foo() {
  56127. * throw new PEAR_Exception('Error Message', ERROR_CODE);
  56128. * }
  56129. * }
  56130. *
  56131. * function myLogger($pear_exception) {
  56132. * echo $pear_exception->getMessage();
  56133. * }
  56134. * // each time a exception is thrown the 'myLogger' will be called
  56135. * // (its use is completely optional)
  56136. * PEAR_Exception::addObserver('myLogger');
  56137. * $test = new Test;
  56138. * try {
  56139. * $test->foo();
  56140. * } catch (PEAR_Exception $e) {
  56141. * print $e;
  56142. * }
  56143. * </code>
  56144. *
  56145. * @category pear
  56146. * @package PEAR
  56147. * @author Tomas V.V.Cox <cox@idecnet.com>
  56148. * @author Hans Lellelid <hans@velum.net>
  56149. * @author Bertrand Mansion <bmansion@mamasam.com>
  56150. * @author Greg Beaver <cellog@php.net>
  56151. * @copyright 1997-2009 The Authors
  56152. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  56153. * @version Release: 1.10.10
  56154. * @link http://pear.php.net/package/PEAR
  56155. * @since Class available since Release 1.3.3
  56156. *
  56157. */
  56158. class PEAR_Exception extends Exception
  56159. {
  56160. const OBSERVER_PRINT = -2;
  56161. const OBSERVER_TRIGGER = -4;
  56162. const OBSERVER_DIE = -8;
  56163. protected $cause;
  56164. private static $_observers = array();
  56165. private static $_uniqueid = 0;
  56166. private $_trace;
  56167. /**
  56168. * Supported signatures:
  56169. * - PEAR_Exception(string $message);
  56170. * - PEAR_Exception(string $message, int $code);
  56171. * - PEAR_Exception(string $message, Exception $cause);
  56172. * - PEAR_Exception(string $message, Exception $cause, int $code);
  56173. * - PEAR_Exception(string $message, PEAR_Error $cause);
  56174. * - PEAR_Exception(string $message, PEAR_Error $cause, int $code);
  56175. * - PEAR_Exception(string $message, array $causes);
  56176. * - PEAR_Exception(string $message, array $causes, int $code);
  56177. * @param string exception message
  56178. * @param int|Exception|PEAR_Error|array|null exception cause
  56179. * @param int|null exception code or null
  56180. */
  56181. public function __construct($message, $p2 = null, $p3 = null)
  56182. {
  56183. if (is_int($p2)) {
  56184. $code = $p2;
  56185. $this->cause = null;
  56186. } elseif (is_object($p2) || is_array($p2)) {
  56187. // using is_object allows both Exception and PEAR_Error
  56188. if (is_object($p2) && !($p2 instanceof Exception)) {
  56189. if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) {
  56190. throw new PEAR_Exception('exception cause must be Exception, ' .
  56191. 'array, or PEAR_Error');
  56192. }
  56193. }
  56194. $code = $p3;
  56195. if (is_array($p2) && isset($p2['message'])) {
  56196. // fix potential problem of passing in a single warning
  56197. $p2 = array($p2);
  56198. }
  56199. $this->cause = $p2;
  56200. } else {
  56201. $code = null;
  56202. $this->cause = null;
  56203. }
  56204. parent::__construct($message, $code);
  56205. $this->signal();
  56206. }
  56207. /**
  56208. * @param mixed $callback - A valid php callback, see php func is_callable()
  56209. * - A PEAR_Exception::OBSERVER_* constant
  56210. * - An array(const PEAR_Exception::OBSERVER_*,
  56211. * mixed $options)
  56212. * @param string $label The name of the observer. Use this if you want
  56213. * to remove it later with removeObserver()
  56214. */
  56215. public static function addObserver($callback, $label = 'default')
  56216. {
  56217. self::$_observers[$label] = $callback;
  56218. }
  56219. public static function removeObserver($label = 'default')
  56220. {
  56221. unset(self::$_observers[$label]);
  56222. }
  56223. /**
  56224. * @return int unique identifier for an observer
  56225. */
  56226. public static function getUniqueId()
  56227. {
  56228. return self::$_uniqueid++;
  56229. }
  56230. private function signal()
  56231. {
  56232. foreach (self::$_observers as $func) {
  56233. if (is_callable($func)) {
  56234. call_user_func($func, $this);
  56235. continue;
  56236. }
  56237. settype($func, 'array');
  56238. switch ($func[0]) {
  56239. case self::OBSERVER_PRINT :
  56240. $f = (isset($func[1])) ? $func[1] : '%s';
  56241. printf($f, $this->getMessage());
  56242. break;
  56243. case self::OBSERVER_TRIGGER :
  56244. $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
  56245. trigger_error($this->getMessage(), $f);
  56246. break;
  56247. case self::OBSERVER_DIE :
  56248. $f = (isset($func[1])) ? $func[1] : '%s';
  56249. die(printf($f, $this->getMessage()));
  56250. break;
  56251. default:
  56252. trigger_error('invalid observer type', E_USER_WARNING);
  56253. }
  56254. }
  56255. }
  56256. /**
  56257. * Return specific error information that can be used for more detailed
  56258. * error messages or translation.
  56259. *
  56260. * This method may be overridden in child exception classes in order
  56261. * to add functionality not present in PEAR_Exception and is a placeholder
  56262. * to define API
  56263. *
  56264. * The returned array must be an associative array of parameter => value like so:
  56265. * <pre>
  56266. * array('name' => $name, 'context' => array(...))
  56267. * </pre>
  56268. * @return array
  56269. */
  56270. public function getErrorData()
  56271. {
  56272. return array();
  56273. }
  56274. /**
  56275. * Returns the exception that caused this exception to be thrown
  56276. * @access public
  56277. * @return Exception|array The context of the exception
  56278. */
  56279. public function getCause()
  56280. {
  56281. return $this->cause;
  56282. }
  56283. /**
  56284. * Function must be public to call on caused exceptions
  56285. * @param array
  56286. */
  56287. public function getCauseMessage(&$causes)
  56288. {
  56289. $trace = $this->getTraceSafe();
  56290. $cause = array('class' => get_class($this),
  56291. 'message' => $this->message,
  56292. 'file' => 'unknown',
  56293. 'line' => 'unknown');
  56294. if (isset($trace[0])) {
  56295. if (isset($trace[0]['file'])) {
  56296. $cause['file'] = $trace[0]['file'];
  56297. $cause['line'] = $trace[0]['line'];
  56298. }
  56299. }
  56300. $causes[] = $cause;
  56301. if ($this->cause instanceof PEAR_Exception) {
  56302. $this->cause->getCauseMessage($causes);
  56303. } elseif ($this->cause instanceof Exception) {
  56304. $causes[] = array('class' => get_class($this->cause),
  56305. 'message' => $this->cause->getMessage(),
  56306. 'file' => $this->cause->getFile(),
  56307. 'line' => $this->cause->getLine());
  56308. } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) {
  56309. $causes[] = array('class' => get_class($this->cause),
  56310. 'message' => $this->cause->getMessage(),
  56311. 'file' => 'unknown',
  56312. 'line' => 'unknown');
  56313. } elseif (is_array($this->cause)) {
  56314. foreach ($this->cause as $cause) {
  56315. if ($cause instanceof PEAR_Exception) {
  56316. $cause->getCauseMessage($causes);
  56317. } elseif ($cause instanceof Exception) {
  56318. $causes[] = array('class' => get_class($cause),
  56319. 'message' => $cause->getMessage(),
  56320. 'file' => $cause->getFile(),
  56321. 'line' => $cause->getLine());
  56322. } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) {
  56323. $causes[] = array('class' => get_class($cause),
  56324. 'message' => $cause->getMessage(),
  56325. 'file' => 'unknown',
  56326. 'line' => 'unknown');
  56327. } elseif (is_array($cause) && isset($cause['message'])) {
  56328. // PEAR_ErrorStack warning
  56329. $causes[] = array(
  56330. 'class' => $cause['package'],
  56331. 'message' => $cause['message'],
  56332. 'file' => isset($cause['context']['file']) ?
  56333. $cause['context']['file'] :
  56334. 'unknown',
  56335. 'line' => isset($cause['context']['line']) ?
  56336. $cause['context']['line'] :
  56337. 'unknown',
  56338. );
  56339. }
  56340. }
  56341. }
  56342. }
  56343. public function getTraceSafe()
  56344. {
  56345. if (!isset($this->_trace)) {
  56346. $this->_trace = $this->getTrace();
  56347. if (empty($this->_trace)) {
  56348. $backtrace = debug_backtrace();
  56349. $this->_trace = array($backtrace[count($backtrace)-1]);
  56350. }
  56351. }
  56352. return $this->_trace;
  56353. }
  56354. public function getErrorClass()
  56355. {
  56356. $trace = $this->getTraceSafe();
  56357. return $trace[0]['class'];
  56358. }
  56359. public function getErrorMethod()
  56360. {
  56361. $trace = $this->getTraceSafe();
  56362. return $trace[0]['function'];
  56363. }
  56364. public function __toString()
  56365. {
  56366. if (isset($_SERVER['REQUEST_URI'])) {
  56367. return $this->toHtml();
  56368. }
  56369. return $this->toText();
  56370. }
  56371. public function toHtml()
  56372. {
  56373. $trace = $this->getTraceSafe();
  56374. $causes = array();
  56375. $this->getCauseMessage($causes);
  56376. $html = '<table style="border: 1px" cellspacing="0">' . "\n";
  56377. foreach ($causes as $i => $cause) {
  56378. $html .= '<tr><td colspan="3" style="background: #ff9999">'
  56379. . str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
  56380. . htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
  56381. . 'on line <b>' . $cause['line'] . '</b>'
  56382. . "</td></tr>\n";
  56383. }
  56384. $html .= '<tr><td colspan="3" style="background-color: #aaaaaa; text-align: center; font-weight: bold;">Exception trace</td></tr>' . "\n"
  56385. . '<tr><td style="text-align: center; background: #cccccc; width:20px; font-weight: bold;">#</td>'
  56386. . '<td style="text-align: center; background: #cccccc; font-weight: bold;">Function</td>'
  56387. . '<td style="text-align: center; background: #cccccc; font-weight: bold;">Location</td></tr>' . "\n";
  56388. foreach ($trace as $k => $v) {
  56389. $html .= '<tr><td style="text-align: center;">' . $k . '</td>'
  56390. . '<td>';
  56391. if (!empty($v['class'])) {
  56392. $html .= $v['class'] . $v['type'];
  56393. }
  56394. $html .= $v['function'];
  56395. $args = array();
  56396. if (!empty($v['args'])) {
  56397. foreach ($v['args'] as $arg) {
  56398. if (is_null($arg)) $args[] = 'null';
  56399. elseif (is_array($arg)) $args[] = 'Array';
  56400. elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
  56401. elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
  56402. elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
  56403. else {
  56404. $arg = (string)$arg;
  56405. $str = htmlspecialchars(substr($arg, 0, 16));
  56406. if (strlen($arg) > 16) $str .= '&hellip;';
  56407. $args[] = "'" . $str . "'";
  56408. }
  56409. }
  56410. }
  56411. $html .= '(' . implode(', ',$args) . ')'
  56412. . '</td>'
  56413. . '<td>' . (isset($v['file']) ? $v['file'] : 'unknown')
  56414. . ':' . (isset($v['line']) ? $v['line'] : 'unknown')
  56415. . '</td></tr>' . "\n";
  56416. }
  56417. $html .= '<tr><td style="text-align: center;">' . ($k+1) . '</td>'
  56418. . '<td>{main}</td>'
  56419. . '<td>&nbsp;</td></tr>' . "\n"
  56420. . '</table>';
  56421. return $html;
  56422. }
  56423. public function toText()
  56424. {
  56425. $causes = array();
  56426. $this->getCauseMessage($causes);
  56427. $causeMsg = '';
  56428. foreach ($causes as $i => $cause) {
  56429. $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': '
  56430. . $cause['message'] . ' in ' . $cause['file']
  56431. . ' on line ' . $cause['line'] . "\n";
  56432. }
  56433. return $causeMsg . $this->getTraceAsString();
  56434. }
  56435. }�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Frontend.php����������������������������������������������������������������������0000644�0001750�0001750�00000014772�13565304531�015310� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  56436. /**
  56437. * PEAR_Frontend, the singleton-based frontend for user input/output
  56438. *
  56439. * PHP versions 4 and 5
  56440. *
  56441. * @category pear
  56442. * @package PEAR
  56443. * @author Greg Beaver <cellog@php.net>
  56444. * @copyright 1997-2009 The Authors
  56445. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  56446. * @link http://pear.php.net/package/PEAR
  56447. * @since File available since Release 1.4.0a1
  56448. */
  56449. /**
  56450. * Include error handling
  56451. */
  56452. //require_once 'PEAR.php';
  56453. /**
  56454. * Which user interface class is being used.
  56455. * @var string class name
  56456. */
  56457. $GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
  56458. /**
  56459. * Instance of $_PEAR_Command_uiclass.
  56460. * @var object
  56461. */
  56462. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
  56463. /**
  56464. * Singleton-based frontend for PEAR user input/output
  56465. *
  56466. * @category pear
  56467. * @package PEAR
  56468. * @author Greg Beaver <cellog@php.net>
  56469. * @copyright 1997-2009 The Authors
  56470. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  56471. * @version Release: 1.10.10
  56472. * @link http://pear.php.net/package/PEAR
  56473. * @since Class available since Release 1.4.0a1
  56474. */
  56475. class PEAR_Frontend extends PEAR
  56476. {
  56477. /**
  56478. * Retrieve the frontend object
  56479. * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
  56480. */
  56481. public static function &singleton($type = null)
  56482. {
  56483. if ($type === null) {
  56484. if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
  56485. $a = false;
  56486. return $a;
  56487. }
  56488. return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  56489. }
  56490. $a = PEAR_Frontend::setFrontendClass($type);
  56491. return $a;
  56492. }
  56493. /**
  56494. * Set the frontend class that will be used by calls to {@link singleton()}
  56495. *
  56496. * Frontends are expected to conform to the PEAR naming standard of
  56497. * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php)
  56498. * @param string $uiclass full class name
  56499. * @return PEAR_Frontend
  56500. */
  56501. public static function &setFrontendClass($uiclass)
  56502. {
  56503. if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  56504. is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
  56505. return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  56506. }
  56507. if (!class_exists($uiclass)) {
  56508. $file = str_replace('_', '/', $uiclass) . '.php';
  56509. if (PEAR_Frontend::isIncludeable($file)) {
  56510. include_once $file;
  56511. }
  56512. }
  56513. if (class_exists($uiclass)) {
  56514. $obj = new $uiclass;
  56515. // quick test to see if this class implements a few of the most
  56516. // important frontend methods
  56517. if (is_a($obj, 'PEAR_Frontend')) {
  56518. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
  56519. $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
  56520. return $obj;
  56521. }
  56522. $err = PEAR::raiseError("not a frontend class: $uiclass");
  56523. return $err;
  56524. }
  56525. $err = PEAR::raiseError("no such class: $uiclass");
  56526. return $err;
  56527. }
  56528. /**
  56529. * Set the frontend class that will be used by calls to {@link singleton()}
  56530. *
  56531. * Frontends are expected to be a descendant of PEAR_Frontend
  56532. * @param PEAR_Frontend
  56533. * @return PEAR_Frontend
  56534. */
  56535. public static function &setFrontendObject($uiobject)
  56536. {
  56537. if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  56538. is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) {
  56539. return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  56540. }
  56541. if (!is_a($uiobject, 'PEAR_Frontend')) {
  56542. $err = PEAR::raiseError('not a valid frontend class: (' .
  56543. get_class($uiobject) . ')');
  56544. return $err;
  56545. }
  56546. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
  56547. $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
  56548. return $uiobject;
  56549. }
  56550. /**
  56551. * @param string $path relative or absolute include path
  56552. * @return boolean
  56553. */
  56554. public static function isIncludeable($path)
  56555. {
  56556. if (file_exists($path) && is_readable($path)) {
  56557. return true;
  56558. }
  56559. $fp = @fopen($path, 'r', true);
  56560. if ($fp) {
  56561. fclose($fp);
  56562. return true;
  56563. }
  56564. return false;
  56565. }
  56566. /**
  56567. * @param PEAR_Config
  56568. */
  56569. function setConfig(&$config)
  56570. {
  56571. }
  56572. /**
  56573. * This can be overridden to allow session-based temporary file management
  56574. *
  56575. * By default, all files are deleted at the end of a session. The web installer
  56576. * needs to be able to sustain a list over many sessions in order to support
  56577. * user interaction with install scripts
  56578. */
  56579. static function addTempFile($file)
  56580. {
  56581. $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  56582. }
  56583. /**
  56584. * Log an action
  56585. *
  56586. * @param string $msg the message to log
  56587. * @param boolean $append_crlf
  56588. * @return boolean true
  56589. * @abstract
  56590. */
  56591. function log($msg, $append_crlf = true)
  56592. {
  56593. }
  56594. /**
  56595. * Run a post-installation script
  56596. *
  56597. * @param array $scripts array of post-install scripts
  56598. * @abstract
  56599. */
  56600. function runPostinstallScripts(&$scripts)
  56601. {
  56602. }
  56603. /**
  56604. * Display human-friendly output formatted depending on the
  56605. * $command parameter.
  56606. *
  56607. * This should be able to handle basic output data with no command
  56608. * @param mixed $data data structure containing the information to display
  56609. * @param string $command command from which this method was called
  56610. * @abstract
  56611. */
  56612. function outputData($data, $command = '_default')
  56613. {
  56614. }
  56615. /**
  56616. * Display a modal form dialog and return the given input
  56617. *
  56618. * A frontend that requires multiple requests to retrieve and process
  56619. * data must take these needs into account, and implement the request
  56620. * handling code.
  56621. * @param string $command command from which this method was called
  56622. * @param array $prompts associative array. keys are the input field names
  56623. * and values are the description
  56624. * @param array $types array of input field types (text, password,
  56625. * etc.) keys have to be the same like in $prompts
  56626. * @param array $defaults array of default values. again keys have
  56627. * to be the same like in $prompts. Do not depend
  56628. * on a default value being set.
  56629. * @return array input sent by the user
  56630. * @abstract
  56631. */
  56632. function userDialog($command, $prompts, $types = array(), $defaults = array())
  56633. {
  56634. }
  56635. }
  56636. ������PEAR-1.10.10/PEAR/Installer.php���������������������������������������������������������������������0000644�0001750�0001750�00000210666�13565304531�015466� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  56637. /**
  56638. * PEAR_Installer
  56639. *
  56640. * PHP versions 4 and 5
  56641. *
  56642. * @category pear
  56643. * @package PEAR
  56644. * @author Stig Bakken <ssb@php.net>
  56645. * @author Tomas V.V. Cox <cox@idecnet.com>
  56646. * @author Martin Jansen <mj@php.net>
  56647. * @author Greg Beaver <cellog@php.net>
  56648. * @copyright 1997-2009 The Authors
  56649. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  56650. * @link http://pear.php.net/package/PEAR
  56651. * @since File available since Release 0.1
  56652. */
  56653. /**
  56654. * Used for installation groups in package.xml 2.0 and platform exceptions
  56655. */
  56656. require_once 'OS/Guess.php';
  56657. require_once 'PEAR/Downloader.php';
  56658. define('PEAR_INSTALLER_NOBINARY', -240);
  56659. /**
  56660. * Administration class used to install PEAR packages and maintain the
  56661. * installed package database.
  56662. *
  56663. * @category pear
  56664. * @package PEAR
  56665. * @author Stig Bakken <ssb@php.net>
  56666. * @author Tomas V.V. Cox <cox@idecnet.com>
  56667. * @author Martin Jansen <mj@php.net>
  56668. * @author Greg Beaver <cellog@php.net>
  56669. * @copyright 1997-2009 The Authors
  56670. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  56671. * @version Release: 1.10.10
  56672. * @link http://pear.php.net/package/PEAR
  56673. * @since Class available since Release 0.1
  56674. */
  56675. class PEAR_Installer extends PEAR_Downloader
  56676. {
  56677. // {{{ properties
  56678. /** name of the package directory, for example Foo-1.0
  56679. * @var string
  56680. */
  56681. var $pkgdir;
  56682. /** directory where PHP code files go
  56683. * @var string
  56684. */
  56685. var $phpdir;
  56686. /** directory where PHP extension files go
  56687. * @var string
  56688. */
  56689. var $extdir;
  56690. /** directory where documentation goes
  56691. * @var string
  56692. */
  56693. var $docdir;
  56694. /** installation root directory (ala PHP's INSTALL_ROOT or
  56695. * automake's DESTDIR
  56696. * @var string
  56697. */
  56698. var $installroot = '';
  56699. /** debug level
  56700. * @var int
  56701. */
  56702. var $debug = 1;
  56703. /** temporary directory
  56704. * @var string
  56705. */
  56706. var $tmpdir;
  56707. /**
  56708. * PEAR_Registry object used by the installer
  56709. * @var PEAR_Registry
  56710. */
  56711. var $registry;
  56712. /**
  56713. * array of PEAR_Downloader_Packages
  56714. * @var array
  56715. */
  56716. var $_downloadedPackages;
  56717. /** List of file transactions queued for an install/upgrade/uninstall.
  56718. *
  56719. * Format:
  56720. * array(
  56721. * 0 => array("rename => array("from-file", "to-file")),
  56722. * 1 => array("delete" => array("file-to-delete")),
  56723. * ...
  56724. * )
  56725. *
  56726. * @var array
  56727. */
  56728. var $file_operations = array();
  56729. // }}}
  56730. // {{{ constructor
  56731. /**
  56732. * PEAR_Installer constructor.
  56733. *
  56734. * @param object $ui user interface object (instance of PEAR_Frontend_*)
  56735. *
  56736. * @access public
  56737. */
  56738. function __construct(&$ui)
  56739. {
  56740. parent::__construct($ui, array(), null);
  56741. $this->setFrontendObject($ui);
  56742. $this->debug = $this->config->get('verbose');
  56743. }
  56744. function setOptions($options)
  56745. {
  56746. $this->_options = $options;
  56747. }
  56748. function setConfig(&$config)
  56749. {
  56750. $this->config = &$config;
  56751. $this->_registry = &$config->getRegistry();
  56752. }
  56753. // }}}
  56754. function _removeBackups($files)
  56755. {
  56756. foreach ($files as $path) {
  56757. $this->addFileOperation('removebackup', array($path));
  56758. }
  56759. }
  56760. // {{{ _deletePackageFiles()
  56761. /**
  56762. * Delete a package's installed files, does not remove empty directories.
  56763. *
  56764. * @param string package name
  56765. * @param string channel name
  56766. * @param bool if true, then files are backed up first
  56767. * @return bool TRUE on success, or a PEAR error on failure
  56768. * @access protected
  56769. */
  56770. function _deletePackageFiles($package, $channel = false, $backup = false)
  56771. {
  56772. if (!$channel) {
  56773. $channel = 'pear.php.net';
  56774. }
  56775. if (!strlen($package)) {
  56776. return $this->raiseError("No package to uninstall given");
  56777. }
  56778. if (strtolower($package) == 'pear' && $channel == 'pear.php.net') {
  56779. // to avoid race conditions, include all possible needed files
  56780. require_once 'PEAR/Task/Common.php';
  56781. require_once 'PEAR/Task/Replace.php';
  56782. require_once 'PEAR/Task/Unixeol.php';
  56783. require_once 'PEAR/Task/Windowseol.php';
  56784. require_once 'PEAR/PackageFile/v1.php';
  56785. require_once 'PEAR/PackageFile/v2.php';
  56786. require_once 'PEAR/PackageFile/Generator/v1.php';
  56787. require_once 'PEAR/PackageFile/Generator/v2.php';
  56788. }
  56789. $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
  56790. if ($filelist == null) {
  56791. return $this->raiseError("$channel/$package not installed");
  56792. }
  56793. $ret = array();
  56794. foreach ($filelist as $file => $props) {
  56795. if (empty($props['installed_as'])) {
  56796. continue;
  56797. }
  56798. $path = $props['installed_as'];
  56799. if ($backup) {
  56800. $this->addFileOperation('backup', array($path));
  56801. $ret[] = $path;
  56802. }
  56803. $this->addFileOperation('delete', array($path));
  56804. }
  56805. if ($backup) {
  56806. return $ret;
  56807. }
  56808. return true;
  56809. }
  56810. // }}}
  56811. // {{{ _installFile()
  56812. /**
  56813. * @param string filename
  56814. * @param array attributes from <file> tag in package.xml
  56815. * @param string path to install the file in
  56816. * @param array options from command-line
  56817. * @access private
  56818. */
  56819. function _installFile($file, $atts, $tmp_path, $options)
  56820. {
  56821. // {{{ return if this file is meant for another platform
  56822. static $os;
  56823. if (!isset($this->_registry)) {
  56824. $this->_registry = &$this->config->getRegistry();
  56825. }
  56826. if (isset($atts['platform'])) {
  56827. if (empty($os)) {
  56828. $os = new OS_Guess();
  56829. }
  56830. if (strlen($atts['platform']) && $atts['platform'][0] == '!') {
  56831. $negate = true;
  56832. $platform = substr($atts['platform'], 1);
  56833. } else {
  56834. $negate = false;
  56835. $platform = $atts['platform'];
  56836. }
  56837. if ((bool) $os->matchSignature($platform) === $negate) {
  56838. $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
  56839. return PEAR_INSTALLER_SKIPPED;
  56840. }
  56841. }
  56842. // }}}
  56843. $channel = $this->pkginfo->getChannel();
  56844. // {{{ assemble the destination paths
  56845. switch ($atts['role']) {
  56846. case 'src':
  56847. case 'extsrc':
  56848. $this->source_files++;
  56849. return;
  56850. case 'doc':
  56851. case 'data':
  56852. case 'test':
  56853. $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) .
  56854. DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
  56855. unset($atts['baseinstalldir']);
  56856. break;
  56857. case 'ext':
  56858. case 'php':
  56859. $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
  56860. break;
  56861. case 'script':
  56862. $dest_dir = $this->config->get('bin_dir', null, $channel);
  56863. break;
  56864. default:
  56865. return $this->raiseError("Invalid role `$atts[role]' for file $file");
  56866. }
  56867. $save_destdir = $dest_dir;
  56868. if (!empty($atts['baseinstalldir'])) {
  56869. $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
  56870. }
  56871. if (dirname($file) != '.' && empty($atts['install-as'])) {
  56872. $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
  56873. }
  56874. if (empty($atts['install-as'])) {
  56875. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
  56876. } else {
  56877. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
  56878. }
  56879. $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
  56880. // Clean up the DIRECTORY_SEPARATOR mess
  56881. $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  56882. list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
  56883. array(DIRECTORY_SEPARATOR,
  56884. DIRECTORY_SEPARATOR,
  56885. DIRECTORY_SEPARATOR),
  56886. array($dest_file, $orig_file));
  56887. $final_dest_file = $installed_as = $dest_file;
  56888. if (isset($this->_options['packagingroot'])) {
  56889. $installedas_dest_dir = dirname($final_dest_file);
  56890. $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  56891. $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']);
  56892. } else {
  56893. $installedas_dest_dir = dirname($final_dest_file);
  56894. $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  56895. }
  56896. $dest_dir = dirname($final_dest_file);
  56897. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  56898. if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
  56899. return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
  56900. }
  56901. // }}}
  56902. if (empty($this->_options['register-only']) &&
  56903. (!file_exists($dest_dir) || !is_dir($dest_dir))) {
  56904. if (!$this->mkDirHier($dest_dir)) {
  56905. return $this->raiseError("failed to mkdir $dest_dir",
  56906. PEAR_INSTALLER_FAILED);
  56907. }
  56908. $this->log(3, "+ mkdir $dest_dir");
  56909. }
  56910. // pretty much nothing happens if we are only registering the install
  56911. if (empty($this->_options['register-only'])) {
  56912. if (empty($atts['replacements'])) {
  56913. if (!file_exists($orig_file)) {
  56914. return $this->raiseError("file $orig_file does not exist",
  56915. PEAR_INSTALLER_FAILED);
  56916. }
  56917. if (!@copy($orig_file, $dest_file)) {
  56918. return $this->raiseError(
  56919. "failed to write $dest_file: " . error_get_last()["message"],
  56920. PEAR_INSTALLER_FAILED);
  56921. }
  56922. $this->log(3, "+ cp $orig_file $dest_file");
  56923. if (isset($atts['md5sum'])) {
  56924. $md5sum = md5_file($dest_file);
  56925. }
  56926. } else {
  56927. // {{{ file with replacements
  56928. if (!file_exists($orig_file)) {
  56929. return $this->raiseError("file does not exist",
  56930. PEAR_INSTALLER_FAILED);
  56931. }
  56932. $contents = file_get_contents($orig_file);
  56933. if ($contents === false) {
  56934. $contents = '';
  56935. }
  56936. if (isset($atts['md5sum'])) {
  56937. $md5sum = md5($contents);
  56938. }
  56939. $subst_from = $subst_to = array();
  56940. foreach ($atts['replacements'] as $a) {
  56941. $to = '';
  56942. if ($a['type'] == 'php-const') {
  56943. if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) {
  56944. eval("\$to = $a[to];");
  56945. } else {
  56946. if (!isset($options['soft'])) {
  56947. $this->log(0, "invalid php-const replacement: $a[to]");
  56948. }
  56949. continue;
  56950. }
  56951. } elseif ($a['type'] == 'pear-config') {
  56952. if ($a['to'] == 'master_server') {
  56953. $chan = $this->_registry->getChannel($channel);
  56954. if (!PEAR::isError($chan)) {
  56955. $to = $chan->getServer();
  56956. } else {
  56957. $to = $this->config->get($a['to'], null, $channel);
  56958. }
  56959. } else {
  56960. $to = $this->config->get($a['to'], null, $channel);
  56961. }
  56962. if (is_null($to)) {
  56963. if (!isset($options['soft'])) {
  56964. $this->log(0, "invalid pear-config replacement: $a[to]");
  56965. }
  56966. continue;
  56967. }
  56968. } elseif ($a['type'] == 'package-info') {
  56969. if ($t = $this->pkginfo->packageInfo($a['to'])) {
  56970. $to = $t;
  56971. } else {
  56972. if (!isset($options['soft'])) {
  56973. $this->log(0, "invalid package-info replacement: $a[to]");
  56974. }
  56975. continue;
  56976. }
  56977. }
  56978. if (!is_null($to)) {
  56979. $subst_from[] = $a['from'];
  56980. $subst_to[] = $to;
  56981. }
  56982. }
  56983. $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
  56984. if (sizeof($subst_from)) {
  56985. $contents = str_replace($subst_from, $subst_to, $contents);
  56986. }
  56987. $wp = @fopen($dest_file, "wb");
  56988. if (!is_resource($wp)) {
  56989. return $this->raiseError(
  56990. "failed to create $dest_file: " . error_get_last()["message"],
  56991. PEAR_INSTALLER_FAILED);
  56992. }
  56993. if (@fwrite($wp, $contents) === false) {
  56994. return $this->raiseError(
  56995. "failed writing to $dest_file: " . error_get_last()["message"],
  56996. PEAR_INSTALLER_FAILED);
  56997. }
  56998. fclose($wp);
  56999. // }}}
  57000. }
  57001. // {{{ check the md5
  57002. if (isset($md5sum)) {
  57003. if (strtolower($md5sum) === strtolower($atts['md5sum'])) {
  57004. $this->log(2, "md5sum ok: $final_dest_file");
  57005. } else {
  57006. if (empty($options['force'])) {
  57007. // delete the file
  57008. if (file_exists($dest_file)) {
  57009. unlink($dest_file);
  57010. }
  57011. if (!isset($options['ignore-errors'])) {
  57012. return $this->raiseError("bad md5sum for file $final_dest_file",
  57013. PEAR_INSTALLER_FAILED);
  57014. }
  57015. if (!isset($options['soft'])) {
  57016. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  57017. }
  57018. } else {
  57019. if (!isset($options['soft'])) {
  57020. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  57021. }
  57022. }
  57023. }
  57024. }
  57025. // }}}
  57026. // {{{ set file permissions
  57027. if (!OS_WINDOWS) {
  57028. if ($atts['role'] == 'script') {
  57029. $mode = 0777 & ~(int)octdec($this->config->get('umask'));
  57030. $this->log(3, "+ chmod +x $dest_file");
  57031. } else {
  57032. $mode = 0666 & ~(int)octdec($this->config->get('umask'));
  57033. }
  57034. if ($atts['role'] != 'src') {
  57035. $this->addFileOperation("chmod", array($mode, $dest_file));
  57036. if (!@chmod($dest_file, $mode)) {
  57037. if (!isset($options['soft'])) {
  57038. $this->log(0, "failed to change mode of $dest_file: " .
  57039. error_get_last()["message"]);
  57040. }
  57041. }
  57042. }
  57043. }
  57044. // }}}
  57045. if ($atts['role'] == 'src') {
  57046. rename($dest_file, $final_dest_file);
  57047. $this->log(2, "renamed source file $dest_file to $final_dest_file");
  57048. } else {
  57049. $this->addFileOperation("rename", array($dest_file, $final_dest_file,
  57050. $atts['role'] == 'ext'));
  57051. }
  57052. }
  57053. // Store the full path where the file was installed for easy unistall
  57054. if ($atts['role'] != 'script') {
  57055. $loc = $this->config->get($atts['role'] . '_dir');
  57056. } else {
  57057. $loc = $this->config->get('bin_dir');
  57058. }
  57059. if ($atts['role'] != 'src') {
  57060. $this->addFileOperation("installed_as", array($file, $installed_as,
  57061. $loc,
  57062. dirname(substr($installedas_dest_file, strlen($loc)))));
  57063. }
  57064. //$this->log(2, "installed: $dest_file");
  57065. return PEAR_INSTALLER_OK;
  57066. }
  57067. // }}}
  57068. // {{{ _installFile2()
  57069. /**
  57070. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  57071. * @param string filename
  57072. * @param array attributes from <file> tag in package.xml
  57073. * @param string path to install the file in
  57074. * @param array options from command-line
  57075. * @access private
  57076. */
  57077. function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options)
  57078. {
  57079. $atts = $real_atts;
  57080. if (!isset($this->_registry)) {
  57081. $this->_registry = &$this->config->getRegistry();
  57082. }
  57083. $channel = $pkg->getChannel();
  57084. // {{{ assemble the destination paths
  57085. if (!in_array($atts['attribs']['role'],
  57086. PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
  57087. return $this->raiseError('Invalid role `' . $atts['attribs']['role'] .
  57088. "' for file $file");
  57089. }
  57090. $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config);
  57091. $err = $role->setup($this, $pkg, $atts['attribs'], $file);
  57092. if (PEAR::isError($err)) {
  57093. return $err;
  57094. }
  57095. if (!$role->isInstallable()) {
  57096. return;
  57097. }
  57098. $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
  57099. if (PEAR::isError($info)) {
  57100. return $info;
  57101. }
  57102. list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
  57103. if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
  57104. return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
  57105. }
  57106. $final_dest_file = $installed_as = $dest_file;
  57107. if (isset($this->_options['packagingroot'])) {
  57108. $final_dest_file = $this->_prependPath($final_dest_file,
  57109. $this->_options['packagingroot']);
  57110. }
  57111. $dest_dir = dirname($final_dest_file);
  57112. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  57113. // }}}
  57114. if (empty($this->_options['register-only'])) {
  57115. if (!file_exists($dest_dir) || !is_dir($dest_dir)) {
  57116. if (!$this->mkDirHier($dest_dir)) {
  57117. return $this->raiseError("failed to mkdir $dest_dir",
  57118. PEAR_INSTALLER_FAILED);
  57119. }
  57120. $this->log(3, "+ mkdir $dest_dir");
  57121. }
  57122. }
  57123. $attribs = $atts['attribs'];
  57124. unset($atts['attribs']);
  57125. // pretty much nothing happens if we are only registering the install
  57126. if (empty($this->_options['register-only'])) {
  57127. if (!count($atts)) { // no tasks
  57128. if (!file_exists($orig_file)) {
  57129. return $this->raiseError("file $orig_file does not exist",
  57130. PEAR_INSTALLER_FAILED);
  57131. }
  57132. if (!@copy($orig_file, $dest_file)) {
  57133. return $this->raiseError(
  57134. "failed to write $dest_file: " . error_get_last()["message"],
  57135. PEAR_INSTALLER_FAILED);
  57136. }
  57137. $this->log(3, "+ cp $orig_file $dest_file");
  57138. if (isset($attribs['md5sum'])) {
  57139. $md5sum = md5_file($dest_file);
  57140. }
  57141. } else { // file with tasks
  57142. if (!file_exists($orig_file)) {
  57143. return $this->raiseError("file $orig_file does not exist",
  57144. PEAR_INSTALLER_FAILED);
  57145. }
  57146. $contents = file_get_contents($orig_file);
  57147. if ($contents === false) {
  57148. $contents = '';
  57149. }
  57150. if (isset($attribs['md5sum'])) {
  57151. $md5sum = md5($contents);
  57152. }
  57153. foreach ($atts as $tag => $raw) {
  57154. $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag);
  57155. $task = "PEAR_Task_$tag";
  57156. $task = new $task($this->config, $this, PEAR_TASK_INSTALL);
  57157. if (!$task->isScript()) { // scripts are only handled after installation
  57158. $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
  57159. $res = $task->startSession($pkg, $contents, $final_dest_file);
  57160. if ($res === false) {
  57161. continue; // skip this file
  57162. }
  57163. if (PEAR::isError($res)) {
  57164. return $res;
  57165. }
  57166. $contents = $res; // save changes
  57167. }
  57168. $wp = @fopen($dest_file, "wb");
  57169. if (!is_resource($wp)) {
  57170. return $this->raiseError(
  57171. "failed to create $dest_file: " . error_get_last()["message"],
  57172. PEAR_INSTALLER_FAILED);
  57173. }
  57174. if (fwrite($wp, $contents) === false) {
  57175. return $this->raiseError(
  57176. "failed writing to $dest_file: " . error_get_last()["message"],
  57177. PEAR_INSTALLER_FAILED);
  57178. }
  57179. fclose($wp);
  57180. }
  57181. }
  57182. // {{{ check the md5
  57183. if (isset($md5sum)) {
  57184. // Make sure the original md5 sum matches with expected
  57185. if (strtolower($md5sum) === strtolower($attribs['md5sum'])) {
  57186. $this->log(2, "md5sum ok: $final_dest_file");
  57187. if (isset($contents)) {
  57188. // set md5 sum based on $content in case any tasks were run.
  57189. $real_atts['attribs']['md5sum'] = md5($contents);
  57190. }
  57191. } else {
  57192. if (empty($options['force'])) {
  57193. // delete the file
  57194. if (file_exists($dest_file)) {
  57195. unlink($dest_file);
  57196. }
  57197. if (!isset($options['ignore-errors'])) {
  57198. return $this->raiseError("bad md5sum for file $final_dest_file",
  57199. PEAR_INSTALLER_FAILED);
  57200. }
  57201. if (!isset($options['soft'])) {
  57202. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  57203. }
  57204. } else {
  57205. if (!isset($options['soft'])) {
  57206. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  57207. }
  57208. }
  57209. }
  57210. } else {
  57211. $real_atts['attribs']['md5sum'] = md5_file($dest_file);
  57212. }
  57213. // }}}
  57214. // {{{ set file permissions
  57215. if (!OS_WINDOWS) {
  57216. if ($role->isExecutable()) {
  57217. $mode = 0777 & ~(int)octdec($this->config->get('umask'));
  57218. $this->log(3, "+ chmod +x $dest_file");
  57219. } else {
  57220. $mode = 0666 & ~(int)octdec($this->config->get('umask'));
  57221. }
  57222. if ($attribs['role'] != 'src') {
  57223. $this->addFileOperation("chmod", array($mode, $dest_file));
  57224. if (!@chmod($dest_file, $mode)) {
  57225. if (!isset($options['soft'])) {
  57226. $this->log(0, "failed to change mode of $dest_file: " .
  57227. error_get_last()["message"]);
  57228. }
  57229. }
  57230. }
  57231. }
  57232. // }}}
  57233. if ($attribs['role'] == 'src') {
  57234. rename($dest_file, $final_dest_file);
  57235. $this->log(2, "renamed source file $dest_file to $final_dest_file");
  57236. } else {
  57237. $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
  57238. }
  57239. }
  57240. // Store the full path where the file was installed for easy uninstall
  57241. if ($attribs['role'] != 'src') {
  57242. $loc = $this->config->get($role->getLocationConfig(), null, $channel);
  57243. $this->addFileOperation('installed_as', array($file, $installed_as,
  57244. $loc,
  57245. dirname(substr($installed_as, strlen($loc)))));
  57246. }
  57247. //$this->log(2, "installed: $dest_file");
  57248. return PEAR_INSTALLER_OK;
  57249. }
  57250. // }}}
  57251. // {{{ addFileOperation()
  57252. /**
  57253. * Add a file operation to the current file transaction.
  57254. *
  57255. * @see startFileTransaction()
  57256. * @param string $type This can be one of:
  57257. * - rename: rename a file ($data has 3 values)
  57258. * - backup: backup an existing file ($data has 1 value)
  57259. * - removebackup: clean up backups created during install ($data has 1 value)
  57260. * - chmod: change permissions on a file ($data has 2 values)
  57261. * - delete: delete a file ($data has 1 value)
  57262. * - rmdir: delete a directory if empty ($data has 1 value)
  57263. * - installed_as: mark a file as installed ($data has 4 values).
  57264. * @param array $data For all file operations, this array must contain the
  57265. * full path to the file or directory that is being operated on. For
  57266. * the rename command, the first parameter must be the file to rename,
  57267. * the second its new name, the third whether this is a PHP extension.
  57268. *
  57269. * The installed_as operation contains 4 elements in this order:
  57270. * 1. Filename as listed in the filelist element from package.xml
  57271. * 2. Full path to the installed file
  57272. * 3. Full path from the php_dir configuration variable used in this
  57273. * installation
  57274. * 4. Relative path from the php_dir that this file is installed in
  57275. */
  57276. function addFileOperation($type, $data)
  57277. {
  57278. if (!is_array($data)) {
  57279. return $this->raiseError('Internal Error: $data in addFileOperation'
  57280. . ' must be an array, was ' . gettype($data));
  57281. }
  57282. if ($type == 'chmod') {
  57283. $octmode = decoct($data[0]);
  57284. $this->log(3, "adding to transaction: $type $octmode $data[1]");
  57285. } else {
  57286. $this->log(3, "adding to transaction: $type " . implode(" ", $data));
  57287. }
  57288. $this->file_operations[] = array($type, $data);
  57289. }
  57290. // }}}
  57291. // {{{ startFileTransaction()
  57292. function startFileTransaction($rollback_in_case = false)
  57293. {
  57294. if (count($this->file_operations) && $rollback_in_case) {
  57295. $this->rollbackFileTransaction();
  57296. }
  57297. $this->file_operations = array();
  57298. }
  57299. // }}}
  57300. // {{{ commitFileTransaction()
  57301. function commitFileTransaction()
  57302. {
  57303. // {{{ first, check permissions and such manually
  57304. $errors = array();
  57305. foreach ($this->file_operations as $key => $tr) {
  57306. list($type, $data) = $tr;
  57307. switch ($type) {
  57308. case 'rename':
  57309. if (!file_exists($data[0])) {
  57310. $errors[] = "cannot rename file $data[0], doesn't exist";
  57311. }
  57312. // check that dest dir. is writable
  57313. if (!is_writable(dirname($data[1]))) {
  57314. $errors[] = "permission denied ($type): $data[1]";
  57315. }
  57316. break;
  57317. case 'chmod':
  57318. // check that file is writable
  57319. if (!is_writable($data[1])) {
  57320. $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
  57321. }
  57322. break;
  57323. case 'delete':
  57324. if (!file_exists($data[0])) {
  57325. $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
  57326. }
  57327. // check that directory is writable
  57328. if (file_exists($data[0])) {
  57329. if (!is_writable(dirname($data[0]))) {
  57330. $errors[] = "permission denied ($type): $data[0]";
  57331. } else {
  57332. // make sure the file to be deleted can be opened for writing
  57333. $fp = false;
  57334. if (!is_dir($data[0]) &&
  57335. (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) {
  57336. $errors[] = "permission denied ($type): $data[0]";
  57337. } elseif ($fp) {
  57338. fclose($fp);
  57339. }
  57340. }
  57341. /* Verify we are not deleting a file owned by another package
  57342. * This can happen when a file moves from package A to B in
  57343. * an upgrade ala http://pear.php.net/17986
  57344. */
  57345. $info = array(
  57346. 'package' => strtolower($this->pkginfo->getName()),
  57347. 'channel' => strtolower($this->pkginfo->getChannel()),
  57348. );
  57349. $result = $this->_registry->checkFileMap($data[0], $info, '1.1');
  57350. if (is_array($result)) {
  57351. $res = array_diff($result, $info);
  57352. if (!empty($res)) {
  57353. $new = $this->_registry->getPackage($result[1], $result[0]);
  57354. $this->file_operations[$key] = false;
  57355. $pkginfoName = $this->pkginfo->getName();
  57356. $newChannel = $new->getChannel();
  57357. $newPackage = $new->getName();
  57358. $this->log(3, "file $data[0] was scheduled for removal from $pkginfoName but is owned by $newChannel/$newPackage, removal has been cancelled.");
  57359. }
  57360. }
  57361. }
  57362. break;
  57363. }
  57364. }
  57365. // }}}
  57366. $n = count($this->file_operations);
  57367. $this->log(2, "about to commit $n file operations for " . $this->pkginfo->getName());
  57368. $m = count($errors);
  57369. if ($m > 0) {
  57370. foreach ($errors as $error) {
  57371. if (!isset($this->_options['soft'])) {
  57372. $this->log(1, $error);
  57373. }
  57374. }
  57375. if (!isset($this->_options['ignore-errors'])) {
  57376. return false;
  57377. }
  57378. }
  57379. $this->_dirtree = array();
  57380. // {{{ really commit the transaction
  57381. foreach ($this->file_operations as $i => $tr) {
  57382. if (!$tr) {
  57383. // support removal of non-existing backups
  57384. continue;
  57385. }
  57386. list($type, $data) = $tr;
  57387. switch ($type) {
  57388. case 'backup':
  57389. if (!file_exists($data[0])) {
  57390. $this->file_operations[$i] = false;
  57391. break;
  57392. }
  57393. if (!@copy($data[0], $data[0] . '.bak')) {
  57394. $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] .
  57395. '.bak ' . error_get_last()["message"]);
  57396. return false;
  57397. }
  57398. $this->log(3, "+ backup $data[0] to $data[0].bak");
  57399. break;
  57400. case 'removebackup':
  57401. if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
  57402. unlink($data[0] . '.bak');
  57403. $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
  57404. }
  57405. break;
  57406. case 'rename':
  57407. $test = file_exists($data[1]) ? @unlink($data[1]) : null;
  57408. if (!$test && file_exists($data[1])) {
  57409. if ($data[2]) {
  57410. $extra = ', this extension must be installed manually. Rename to "' .
  57411. basename($data[1]) . '"';
  57412. } else {
  57413. $extra = '';
  57414. }
  57415. if (!isset($this->_options['soft'])) {
  57416. $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' .
  57417. $data[0] . $extra);
  57418. }
  57419. if (!isset($this->_options['ignore-errors'])) {
  57420. return false;
  57421. }
  57422. }
  57423. // permissions issues with rename - copy() is far superior
  57424. $perms = @fileperms($data[0]);
  57425. if (!@copy($data[0], $data[1])) {
  57426. $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] .
  57427. ' ' . error_get_last()["message"]);
  57428. return false;
  57429. }
  57430. // copy over permissions, otherwise they are lost
  57431. @chmod($data[1], $perms);
  57432. @unlink($data[0]);
  57433. $this->log(3, "+ mv $data[0] $data[1]");
  57434. break;
  57435. case 'chmod':
  57436. if (!@chmod($data[1], $data[0])) {
  57437. $this->log(1, 'Could not chmod ' . $data[1] . ' to ' .
  57438. decoct($data[0]) . ' ' . error_get_last()["message"]);
  57439. return false;
  57440. }
  57441. $octmode = decoct($data[0]);
  57442. $this->log(3, "+ chmod $octmode $data[1]");
  57443. break;
  57444. case 'delete':
  57445. if (file_exists($data[0])) {
  57446. if (!@unlink($data[0])) {
  57447. $this->log(1, 'Could not delete ' . $data[0] . ' ' .
  57448. error_get_last()["message"]);
  57449. return false;
  57450. }
  57451. $this->log(3, "+ rm $data[0]");
  57452. }
  57453. break;
  57454. case 'rmdir':
  57455. if (file_exists($data[0])) {
  57456. do {
  57457. $testme = opendir($data[0]);
  57458. while (false !== ($entry = readdir($testme))) {
  57459. if ($entry == '.' || $entry == '..') {
  57460. continue;
  57461. }
  57462. closedir($testme);
  57463. break 2; // this directory is not empty and can't be
  57464. // deleted
  57465. }
  57466. closedir($testme);
  57467. if (!@rmdir($data[0])) {
  57468. $this->log(1, 'Could not rmdir ' . $data[0] . ' ' .
  57469. error_get_last()["message"]);
  57470. return false;
  57471. }
  57472. $this->log(3, "+ rmdir $data[0]");
  57473. } while (false);
  57474. }
  57475. break;
  57476. case 'installed_as':
  57477. $this->pkginfo->setInstalledAs($data[0], $data[1]);
  57478. if (!isset($this->_dirtree[dirname($data[1])])) {
  57479. $this->_dirtree[dirname($data[1])] = true;
  57480. $this->pkginfo->setDirtree(dirname($data[1]));
  57481. while(!empty($data[3]) && dirname($data[3]) != $data[3] &&
  57482. $data[3] != '/' && $data[3] != '\\') {
  57483. $this->pkginfo->setDirtree($pp =
  57484. $this->_prependPath($data[3], $data[2]));
  57485. $this->_dirtree[$pp] = true;
  57486. $data[3] = dirname($data[3]);
  57487. }
  57488. }
  57489. break;
  57490. }
  57491. }
  57492. // }}}
  57493. $this->log(2, "successfully committed $n file operations");
  57494. $this->file_operations = array();
  57495. return true;
  57496. }
  57497. // }}}
  57498. // {{{ rollbackFileTransaction()
  57499. function rollbackFileTransaction()
  57500. {
  57501. $n = count($this->file_operations);
  57502. $this->log(2, "rolling back $n file operations");
  57503. foreach ($this->file_operations as $tr) {
  57504. list($type, $data) = $tr;
  57505. switch ($type) {
  57506. case 'backup':
  57507. if (file_exists($data[0] . '.bak')) {
  57508. if (file_exists($data[0] && is_writable($data[0]))) {
  57509. unlink($data[0]);
  57510. }
  57511. @copy($data[0] . '.bak', $data[0]);
  57512. $this->log(3, "+ restore $data[0] from $data[0].bak");
  57513. }
  57514. break;
  57515. case 'removebackup':
  57516. if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
  57517. unlink($data[0] . '.bak');
  57518. $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
  57519. }
  57520. break;
  57521. case 'rename':
  57522. @unlink($data[0]);
  57523. $this->log(3, "+ rm $data[0]");
  57524. break;
  57525. case 'mkdir':
  57526. @rmdir($data[0]);
  57527. $this->log(3, "+ rmdir $data[0]");
  57528. break;
  57529. case 'chmod':
  57530. break;
  57531. case 'delete':
  57532. break;
  57533. case 'installed_as':
  57534. $this->pkginfo->setInstalledAs($data[0], false);
  57535. break;
  57536. }
  57537. }
  57538. $this->pkginfo->resetDirtree();
  57539. $this->file_operations = array();
  57540. }
  57541. // }}}
  57542. // {{{ mkDirHier($dir)
  57543. function mkDirHier($dir)
  57544. {
  57545. $this->addFileOperation('mkdir', array($dir));
  57546. return parent::mkDirHier($dir);
  57547. }
  57548. // }}}
  57549. // {{{ _parsePackageXml()
  57550. function _parsePackageXml(&$descfile)
  57551. {
  57552. // Parse xml file -----------------------------------------------
  57553. $pkg = new PEAR_PackageFile($this->config, $this->debug);
  57554. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  57555. $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
  57556. PEAR::staticPopErrorHandling();
  57557. if (PEAR::isError($p)) {
  57558. if (is_array($p->getUserInfo())) {
  57559. foreach ($p->getUserInfo() as $err) {
  57560. $loglevel = $err['level'] == 'error' ? 0 : 1;
  57561. if (!isset($this->_options['soft'])) {
  57562. $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
  57563. }
  57564. }
  57565. }
  57566. return $this->raiseError('Installation failed: invalid package file');
  57567. }
  57568. $descfile = $p->getPackageFile();
  57569. return $p;
  57570. }
  57571. // }}}
  57572. /**
  57573. * Set the list of PEAR_Downloader_Package objects to allow more sane
  57574. * dependency validation
  57575. * @param array
  57576. */
  57577. function setDownloadedPackages(&$pkgs)
  57578. {
  57579. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  57580. $err = $this->analyzeDependencies($pkgs);
  57581. PEAR::popErrorHandling();
  57582. if (PEAR::isError($err)) {
  57583. return $err;
  57584. }
  57585. $this->_downloadedPackages = &$pkgs;
  57586. }
  57587. /**
  57588. * Set the list of PEAR_Downloader_Package objects to allow more sane
  57589. * dependency validation
  57590. * @param array
  57591. */
  57592. function setUninstallPackages(&$pkgs)
  57593. {
  57594. $this->_downloadedPackages = &$pkgs;
  57595. }
  57596. function getInstallPackages()
  57597. {
  57598. return $this->_downloadedPackages;
  57599. }
  57600. // {{{ install()
  57601. /**
  57602. * Installs the files within the package file specified.
  57603. *
  57604. * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
  57605. * or a pre-initialized packagefile object
  57606. * @param array $options
  57607. * recognized options:
  57608. * - installroot : optional prefix directory for installation
  57609. * - force : force installation
  57610. * - register-only : update registry but don't install files
  57611. * - upgrade : upgrade existing install
  57612. * - soft : fail silently
  57613. * - nodeps : ignore dependency conflicts/missing dependencies
  57614. * - alldeps : install all dependencies
  57615. * - onlyreqdeps : install only required dependencies
  57616. *
  57617. * @return array|PEAR_Error package info if successful
  57618. */
  57619. function install($pkgfile, $options = array())
  57620. {
  57621. $this->_options = $options;
  57622. $this->_registry = &$this->config->getRegistry();
  57623. if (is_object($pkgfile)) {
  57624. $dlpkg = &$pkgfile;
  57625. $pkg = $pkgfile->getPackageFile();
  57626. $pkgfile = $pkg->getArchiveFile();
  57627. $descfile = $pkg->getPackageFile();
  57628. } else {
  57629. $descfile = $pkgfile;
  57630. $pkg = $this->_parsePackageXml($descfile);
  57631. if (PEAR::isError($pkg)) {
  57632. return $pkg;
  57633. }
  57634. }
  57635. $tmpdir = dirname($descfile);
  57636. if (realpath($descfile) != realpath($pkgfile)) {
  57637. // Use the temp_dir since $descfile can contain the download dir path
  57638. $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net');
  57639. $tmpdir = System::mktemp('-d -t "' . $tmpdir . '"');
  57640. $tar = new Archive_Tar($pkgfile);
  57641. if (!$tar->extract($tmpdir)) {
  57642. return $this->raiseError("unable to unpack $pkgfile");
  57643. }
  57644. }
  57645. $pkgname = $pkg->getName();
  57646. $channel = $pkg->getChannel();
  57647. if (isset($options['installroot'])) {
  57648. $this->config->setInstallRoot($options['installroot']);
  57649. $this->_registry = &$this->config->getRegistry();
  57650. $installregistry = &$this->_registry;
  57651. $this->installroot = ''; // all done automagically now
  57652. $php_dir = $this->config->get('php_dir', null, $channel);
  57653. } else {
  57654. $this->config->setInstallRoot(false);
  57655. $this->_registry = &$this->config->getRegistry();
  57656. if (isset($this->_options['packagingroot'])) {
  57657. $regdir = $this->_prependPath(
  57658. $this->config->get('php_dir', null, 'pear.php.net'),
  57659. $this->_options['packagingroot']);
  57660. $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
  57661. if ($metadata_dir) {
  57662. $metadata_dir = $this->_prependPath(
  57663. $metadata_dir,
  57664. $this->_options['packagingroot']);
  57665. }
  57666. $packrootphp_dir = $this->_prependPath(
  57667. $this->config->get('php_dir', null, $channel),
  57668. $this->_options['packagingroot']);
  57669. $installregistry = new PEAR_Registry($regdir, false, false, $metadata_dir);
  57670. if (!$installregistry->channelExists($channel, true)) {
  57671. // we need to fake a channel-discover of this channel
  57672. $chanobj = $this->_registry->getChannel($channel, true);
  57673. $installregistry->addChannel($chanobj);
  57674. }
  57675. $php_dir = $packrootphp_dir;
  57676. } else {
  57677. $installregistry = &$this->_registry;
  57678. $php_dir = $this->config->get('php_dir', null, $channel);
  57679. }
  57680. $this->installroot = '';
  57681. }
  57682. // {{{ checks to do when not in "force" mode
  57683. if (empty($options['force']) &&
  57684. (file_exists($this->config->get('php_dir')) &&
  57685. is_dir($this->config->get('php_dir')))) {
  57686. $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
  57687. $instfilelist = $pkg->getInstallationFileList(true);
  57688. if (PEAR::isError($instfilelist)) {
  57689. return $instfilelist;
  57690. }
  57691. // ensure we have the most accurate registry
  57692. $installregistry->flushFileMap();
  57693. $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1');
  57694. if (PEAR::isError($test)) {
  57695. return $test;
  57696. }
  57697. if (sizeof($test)) {
  57698. $pkgs = $this->getInstallPackages();
  57699. $found = false;
  57700. foreach ($pkgs as $param) {
  57701. if ($pkg->isSubpackageOf($param)) {
  57702. $found = true;
  57703. break;
  57704. }
  57705. }
  57706. if ($found) {
  57707. // subpackages can conflict with earlier versions of parent packages
  57708. $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel());
  57709. $tmp = $test;
  57710. foreach ($tmp as $file => $info) {
  57711. if (is_array($info)) {
  57712. if (strtolower($info[1]) == strtolower($param->getPackage()) &&
  57713. strtolower($info[0]) == strtolower($param->getChannel())
  57714. ) {
  57715. if (isset($parentreg['filelist'][$file])) {
  57716. unset($parentreg['filelist'][$file]);
  57717. } else{
  57718. $pos = strpos($file, '/');
  57719. $basedir = substr($file, 0, $pos);
  57720. $file2 = substr($file, $pos + 1);
  57721. if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
  57722. && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
  57723. ) {
  57724. unset($parentreg['filelist'][$file2]);
  57725. }
  57726. }
  57727. unset($test[$file]);
  57728. }
  57729. } else {
  57730. if (strtolower($param->getChannel()) != 'pear.php.net') {
  57731. continue;
  57732. }
  57733. if (strtolower($info) == strtolower($param->getPackage())) {
  57734. if (isset($parentreg['filelist'][$file])) {
  57735. unset($parentreg['filelist'][$file]);
  57736. } else{
  57737. $pos = strpos($file, '/');
  57738. $basedir = substr($file, 0, $pos);
  57739. $file2 = substr($file, $pos + 1);
  57740. if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
  57741. && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
  57742. ) {
  57743. unset($parentreg['filelist'][$file2]);
  57744. }
  57745. }
  57746. unset($test[$file]);
  57747. }
  57748. }
  57749. }
  57750. $pfk = new PEAR_PackageFile($this->config);
  57751. $parentpkg = &$pfk->fromArray($parentreg);
  57752. $installregistry->updatePackage2($parentpkg);
  57753. }
  57754. if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) {
  57755. $tmp = $test;
  57756. foreach ($tmp as $file => $info) {
  57757. if (is_string($info)) {
  57758. // pear.php.net packages are always stored as strings
  57759. if (strtolower($info) == strtolower($param->getPackage())) {
  57760. // upgrading existing package
  57761. unset($test[$file]);
  57762. }
  57763. }
  57764. }
  57765. }
  57766. if (count($test)) {
  57767. $msg = "$channel/$pkgname: conflicting files found:\n";
  57768. $longest = max(array_map("strlen", array_keys($test)));
  57769. $fmt = "%${longest}s (%s)\n";
  57770. foreach ($test as $file => $info) {
  57771. if (!is_array($info)) {
  57772. $info = array('pear.php.net', $info);
  57773. }
  57774. $info = $info[0] . '/' . $info[1];
  57775. $msg .= sprintf($fmt, $file, $info);
  57776. }
  57777. if (!isset($options['ignore-errors'])) {
  57778. return $this->raiseError($msg);
  57779. }
  57780. if (!isset($options['soft'])) {
  57781. $this->log(0, "WARNING: $msg");
  57782. }
  57783. }
  57784. }
  57785. }
  57786. // }}}
  57787. $this->startFileTransaction();
  57788. $usechannel = $channel;
  57789. if ($channel == 'pecl.php.net') {
  57790. $test = $installregistry->packageExists($pkgname, $channel);
  57791. if (!$test) {
  57792. $test = $installregistry->packageExists($pkgname, 'pear.php.net');
  57793. $usechannel = 'pear.php.net';
  57794. }
  57795. } else {
  57796. $test = $installregistry->packageExists($pkgname, $channel);
  57797. }
  57798. if (empty($options['upgrade']) && empty($options['soft'])) {
  57799. // checks to do only when installing new packages
  57800. if (empty($options['force']) && $test) {
  57801. return $this->raiseError("$channel/$pkgname is already installed");
  57802. }
  57803. } else {
  57804. // Upgrade
  57805. if ($test) {
  57806. $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel);
  57807. $v2 = $pkg->getVersion();
  57808. $cmp = version_compare("$v1", "$v2", 'gt');
  57809. if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
  57810. return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
  57811. }
  57812. }
  57813. }
  57814. // Do cleanups for upgrade and install, remove old release's files first
  57815. if ($test && empty($options['register-only'])) {
  57816. // when upgrading, remove old release's files first:
  57817. if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel,
  57818. true))) {
  57819. if (!isset($options['ignore-errors'])) {
  57820. return $this->raiseError($err);
  57821. }
  57822. if (!isset($options['soft'])) {
  57823. $this->log(0, 'WARNING: ' . $err->getMessage());
  57824. }
  57825. } else {
  57826. $backedup = $err;
  57827. }
  57828. }
  57829. // {{{ Copy files to dest dir ---------------------------------------
  57830. // info from the package it self we want to access from _installFile
  57831. $this->pkginfo = &$pkg;
  57832. // used to determine whether we should build any C code
  57833. $this->source_files = 0;
  57834. $savechannel = $this->config->get('default_channel');
  57835. if (empty($options['register-only']) && !is_dir($php_dir)) {
  57836. if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) {
  57837. return $this->raiseError("no installation destination directory '$php_dir'\n");
  57838. }
  57839. }
  57840. if (substr($pkgfile, -4) != '.xml') {
  57841. $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion();
  57842. }
  57843. $this->configSet('default_channel', $channel);
  57844. // {{{ install files
  57845. $ver = $pkg->getPackagexmlVersion();
  57846. if (version_compare($ver, '2.0', '>=')) {
  57847. $filelist = $pkg->getInstallationFilelist();
  57848. } else {
  57849. $filelist = $pkg->getFileList();
  57850. }
  57851. if (PEAR::isError($filelist)) {
  57852. return $filelist;
  57853. }
  57854. $p = &$installregistry->getPackage($pkgname, $channel);
  57855. $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false;
  57856. $pkg->resetFilelist();
  57857. $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(),
  57858. 'version', $pkg->getChannel()));
  57859. foreach ($filelist as $file => $atts) {
  57860. $this->expectError(PEAR_INSTALLER_FAILED);
  57861. if ($pkg->getPackagexmlVersion() == '1.0') {
  57862. $res = $this->_installFile($file, $atts, $tmpdir, $options);
  57863. } else {
  57864. $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options);
  57865. }
  57866. $this->popExpect();
  57867. if (PEAR::isError($res)) {
  57868. if (empty($options['ignore-errors'])) {
  57869. $this->rollbackFileTransaction();
  57870. if ($res->getMessage() == "file does not exist") {
  57871. $this->raiseError("file $file in package.xml does not exist");
  57872. }
  57873. return $this->raiseError($res);
  57874. }
  57875. if (!isset($options['soft'])) {
  57876. $this->log(0, "Warning: " . $res->getMessage());
  57877. }
  57878. }
  57879. $real = isset($atts['attribs']) ? $atts['attribs'] : $atts;
  57880. if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') {
  57881. // Register files that were installed
  57882. $pkg->installedFile($file, $atts);
  57883. }
  57884. }
  57885. // }}}
  57886. // {{{ compile and install source files
  57887. if ($this->source_files > 0 && empty($options['nobuild'])) {
  57888. $configureoptions = empty($options['configureoptions']) ? '' : $options['configureoptions'];
  57889. if (PEAR::isError($err =
  57890. $this->_compileSourceFiles($savechannel, $pkg, $configureoptions))) {
  57891. return $err;
  57892. }
  57893. }
  57894. // }}}
  57895. if (isset($backedup)) {
  57896. $this->_removeBackups($backedup);
  57897. }
  57898. if (!$this->commitFileTransaction()) {
  57899. $this->rollbackFileTransaction();
  57900. $this->configSet('default_channel', $savechannel);
  57901. return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
  57902. }
  57903. // }}}
  57904. $ret = false;
  57905. $installphase = 'install';
  57906. $oldversion = false;
  57907. // {{{ Register that the package is installed -----------------------
  57908. if (empty($options['upgrade'])) {
  57909. // if 'force' is used, replace the info in registry
  57910. $usechannel = $channel;
  57911. if ($channel == 'pecl.php.net') {
  57912. $test = $installregistry->packageExists($pkgname, $channel);
  57913. if (!$test) {
  57914. $test = $installregistry->packageExists($pkgname, 'pear.php.net');
  57915. $usechannel = 'pear.php.net';
  57916. }
  57917. } else {
  57918. $test = $installregistry->packageExists($pkgname, $channel);
  57919. }
  57920. if (!empty($options['force']) && $test) {
  57921. $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel);
  57922. $installregistry->deletePackage($pkgname, $usechannel);
  57923. }
  57924. $ret = $installregistry->addPackage2($pkg);
  57925. } else {
  57926. if ($dirtree) {
  57927. $this->startFileTransaction();
  57928. // attempt to delete empty directories
  57929. uksort($dirtree, array($this, '_sortDirs'));
  57930. foreach($dirtree as $dir => $notused) {
  57931. $this->addFileOperation('rmdir', array($dir));
  57932. }
  57933. $this->commitFileTransaction();
  57934. }
  57935. $usechannel = $channel;
  57936. if ($channel == 'pecl.php.net') {
  57937. $test = $installregistry->packageExists($pkgname, $channel);
  57938. if (!$test) {
  57939. $test = $installregistry->packageExists($pkgname, 'pear.php.net');
  57940. $usechannel = 'pear.php.net';
  57941. }
  57942. } else {
  57943. $test = $installregistry->packageExists($pkgname, $channel);
  57944. }
  57945. // new: upgrade installs a package if it isn't installed
  57946. if (!$test) {
  57947. $ret = $installregistry->addPackage2($pkg);
  57948. } else {
  57949. if ($usechannel != $channel) {
  57950. $installregistry->deletePackage($pkgname, $usechannel);
  57951. $ret = $installregistry->addPackage2($pkg);
  57952. } else {
  57953. $ret = $installregistry->updatePackage2($pkg);
  57954. }
  57955. $installphase = 'upgrade';
  57956. }
  57957. }
  57958. if (!$ret) {
  57959. $this->configSet('default_channel', $savechannel);
  57960. return $this->raiseError("Adding package $channel/$pkgname to registry failed");
  57961. }
  57962. // }}}
  57963. $this->configSet('default_channel', $savechannel);
  57964. if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist
  57965. if (PEAR_Task_Common::hasPostinstallTasks()) {
  57966. PEAR_Task_Common::runPostinstallTasks($installphase);
  57967. }
  57968. }
  57969. return $pkg->toArray(true);
  57970. }
  57971. // }}}
  57972. // {{{ _compileSourceFiles()
  57973. /**
  57974. * @param string
  57975. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  57976. * @param mixed[] $configureoptions
  57977. */
  57978. function _compileSourceFiles($savechannel, &$filelist, $configureoptions)
  57979. {
  57980. require_once 'PEAR/Builder.php';
  57981. $this->log(1, "$this->source_files source files, building");
  57982. $bob = new PEAR_Builder($configureoptions, $this->ui);
  57983. $bob->debug = $this->debug;
  57984. $built = $bob->build($filelist, array(&$this, '_buildCallback'));
  57985. if (PEAR::isError($built)) {
  57986. $this->rollbackFileTransaction();
  57987. $this->configSet('default_channel', $savechannel);
  57988. return $built;
  57989. }
  57990. $this->log(1, "\nBuild process completed successfully");
  57991. foreach ($built as $ext) {
  57992. $bn = basename($ext['file']);
  57993. list($_ext_name, $_ext_suff) = explode('.', $bn);
  57994. if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
  57995. if (extension_loaded($_ext_name)) {
  57996. $this->raiseError("Extension '$_ext_name' already loaded. " .
  57997. 'Please unload it in your php.ini file ' .
  57998. 'prior to install or upgrade');
  57999. }
  58000. $role = 'ext';
  58001. } else {
  58002. $role = 'src';
  58003. }
  58004. $dest = $ext['dest'];
  58005. $packagingroot = '';
  58006. if (isset($this->_options['packagingroot'])) {
  58007. $packagingroot = $this->_options['packagingroot'];
  58008. }
  58009. $copyto = $this->_prependPath($dest, $packagingroot);
  58010. $extra = $copyto != $dest ? " as '$copyto'" : '';
  58011. $this->log(1, "Installing '$dest'$extra");
  58012. $copydir = dirname($copyto);
  58013. // pretty much nothing happens if we are only registering the install
  58014. if (empty($this->_options['register-only'])) {
  58015. if (!file_exists($copydir) || !is_dir($copydir)) {
  58016. if (!$this->mkDirHier($copydir)) {
  58017. return $this->raiseError("failed to mkdir $copydir",
  58018. PEAR_INSTALLER_FAILED);
  58019. }
  58020. $this->log(3, "+ mkdir $copydir");
  58021. }
  58022. if (!@copy($ext['file'], $copyto)) {
  58023. return $this->raiseError(
  58024. "failed to write $copyto (" . error_get_last()["message"] . ")",
  58025. PEAR_INSTALLER_FAILED);
  58026. }
  58027. $this->log(3, "+ cp $ext[file] $copyto");
  58028. $this->addFileOperation('rename', array($ext['file'], $copyto));
  58029. if (!OS_WINDOWS) {
  58030. $mode = 0666 & ~(int)octdec($this->config->get('umask'));
  58031. $this->addFileOperation('chmod', array($mode, $copyto));
  58032. if (!@chmod($copyto, $mode)) {
  58033. $this->log(0, "failed to change mode of $copyto (" .
  58034. error_get_last()["message"] . ")");
  58035. }
  58036. }
  58037. }
  58038. $data = array(
  58039. 'role' => $role,
  58040. 'name' => $bn,
  58041. 'installed_as' => $dest,
  58042. 'php_api' => $ext['php_api'],
  58043. 'zend_mod_api' => $ext['zend_mod_api'],
  58044. 'zend_ext_api' => $ext['zend_ext_api'],
  58045. );
  58046. if ($filelist->getPackageXmlVersion() == '1.0') {
  58047. $filelist->installedFile($bn, $data);
  58048. } else {
  58049. $filelist->installedFile($bn, array('attribs' => $data));
  58050. }
  58051. }
  58052. }
  58053. // }}}
  58054. function &getUninstallPackages()
  58055. {
  58056. return $this->_downloadedPackages;
  58057. }
  58058. // {{{ uninstall()
  58059. /**
  58060. * Uninstall a package
  58061. *
  58062. * This method removes all files installed by the application, and then
  58063. * removes any empty directories.
  58064. * @param string package name
  58065. * @param array Command-line options. Possibilities include:
  58066. *
  58067. * - installroot: base installation dir, if not the default
  58068. * - register-only : update registry but don't remove files
  58069. * - nodeps: do not process dependencies of other packages to ensure
  58070. * uninstallation does not break things
  58071. */
  58072. function uninstall($package, $options = array())
  58073. {
  58074. $installRoot = isset($options['installroot']) ? $options['installroot'] : '';
  58075. $this->config->setInstallRoot($installRoot);
  58076. $this->installroot = '';
  58077. $this->_registry = &$this->config->getRegistry();
  58078. if (is_object($package)) {
  58079. $channel = $package->getChannel();
  58080. $pkg = $package;
  58081. $package = $pkg->getPackage();
  58082. } else {
  58083. $pkg = false;
  58084. $info = $this->_registry->parsePackageName($package,
  58085. $this->config->get('default_channel'));
  58086. $channel = $info['channel'];
  58087. $package = $info['package'];
  58088. }
  58089. $savechannel = $this->config->get('default_channel');
  58090. $this->configSet('default_channel', $channel);
  58091. if (!is_object($pkg)) {
  58092. $pkg = $this->_registry->getPackage($package, $channel);
  58093. }
  58094. if (!$pkg) {
  58095. $this->configSet('default_channel', $savechannel);
  58096. return $this->raiseError($this->_registry->parsedPackageNameToString(
  58097. array(
  58098. 'channel' => $channel,
  58099. 'package' => $package
  58100. ), true) . ' not installed');
  58101. }
  58102. if ($pkg->getInstalledBinary()) {
  58103. // this is just an alias for a binary package
  58104. return $this->_registry->deletePackage($package, $channel);
  58105. }
  58106. $filelist = $pkg->getFilelist();
  58107. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  58108. if (!class_exists('PEAR_Dependency2')) {
  58109. require_once 'PEAR/Dependency2.php';
  58110. }
  58111. $depchecker = new PEAR_Dependency2($this->config, $options,
  58112. array('channel' => $channel, 'package' => $package),
  58113. PEAR_VALIDATE_UNINSTALLING);
  58114. $e = $depchecker->validatePackageUninstall($this);
  58115. PEAR::staticPopErrorHandling();
  58116. if (PEAR::isError($e)) {
  58117. if (!isset($options['ignore-errors'])) {
  58118. return $this->raiseError($e);
  58119. }
  58120. if (!isset($options['soft'])) {
  58121. $this->log(0, 'WARNING: ' . $e->getMessage());
  58122. }
  58123. } elseif (is_array($e)) {
  58124. if (!isset($options['soft'])) {
  58125. $this->log(0, $e[0]);
  58126. }
  58127. }
  58128. $this->pkginfo = &$pkg;
  58129. // pretty much nothing happens if we are only registering the uninstall
  58130. if (empty($options['register-only'])) {
  58131. // {{{ Delete the files
  58132. $this->startFileTransaction();
  58133. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  58134. if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) {
  58135. PEAR::popErrorHandling();
  58136. $this->rollbackFileTransaction();
  58137. $this->configSet('default_channel', $savechannel);
  58138. if (!isset($options['ignore-errors'])) {
  58139. return $this->raiseError($err);
  58140. }
  58141. if (!isset($options['soft'])) {
  58142. $this->log(0, 'WARNING: ' . $err->getMessage());
  58143. }
  58144. } else {
  58145. PEAR::popErrorHandling();
  58146. }
  58147. if (!$this->commitFileTransaction()) {
  58148. $this->rollbackFileTransaction();
  58149. if (!isset($options['ignore-errors'])) {
  58150. return $this->raiseError("uninstall failed");
  58151. }
  58152. if (!isset($options['soft'])) {
  58153. $this->log(0, 'WARNING: uninstall failed');
  58154. }
  58155. } else {
  58156. $this->startFileTransaction();
  58157. $dirtree = $pkg->getDirTree();
  58158. if ($dirtree === false) {
  58159. $this->configSet('default_channel', $savechannel);
  58160. return $this->_registry->deletePackage($package, $channel);
  58161. }
  58162. // attempt to delete empty directories
  58163. uksort($dirtree, array($this, '_sortDirs'));
  58164. foreach($dirtree as $dir => $notused) {
  58165. $this->addFileOperation('rmdir', array($dir));
  58166. }
  58167. if (!$this->commitFileTransaction()) {
  58168. $this->rollbackFileTransaction();
  58169. if (!isset($options['ignore-errors'])) {
  58170. return $this->raiseError("uninstall failed");
  58171. }
  58172. if (!isset($options['soft'])) {
  58173. $this->log(0, 'WARNING: uninstall failed');
  58174. }
  58175. }
  58176. }
  58177. // }}}
  58178. }
  58179. $this->configSet('default_channel', $savechannel);
  58180. // Register that the package is no longer installed
  58181. return $this->_registry->deletePackage($package, $channel);
  58182. }
  58183. /**
  58184. * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  58185. *
  58186. * It also removes duplicate dependencies
  58187. * @param array an array of PEAR_PackageFile_v[1/2] objects
  58188. * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
  58189. */
  58190. function sortPackagesForUninstall(&$packages)
  58191. {
  58192. $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config);
  58193. if (PEAR::isError($this->_dependencyDB)) {
  58194. return $this->_dependencyDB;
  58195. }
  58196. usort($packages, array(&$this, '_sortUninstall'));
  58197. }
  58198. function _sortUninstall($a, $b)
  58199. {
  58200. if (!$a->getDeps() && !$b->getDeps()) {
  58201. return 0; // neither package has dependencies, order is insignificant
  58202. }
  58203. if ($a->getDeps() && !$b->getDeps()) {
  58204. return -1; // $a must be installed after $b because $a has dependencies
  58205. }
  58206. if (!$a->getDeps() && $b->getDeps()) {
  58207. return 1; // $b must be installed after $a because $b has dependencies
  58208. }
  58209. // both packages have dependencies
  58210. if ($this->_dependencyDB->dependsOn($a, $b)) {
  58211. return -1;
  58212. }
  58213. if ($this->_dependencyDB->dependsOn($b, $a)) {
  58214. return 1;
  58215. }
  58216. return 0;
  58217. }
  58218. // }}}
  58219. // {{{ _sortDirs()
  58220. function _sortDirs($a, $b)
  58221. {
  58222. if (strnatcmp($a, $b) == -1) return 1;
  58223. if (strnatcmp($a, $b) == 1) return -1;
  58224. return 0;
  58225. }
  58226. // }}}
  58227. // {{{ _buildCallback()
  58228. function _buildCallback($what, $data)
  58229. {
  58230. if (($what == 'cmdoutput' && $this->debug > 1) ||
  58231. ($what == 'output' && $this->debug > 0)) {
  58232. $this->ui->outputData(rtrim($data), 'build');
  58233. }
  58234. }
  58235. // }}}
  58236. }
  58237. ��������������������������������������������������������������������������PEAR-1.10.10/PEAR/PackageFile.php�������������������������������������������������������������������0000644�0001750�0001750�00000036746�13565304531�015671� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  58238. /**
  58239. * PEAR_PackageFile, package.xml parsing utility class
  58240. *
  58241. * PHP versions 4 and 5
  58242. *
  58243. * @category pear
  58244. * @package PEAR
  58245. * @author Greg Beaver <cellog@php.net>
  58246. * @copyright 1997-2009 The Authors
  58247. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  58248. * @link http://pear.php.net/package/PEAR
  58249. * @since File available since Release 1.4.0a1
  58250. */
  58251. /**
  58252. * needed for PEAR_VALIDATE_* constants
  58253. */
  58254. require_once 'PEAR/Validate.php';
  58255. /**
  58256. * Error code if the package.xml <package> tag does not contain a valid version
  58257. */
  58258. define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1);
  58259. /**
  58260. * Error code if the package.xml <package> tag version is not supported (version 1.0 and 1.1 are the only supported versions,
  58261. * currently
  58262. */
  58263. define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2);
  58264. /**
  58265. * Abstraction for the package.xml package description file
  58266. *
  58267. * @category pear
  58268. * @package PEAR
  58269. * @author Greg Beaver <cellog@php.net>
  58270. * @copyright 1997-2009 The Authors
  58271. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  58272. * @version Release: 1.10.10
  58273. * @link http://pear.php.net/package/PEAR
  58274. * @since Class available since Release 1.4.0a1
  58275. */
  58276. class PEAR_PackageFile
  58277. {
  58278. /**
  58279. * @var PEAR_Config
  58280. */
  58281. var $_config;
  58282. var $_debug;
  58283. var $_logger = false;
  58284. /**
  58285. * @var boolean
  58286. */
  58287. var $_rawReturn = false;
  58288. /**
  58289. * helper for extracting Archive_Tar errors
  58290. * @var array
  58291. * @access private
  58292. */
  58293. var $_extractErrors = array();
  58294. /**
  58295. *
  58296. * @param PEAR_Config $config
  58297. * @param ? $debug
  58298. * @param string @tmpdir Optional temporary directory for uncompressing
  58299. * files
  58300. */
  58301. function __construct(&$config, $debug = false)
  58302. {
  58303. $this->_config = $config;
  58304. $this->_debug = $debug;
  58305. }
  58306. /**
  58307. * Turn off validation - return a parsed package.xml without checking it
  58308. *
  58309. * This is used by the package-validate command
  58310. */
  58311. function rawReturn()
  58312. {
  58313. $this->_rawReturn = true;
  58314. }
  58315. function setLogger(&$l)
  58316. {
  58317. $this->_logger = &$l;
  58318. }
  58319. /**
  58320. * Create a PEAR_PackageFile_Parser_v* of a given version.
  58321. * @param int $version
  58322. * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1
  58323. */
  58324. function &parserFactory($version)
  58325. {
  58326. if (!in_array($version[0], array('1', '2'))) {
  58327. $a = false;
  58328. return $a;
  58329. }
  58330. include_once 'PEAR/PackageFile/Parser/v' . $version[0] . '.php';
  58331. $version = $version[0];
  58332. $class = "PEAR_PackageFile_Parser_v$version";
  58333. $a = new $class;
  58334. return $a;
  58335. }
  58336. /**
  58337. * For simpler unit-testing
  58338. * @return string
  58339. */
  58340. function getClassPrefix()
  58341. {
  58342. return 'PEAR_PackageFile_v';
  58343. }
  58344. /**
  58345. * Create a PEAR_PackageFile_v* of a given version.
  58346. * @param int $version
  58347. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1
  58348. */
  58349. function &factory($version)
  58350. {
  58351. if (!in_array($version[0], array('1', '2'))) {
  58352. $a = false;
  58353. return $a;
  58354. }
  58355. include_once 'PEAR/PackageFile/v' . $version[0] . '.php';
  58356. $version = $version[0];
  58357. $class = $this->getClassPrefix() . $version;
  58358. $a = new $class;
  58359. return $a;
  58360. }
  58361. /**
  58362. * Create a PEAR_PackageFile_v* from its toArray() method
  58363. *
  58364. * WARNING: no validation is performed, the array is assumed to be valid,
  58365. * always parse from xml if you want validation.
  58366. * @param array $arr
  58367. * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2
  58368. * @uses factory() to construct the returned object.
  58369. */
  58370. function &fromArray($arr)
  58371. {
  58372. if (isset($arr['xsdversion'])) {
  58373. $obj = &$this->factory($arr['xsdversion']);
  58374. if ($this->_logger) {
  58375. $obj->setLogger($this->_logger);
  58376. }
  58377. $obj->setConfig($this->_config);
  58378. $obj->fromArray($arr);
  58379. return $obj;
  58380. }
  58381. if (isset($arr['package']['attribs']['version'])) {
  58382. $obj = &$this->factory($arr['package']['attribs']['version']);
  58383. } else {
  58384. $obj = &$this->factory('1.0');
  58385. }
  58386. if ($this->_logger) {
  58387. $obj->setLogger($this->_logger);
  58388. }
  58389. $obj->setConfig($this->_config);
  58390. $obj->fromArray($arr);
  58391. return $obj;
  58392. }
  58393. /**
  58394. * Create a PEAR_PackageFile_v* from an XML string.
  58395. * @access public
  58396. * @param string $data contents of package.xml file
  58397. * @param int $state package state (one of PEAR_VALIDATE_* constants)
  58398. * @param string $file full path to the package.xml file (and the files
  58399. * it references)
  58400. * @param string $archive optional name of the archive that the XML was
  58401. * extracted from, if any
  58402. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  58403. * @uses parserFactory() to construct a parser to load the package.
  58404. */
  58405. function &fromXmlString($data, $state, $file, $archive = false)
  58406. {
  58407. if (preg_match('/<package[^>]+version=[\'"]([0-9]+\.[0-9]+)[\'"]/', $data, $packageversion)) {
  58408. if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) {
  58409. return PEAR::raiseError('package.xml version "' . $packageversion[1] .
  58410. '" is not supported, only 1.0, 2.0, and 2.1 are supported.');
  58411. }
  58412. $object = &$this->parserFactory($packageversion[1]);
  58413. if ($this->_logger) {
  58414. $object->setLogger($this->_logger);
  58415. }
  58416. $object->setConfig($this->_config);
  58417. $pf = $object->parse($data, $file, $archive);
  58418. if (PEAR::isError($pf)) {
  58419. return $pf;
  58420. }
  58421. if ($this->_rawReturn) {
  58422. return $pf;
  58423. }
  58424. if (!$pf->validate($state)) {;
  58425. if ($this->_config->get('verbose') > 0
  58426. && $this->_logger && $pf->getValidationWarnings(false)
  58427. ) {
  58428. foreach ($pf->getValidationWarnings(false) as $warning) {
  58429. $this->_logger->log(0, 'ERROR: ' . $warning['message']);
  58430. }
  58431. }
  58432. $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
  58433. 2, null, null, $pf->getValidationWarnings());
  58434. return $a;
  58435. }
  58436. if ($this->_logger && $pf->getValidationWarnings(false)) {
  58437. foreach ($pf->getValidationWarnings() as $warning) {
  58438. $this->_logger->log(0, 'WARNING: ' . $warning['message']);
  58439. }
  58440. }
  58441. if (method_exists($pf, 'flattenFilelist')) {
  58442. $pf->flattenFilelist(); // for v2
  58443. }
  58444. return $pf;
  58445. } elseif (preg_match('/<package[^>]+version=[\'"]([^"\']+)[\'"]/', $data, $packageversion)) {
  58446. $a = PEAR::raiseError('package.xml file "' . $file .
  58447. '" has unsupported package.xml <package> version "' . $packageversion[1] . '"');
  58448. return $a;
  58449. } else {
  58450. if (!class_exists('PEAR_ErrorStack')) {
  58451. require_once 'PEAR/ErrorStack.php';
  58452. }
  58453. PEAR_ErrorStack::staticPush('PEAR_PackageFile',
  58454. PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION,
  58455. 'warning', array('xml' => $data), 'package.xml "' . $file .
  58456. '" has no package.xml <package> version');
  58457. $object = &$this->parserFactory('1.0');
  58458. $object->setConfig($this->_config);
  58459. $pf = $object->parse($data, $file, $archive);
  58460. if (PEAR::isError($pf)) {
  58461. return $pf;
  58462. }
  58463. if ($this->_rawReturn) {
  58464. return $pf;
  58465. }
  58466. if (!$pf->validate($state)) {
  58467. $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
  58468. 2, null, null, $pf->getValidationWarnings());
  58469. return $a;
  58470. }
  58471. if ($this->_logger && $pf->getValidationWarnings(false)) {
  58472. foreach ($pf->getValidationWarnings() as $warning) {
  58473. $this->_logger->log(0, 'WARNING: ' . $warning['message']);
  58474. }
  58475. }
  58476. if (method_exists($pf, 'flattenFilelist')) {
  58477. $pf->flattenFilelist(); // for v2
  58478. }
  58479. return $pf;
  58480. }
  58481. }
  58482. /**
  58483. * Register a temporary file or directory. When the destructor is
  58484. * executed, all registered temporary files and directories are
  58485. * removed.
  58486. *
  58487. * @param string $file name of file or directory
  58488. * @return void
  58489. */
  58490. static function addTempFile($file)
  58491. {
  58492. $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  58493. }
  58494. /**
  58495. * Create a PEAR_PackageFile_v* from a compressed Tar or Tgz file.
  58496. * @access public
  58497. * @param string contents of package.xml file
  58498. * @param int package state (one of PEAR_VALIDATE_* constants)
  58499. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  58500. * @using Archive_Tar to extract the files
  58501. * @using fromPackageFile() to load the package after the package.xml
  58502. * file is extracted.
  58503. */
  58504. function &fromTgzFile($file, $state)
  58505. {
  58506. if (!class_exists('Archive_Tar')) {
  58507. require_once 'Archive/Tar.php';
  58508. }
  58509. $tar = new Archive_Tar($file);
  58510. if ($this->_debug <= 1) {
  58511. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  58512. }
  58513. $content = $tar->listContent();
  58514. if ($this->_debug <= 1) {
  58515. $tar->popErrorHandling();
  58516. }
  58517. if (!is_array($content)) {
  58518. if (is_string($file) && strlen($file) < 255 &&
  58519. (!file_exists($file) || !@is_file($file))) {
  58520. $ret = PEAR::raiseError("could not open file \"$file\"");
  58521. return $ret;
  58522. }
  58523. $file = realpath($file);
  58524. $ret = PEAR::raiseError("Could not get contents of package \"$file\"".
  58525. '. Invalid tgz file.');
  58526. return $ret;
  58527. }
  58528. if (!count($content) && !@is_file($file)) {
  58529. $ret = PEAR::raiseError("could not open file \"$file\"");
  58530. return $ret;
  58531. }
  58532. $xml = null;
  58533. $origfile = $file;
  58534. foreach ($content as $file) {
  58535. $name = $file['filename'];
  58536. if ($name == 'package2.xml') { // allow a .tgz to distribute both versions
  58537. $xml = $name;
  58538. break;
  58539. }
  58540. if ($name == 'package.xml') {
  58541. $xml = $name;
  58542. break;
  58543. } elseif (preg_match('/package.xml$/', $name, $match)) {
  58544. $xml = $name;
  58545. break;
  58546. }
  58547. }
  58548. $tmpdir = System::mktemp('-t "' . $this->_config->get('temp_dir') . '" -d pear');
  58549. if ($tmpdir === false) {
  58550. $ret = PEAR::raiseError("there was a problem with getting the configured temp directory");
  58551. return $ret;
  58552. }
  58553. PEAR_PackageFile::addTempFile($tmpdir);
  58554. $this->_extractErrors();
  58555. PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors'));
  58556. if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
  58557. $extra = implode("\n", $this->_extractErrors());
  58558. if ($extra) {
  58559. $extra = ' ' . $extra;
  58560. }
  58561. PEAR::staticPopErrorHandling();
  58562. $ret = PEAR::raiseError('could not extract the package.xml file from "' .
  58563. $origfile . '"' . $extra);
  58564. return $ret;
  58565. }
  58566. PEAR::staticPopErrorHandling();
  58567. $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
  58568. return $ret;
  58569. }
  58570. /**
  58571. * helper callback for extracting Archive_Tar errors
  58572. *
  58573. * @param PEAR_Error|null $err
  58574. * @return array
  58575. * @access private
  58576. */
  58577. function _extractErrors($err = null)
  58578. {
  58579. static $errors = array();
  58580. if ($err === null) {
  58581. $e = $errors;
  58582. $errors = array();
  58583. return $e;
  58584. }
  58585. $errors[] = $err->getMessage();
  58586. }
  58587. /**
  58588. * Create a PEAR_PackageFile_v* from a package.xml file.
  58589. *
  58590. * @access public
  58591. * @param string $descfile name of package xml file
  58592. * @param int $state package state (one of PEAR_VALIDATE_* constants)
  58593. * @param string|false $archive name of the archive this package.xml came
  58594. * from, if any
  58595. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  58596. * @uses PEAR_PackageFile::fromXmlString to create the oject after the
  58597. * XML is loaded from the package.xml file.
  58598. */
  58599. function &fromPackageFile($descfile, $state, $archive = false)
  58600. {
  58601. $fp = false;
  58602. if (is_string($descfile) && strlen($descfile) < 255 &&
  58603. (
  58604. !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile)
  58605. || (!$fp = @fopen($descfile, 'r'))
  58606. )
  58607. ) {
  58608. $a = PEAR::raiseError("Unable to open $descfile");
  58609. return $a;
  58610. }
  58611. // read the whole thing so we only get one cdata callback
  58612. // for each block of cdata
  58613. fclose($fp);
  58614. $data = file_get_contents($descfile);
  58615. $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive);
  58616. return $ret;
  58617. }
  58618. /**
  58619. * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file.
  58620. *
  58621. * This method is able to extract information about a package from a .tgz
  58622. * archive or from a XML package definition file.
  58623. *
  58624. * @access public
  58625. * @param string $info file name
  58626. * @param int $state package state (one of PEAR_VALIDATE_* constants)
  58627. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  58628. * @uses fromPackageFile() if the file appears to be XML
  58629. * @uses fromTgzFile() to load all non-XML files
  58630. */
  58631. function &fromAnyFile($info, $state)
  58632. {
  58633. if (is_dir($info)) {
  58634. $dir_name = realpath($info);
  58635. if (file_exists($dir_name . '/package.xml')) {
  58636. $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state);
  58637. } elseif (file_exists($dir_name . '/package2.xml')) {
  58638. $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state);
  58639. } else {
  58640. $info = PEAR::raiseError("No package definition found in '$info' directory");
  58641. }
  58642. return $info;
  58643. }
  58644. $fp = false;
  58645. if (is_string($info) && strlen($info) < 255 &&
  58646. (file_exists($info) || ($fp = @fopen($info, 'r')))
  58647. ) {
  58648. if ($fp) {
  58649. fclose($fp);
  58650. }
  58651. $tmp = substr($info, -4);
  58652. if ($tmp == '.xml') {
  58653. $info = &PEAR_PackageFile::fromPackageFile($info, $state);
  58654. } elseif ($tmp == '.tar' || $tmp == '.tgz') {
  58655. $info = &PEAR_PackageFile::fromTgzFile($info, $state);
  58656. } else {
  58657. $fp = fopen($info, 'r');
  58658. $test = fread($fp, 5);
  58659. fclose($fp);
  58660. if ($test == '<?xml') {
  58661. $info = &PEAR_PackageFile::fromPackageFile($info, $state);
  58662. } else {
  58663. $info = &PEAR_PackageFile::fromTgzFile($info, $state);
  58664. }
  58665. }
  58666. return $info;
  58667. }
  58668. $info = PEAR::raiseError("Cannot open '$info' for parsing");
  58669. return $info;
  58670. }
  58671. }
  58672. ��������������������������PEAR-1.10.10/PEAR/Packager.php����������������������������������������������������������������������0000644�0001750�0001750�00000017040�13565304531�015235� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  58673. /**
  58674. * PEAR_Packager for generating releases
  58675. *
  58676. * PHP versions 4 and 5
  58677. *
  58678. * @category pear
  58679. * @package PEAR
  58680. * @author Stig Bakken <ssb@php.net>
  58681. * @author Tomas V. V. Cox <cox@idecnet.com>
  58682. * @author Greg Beaver <cellog@php.net>
  58683. * @copyright 1997-2009 The Authors
  58684. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  58685. * @link http://pear.php.net/package/PEAR
  58686. * @since File available since Release 0.1
  58687. */
  58688. /**
  58689. * base class
  58690. */
  58691. require_once 'PEAR/Common.php';
  58692. require_once 'PEAR/PackageFile.php';
  58693. require_once 'System.php';
  58694. /**
  58695. * Administration class used to make a PEAR release tarball.
  58696. *
  58697. * @category pear
  58698. * @package PEAR
  58699. * @author Greg Beaver <cellog@php.net>
  58700. * @copyright 1997-2009 The Authors
  58701. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  58702. * @version Release: 1.10.10
  58703. * @link http://pear.php.net/package/PEAR
  58704. * @since Class available since Release 0.1
  58705. */
  58706. class PEAR_Packager extends PEAR_Common
  58707. {
  58708. /**
  58709. * @var PEAR_Registry
  58710. */
  58711. var $_registry;
  58712. function package($pkgfile = null, $compress = true, $pkg2 = null)
  58713. {
  58714. // {{{ validate supplied package.xml file
  58715. if (empty($pkgfile)) {
  58716. $pkgfile = 'package.xml';
  58717. }
  58718. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  58719. $pkg = new PEAR_PackageFile($this->config, $this->debug);
  58720. $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL);
  58721. $main = &$pf;
  58722. PEAR::staticPopErrorHandling();
  58723. if (PEAR::isError($pf)) {
  58724. if (is_array($pf->getUserInfo())) {
  58725. foreach ($pf->getUserInfo() as $error) {
  58726. $this->log(0, 'Error: ' . $error['message']);
  58727. }
  58728. }
  58729. $this->log(0, $pf->getMessage());
  58730. return $this->raiseError("Cannot package, errors in package file");
  58731. }
  58732. foreach ($pf->getValidationWarnings() as $warning) {
  58733. $this->log(1, 'Warning: ' . $warning['message']);
  58734. }
  58735. // }}}
  58736. if ($pkg2) {
  58737. $this->log(0, 'Attempting to process the second package file');
  58738. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  58739. $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL);
  58740. PEAR::staticPopErrorHandling();
  58741. if (PEAR::isError($pf2)) {
  58742. if (is_array($pf2->getUserInfo())) {
  58743. foreach ($pf2->getUserInfo() as $error) {
  58744. $this->log(0, 'Error: ' . $error['message']);
  58745. }
  58746. }
  58747. $this->log(0, $pf2->getMessage());
  58748. return $this->raiseError("Cannot package, errors in second package file");
  58749. }
  58750. foreach ($pf2->getValidationWarnings() as $warning) {
  58751. $this->log(1, 'Warning: ' . $warning['message']);
  58752. }
  58753. if ($pf2->getPackagexmlVersion() == '2.0' ||
  58754. $pf2->getPackagexmlVersion() == '2.1'
  58755. ) {
  58756. $main = &$pf2;
  58757. $other = &$pf;
  58758. } else {
  58759. $main = &$pf;
  58760. $other = &$pf2;
  58761. }
  58762. if ($main->getPackagexmlVersion() != '2.0' &&
  58763. $main->getPackagexmlVersion() != '2.1') {
  58764. return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' .
  58765. 'only package together a package.xml 1.0 and package.xml 2.0');
  58766. }
  58767. if ($other->getPackagexmlVersion() != '1.0') {
  58768. return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' .
  58769. 'only package together a package.xml 1.0 and package.xml 2.0');
  58770. }
  58771. }
  58772. $main->setLogger($this);
  58773. if (!$main->validate(PEAR_VALIDATE_PACKAGING)) {
  58774. foreach ($main->getValidationWarnings() as $warning) {
  58775. $this->log(0, 'Error: ' . $warning['message']);
  58776. }
  58777. return $this->raiseError("Cannot package, errors in package");
  58778. }
  58779. foreach ($main->getValidationWarnings() as $warning) {
  58780. $this->log(1, 'Warning: ' . $warning['message']);
  58781. }
  58782. if ($pkg2) {
  58783. $other->setLogger($this);
  58784. $a = false;
  58785. if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) {
  58786. foreach ($other->getValidationWarnings() as $warning) {
  58787. $this->log(0, 'Error: ' . $warning['message']);
  58788. }
  58789. foreach ($main->getValidationWarnings() as $warning) {
  58790. $this->log(0, 'Error: ' . $warning['message']);
  58791. }
  58792. if ($a) {
  58793. return $this->raiseError('The two package.xml files are not equivalent!');
  58794. }
  58795. return $this->raiseError("Cannot package, errors in package");
  58796. }
  58797. foreach ($other->getValidationWarnings() as $warning) {
  58798. $this->log(1, 'Warning: ' . $warning['message']);
  58799. }
  58800. $gen = &$main->getDefaultGenerator();
  58801. $tgzfile = $gen->toTgz2($this, $other, $compress);
  58802. if (PEAR::isError($tgzfile)) {
  58803. return $tgzfile;
  58804. }
  58805. $dest_package = basename($tgzfile);
  58806. $pkgdir = dirname($pkgfile);
  58807. // TAR the Package -------------------------------------------
  58808. $this->log(1, "Package $dest_package done");
  58809. if (file_exists("$pkgdir/CVS/Root")) {
  58810. $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion());
  58811. $cvstag = "RELEASE_$cvsversion";
  58812. $this->log(1, 'Tag the released code with "pear cvstag ' .
  58813. $main->getPackageFile() . '"');
  58814. $this->log(1, "(or set the CVS tag $cvstag by hand)");
  58815. } elseif (file_exists("$pkgdir/.svn")) {
  58816. $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion());
  58817. $svntag = $pf->getName() . "-$svnversion";
  58818. $this->log(1, 'Tag the released code with "pear svntag ' .
  58819. $main->getPackageFile() . '"');
  58820. $this->log(1, "(or set the SVN tag $svntag by hand)");
  58821. }
  58822. } else { // this branch is executed for single packagefile packaging
  58823. $gen = &$pf->getDefaultGenerator();
  58824. $tgzfile = $gen->toTgz($this, $compress);
  58825. if (PEAR::isError($tgzfile)) {
  58826. $this->log(0, $tgzfile->getMessage());
  58827. return $this->raiseError("Cannot package, errors in package");
  58828. }
  58829. $dest_package = basename($tgzfile);
  58830. $pkgdir = dirname($pkgfile);
  58831. // TAR the Package -------------------------------------------
  58832. $this->log(1, "Package $dest_package done");
  58833. if (file_exists("$pkgdir/CVS/Root")) {
  58834. $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion());
  58835. $cvstag = "RELEASE_$cvsversion";
  58836. $this->log(1, "Tag the released code with `pear cvstag $pkgfile'");
  58837. $this->log(1, "(or set the CVS tag $cvstag by hand)");
  58838. } elseif (file_exists("$pkgdir/.svn")) {
  58839. $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion());
  58840. $svntag = $pf->getName() . "-$svnversion";
  58841. $this->log(1, "Tag the released code with `pear svntag $pkgfile'");
  58842. $this->log(1, "(or set the SVN tag $svntag by hand)");
  58843. }
  58844. }
  58845. return $dest_package;
  58846. }
  58847. }������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Proxy.php�������������������������������������������������������������������������0000644�0001750�0001750�00000013022�13565304531�014635� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  58848. /**
  58849. * PEAR_Proxy
  58850. *
  58851. * HTTP Proxy handling
  58852. *
  58853. * @category pear
  58854. * @package PEAR
  58855. * @author Nico Boehr
  58856. * @copyright 1997-2009 The Authors
  58857. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  58858. * @link http://pear.php.net/package/PEAR
  58859. */
  58860. class PEAR_Proxy
  58861. {
  58862. var $config = null;
  58863. /**
  58864. * @access private
  58865. */
  58866. var $proxy_host;
  58867. /**
  58868. * @access private
  58869. */
  58870. var $proxy_port;
  58871. /**
  58872. * @access private
  58873. */
  58874. var $proxy_user;
  58875. /**
  58876. * @access private
  58877. */
  58878. var $proxy_pass;
  58879. /**
  58880. * @access private
  58881. */
  58882. var $proxy_schema;
  58883. function __construct($config = null)
  58884. {
  58885. $this->config = $config;
  58886. $this->_parseProxyInfo();
  58887. }
  58888. /**
  58889. * @access private
  58890. */
  58891. function _parseProxyInfo()
  58892. {
  58893. $this->proxy_host = $this->proxy_port = $this->proxy_user = $this->proxy_pass = '';
  58894. if ($this->config->get('http_proxy')&&
  58895. $proxy = parse_url($this->config->get('http_proxy'))
  58896. ) {
  58897. $this->proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
  58898. $this->proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
  58899. $this->proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
  58900. $this->proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
  58901. $this->proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http';
  58902. }
  58903. }
  58904. /**
  58905. * @access private
  58906. */
  58907. function _httpConnect($fp, $host, $port)
  58908. {
  58909. fwrite($fp, "CONNECT $host:$port HTTP/1.1\r\n");
  58910. fwrite($fp, "Host: $host:$port\r\n");
  58911. if ($this->getProxyAuth()) {
  58912. fwrite($fp, 'Proxy-Authorization: Basic ' . $this->getProxyAuth() . "\r\n");
  58913. }
  58914. fwrite($fp, "\r\n");
  58915. while ($line = trim(fgets($fp, 1024))) {
  58916. if (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  58917. $code = (int)$matches[1];
  58918. /* as per RFC 2817 */
  58919. if ($code < 200 || $code >= 300) {
  58920. return PEAR::raiseError("Establishing a CONNECT tunnel through proxy failed with response code $code");
  58921. }
  58922. }
  58923. }
  58924. // connection was successful -- establish SSL through
  58925. // the tunnel
  58926. $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
  58927. if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
  58928. $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
  58929. $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
  58930. }
  58931. // set the correct hostname for working hostname
  58932. // verification
  58933. stream_context_set_option($fp, 'ssl', 'peer_name', $host);
  58934. // blocking socket needed for
  58935. // stream_socket_enable_crypto()
  58936. // see
  58937. // <http://php.net/manual/en/function.stream-socket-enable-crypto.php>
  58938. stream_set_blocking ($fp, true);
  58939. $crypto_res = stream_socket_enable_crypto($fp, true, $crypto_method);
  58940. if (!$crypto_res) {
  58941. return PEAR::raiseError("Could not establish SSL connection through proxy $proxy_host:$proxy_port: $crypto_res");
  58942. }
  58943. return true;
  58944. }
  58945. /**
  58946. * get the authorization information for the proxy, encoded to be
  58947. * passed in the Proxy-Authentication HTTP header.
  58948. * @return null|string the encoded authentication information if a
  58949. * proxy and authentication is configured, null
  58950. * otherwise.
  58951. */
  58952. function getProxyAuth()
  58953. {
  58954. if ($this->isProxyConfigured() && $this->proxy_user != '') {
  58955. return base64_encode($this->proxy_user . ':' . $this->proxy_pass);
  58956. }
  58957. return null;
  58958. }
  58959. function getProxyUser()
  58960. {
  58961. return $this->proxy_user;
  58962. }
  58963. /**
  58964. * Check if we are configured to use a proxy.
  58965. *
  58966. * @return boolean true if we are configured to use a proxy, false
  58967. * otherwise.
  58968. * @access public
  58969. */
  58970. function isProxyConfigured()
  58971. {
  58972. return $this->proxy_host != '';
  58973. }
  58974. /**
  58975. * Open a socket to a remote server, possibly involving a HTTP
  58976. * proxy.
  58977. *
  58978. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  58979. * setting), the proxy will be used.
  58980. *
  58981. * @param string $host the host to connect to
  58982. * @param string $port the port to connect to
  58983. * @param boolean $secure if true, establish a secure connection
  58984. * using TLS.
  58985. * @access public
  58986. */
  58987. function openSocket($host, $port, $secure = false)
  58988. {
  58989. if ($this->isProxyConfigured()) {
  58990. $fp = @fsockopen(
  58991. $this->proxy_host, $this->proxy_port,
  58992. $errno, $errstr, 15
  58993. );
  58994. if (!$fp) {
  58995. return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276);
  58996. }
  58997. /* HTTPS is to be used and we have a proxy, use CONNECT verb */
  58998. if ($secure) {
  58999. $res = $this->_httpConnect($fp, $host, $port);
  59000. if (PEAR::isError($res)) {
  59001. return $res;
  59002. }
  59003. }
  59004. } else {
  59005. if ($secure) {
  59006. $host = 'ssl://' . $host;
  59007. }
  59008. $fp = @fsockopen($host, $port, $errno, $errstr);
  59009. if (!$fp) {
  59010. return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
  59011. }
  59012. }
  59013. return $fp;
  59014. }
  59015. }
  59016. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Registry.php����������������������������������������������������������������������0000644�0001750�0001750�00000223730�13565304531�015335� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  59017. /**
  59018. * PEAR_Registry
  59019. *
  59020. * PHP versions 4 and 5
  59021. *
  59022. * @category pear
  59023. * @package PEAR
  59024. * @author Stig Bakken <ssb@php.net>
  59025. * @author Tomas V. V. Cox <cox@idecnet.com>
  59026. * @author Greg Beaver <cellog@php.net>
  59027. * @copyright 1997-2009 The Authors
  59028. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  59029. * @link http://pear.php.net/package/PEAR
  59030. * @since File available since Release 0.1
  59031. */
  59032. /**
  59033. * for PEAR_Error
  59034. */
  59035. require_once 'PEAR.php';
  59036. require_once 'PEAR/DependencyDB.php';
  59037. define('PEAR_REGISTRY_ERROR_LOCK', -2);
  59038. define('PEAR_REGISTRY_ERROR_FORMAT', -3);
  59039. define('PEAR_REGISTRY_ERROR_FILE', -4);
  59040. define('PEAR_REGISTRY_ERROR_CONFLICT', -5);
  59041. define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6);
  59042. /**
  59043. * Administration class used to maintain the installed package database.
  59044. * @category pear
  59045. * @package PEAR
  59046. * @author Stig Bakken <ssb@php.net>
  59047. * @author Tomas V. V. Cox <cox@idecnet.com>
  59048. * @author Greg Beaver <cellog@php.net>
  59049. * @copyright 1997-2009 The Authors
  59050. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  59051. * @version Release: 1.10.10
  59052. * @link http://pear.php.net/package/PEAR
  59053. * @since Class available since Release 1.4.0a1
  59054. */
  59055. class PEAR_Registry extends PEAR
  59056. {
  59057. /**
  59058. * File containing all channel information.
  59059. * @var string
  59060. */
  59061. var $channels = '';
  59062. /** Directory where registry files are stored.
  59063. * @var string
  59064. */
  59065. var $statedir = '';
  59066. /** File where the file map is stored
  59067. * @var string
  59068. */
  59069. var $filemap = '';
  59070. /** Directory where registry files for channels are stored.
  59071. * @var string
  59072. */
  59073. var $channelsdir = '';
  59074. /** Name of file used for locking the registry
  59075. * @var string
  59076. */
  59077. var $lockfile = '';
  59078. /** File descriptor used during locking
  59079. * @var resource
  59080. */
  59081. var $lock_fp = null;
  59082. /** Mode used during locking
  59083. * @var int
  59084. */
  59085. var $lock_mode = 0; // XXX UNUSED
  59086. /** Cache of package information. Structure:
  59087. * array(
  59088. * 'package' => array('id' => ... ),
  59089. * ... )
  59090. * @var array
  59091. */
  59092. var $pkginfo_cache = array();
  59093. /** Cache of file map. Structure:
  59094. * array( '/path/to/file' => 'package', ... )
  59095. * @var array
  59096. */
  59097. var $filemap_cache = array();
  59098. /**
  59099. * @var false|PEAR_ChannelFile
  59100. */
  59101. var $_pearChannel;
  59102. /**
  59103. * @var false|PEAR_ChannelFile
  59104. */
  59105. var $_peclChannel;
  59106. /**
  59107. * @var false|PEAR_ChannelFile
  59108. */
  59109. var $_docChannel;
  59110. /**
  59111. * @var PEAR_DependencyDB
  59112. */
  59113. var $_dependencyDB;
  59114. /**
  59115. * @var PEAR_Config
  59116. */
  59117. var $_config;
  59118. /**
  59119. * PEAR_Registry constructor.
  59120. *
  59121. * @param string (optional) PEAR install directory (for .php files)
  59122. * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if
  59123. * default values are not desired. Only used the very first time a PEAR
  59124. * repository is initialized
  59125. * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if
  59126. * default values are not desired. Only used the very first time a PEAR
  59127. * repository is initialized
  59128. *
  59129. * @access public
  59130. */
  59131. function __construct($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,
  59132. $pecl_channel = false, $pear_metadata_dir = '')
  59133. {
  59134. parent::__construct();
  59135. $this->setInstallDir($pear_install_dir, $pear_metadata_dir);
  59136. $this->_pearChannel = $pear_channel;
  59137. $this->_peclChannel = $pecl_channel;
  59138. $this->_config = false;
  59139. }
  59140. function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR, $pear_metadata_dir = '')
  59141. {
  59142. $ds = DIRECTORY_SEPARATOR;
  59143. $this->install_dir = $pear_install_dir;
  59144. if (!$pear_metadata_dir) {
  59145. $pear_metadata_dir = $pear_install_dir;
  59146. }
  59147. $this->channelsdir = $pear_metadata_dir.$ds.'.channels';
  59148. $this->statedir = $pear_metadata_dir.$ds.'.registry';
  59149. $this->filemap = $pear_metadata_dir.$ds.'.filemap';
  59150. $this->lockfile = $pear_metadata_dir.$ds.'.lock';
  59151. }
  59152. function hasWriteAccess()
  59153. {
  59154. if (!file_exists($this->install_dir)) {
  59155. $dir = $this->install_dir;
  59156. while ($dir && $dir != '.') {
  59157. $olddir = $dir;
  59158. $dir = dirname($dir);
  59159. if ($dir != '.' && file_exists($dir)) {
  59160. if (is_writeable($dir)) {
  59161. return true;
  59162. }
  59163. return false;
  59164. }
  59165. if ($dir == $olddir) { // this can happen in safe mode
  59166. return @is_writable($dir);
  59167. }
  59168. }
  59169. return false;
  59170. }
  59171. return is_writeable($this->install_dir);
  59172. }
  59173. function setConfig(&$config, $resetInstallDir = true)
  59174. {
  59175. $this->_config = &$config;
  59176. if ($resetInstallDir) {
  59177. $this->setInstallDir($config->get('php_dir'), $config->get('metadata_dir'));
  59178. }
  59179. }
  59180. function _initializeChannelDirs()
  59181. {
  59182. static $running = false;
  59183. if (!$running) {
  59184. $running = true;
  59185. $ds = DIRECTORY_SEPARATOR;
  59186. if (!is_dir($this->channelsdir) ||
  59187. !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
  59188. !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
  59189. !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
  59190. !file_exists($this->channelsdir . $ds . '__uri.reg')) {
  59191. if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
  59192. $pear_channel = $this->_pearChannel;
  59193. if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) {
  59194. if (!class_exists('PEAR_ChannelFile')) {
  59195. require_once 'PEAR/ChannelFile.php';
  59196. }
  59197. $pear_channel = new PEAR_ChannelFile;
  59198. $pear_channel->setAlias('pear');
  59199. $pear_channel->setServer('pear.php.net');
  59200. $pear_channel->setSummary('PHP Extension and Application Repository');
  59201. $pear_channel->setDefaultPEARProtocols();
  59202. $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
  59203. $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
  59204. $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
  59205. //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/');
  59206. } else {
  59207. $pear_channel->setServer('pear.php.net');
  59208. $pear_channel->setAlias('pear');
  59209. }
  59210. $pear_channel->validate();
  59211. $this->_addChannel($pear_channel);
  59212. }
  59213. if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) {
  59214. $pecl_channel = $this->_peclChannel;
  59215. if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) {
  59216. if (!class_exists('PEAR_ChannelFile')) {
  59217. require_once 'PEAR/ChannelFile.php';
  59218. }
  59219. $pecl_channel = new PEAR_ChannelFile;
  59220. $pecl_channel->setAlias('pecl');
  59221. $pecl_channel->setServer('pecl.php.net');
  59222. $pecl_channel->setSummary('PHP Extension Community Library');
  59223. $pecl_channel->setDefaultPEARProtocols();
  59224. $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
  59225. $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
  59226. $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
  59227. } else {
  59228. $pecl_channel->setServer('pecl.php.net');
  59229. $pecl_channel->setAlias('pecl');
  59230. }
  59231. $pecl_channel->validate();
  59232. $this->_addChannel($pecl_channel);
  59233. }
  59234. if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) {
  59235. $doc_channel = $this->_docChannel;
  59236. if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) {
  59237. if (!class_exists('PEAR_ChannelFile')) {
  59238. require_once 'PEAR/ChannelFile.php';
  59239. }
  59240. $doc_channel = new PEAR_ChannelFile;
  59241. $doc_channel->setAlias('phpdocs');
  59242. $doc_channel->setServer('doc.php.net');
  59243. $doc_channel->setSummary('PHP Documentation Team');
  59244. $doc_channel->setDefaultPEARProtocols();
  59245. $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
  59246. $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
  59247. $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
  59248. } else {
  59249. $doc_channel->setServer('doc.php.net');
  59250. $doc_channel->setAlias('doc');
  59251. }
  59252. $doc_channel->validate();
  59253. $this->_addChannel($doc_channel);
  59254. }
  59255. if (!file_exists($this->channelsdir . $ds . '__uri.reg')) {
  59256. if (!class_exists('PEAR_ChannelFile')) {
  59257. require_once 'PEAR/ChannelFile.php';
  59258. }
  59259. $private = new PEAR_ChannelFile;
  59260. $private->setName('__uri');
  59261. $private->setDefaultPEARProtocols();
  59262. $private->setBaseURL('REST1.0', '****');
  59263. $private->setSummary('Pseudo-channel for static packages');
  59264. $this->_addChannel($private);
  59265. }
  59266. $this->_rebuildFileMap();
  59267. }
  59268. $running = false;
  59269. }
  59270. }
  59271. function _initializeDirs()
  59272. {
  59273. $ds = DIRECTORY_SEPARATOR;
  59274. // XXX Compatibility code should be removed in the future
  59275. // rename all registry files if any to lowercase
  59276. if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) &&
  59277. $handle = opendir($this->statedir)) {
  59278. $dest = $this->statedir . $ds;
  59279. while (false !== ($file = readdir($handle))) {
  59280. if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) {
  59281. rename($dest . $file, $dest . strtolower($file));
  59282. }
  59283. }
  59284. closedir($handle);
  59285. }
  59286. $this->_initializeChannelDirs();
  59287. if (!file_exists($this->filemap)) {
  59288. $this->_rebuildFileMap();
  59289. }
  59290. $this->_initializeDepDB();
  59291. }
  59292. function _initializeDepDB()
  59293. {
  59294. if (!isset($this->_dependencyDB)) {
  59295. static $initializing = false;
  59296. if (!$initializing) {
  59297. $initializing = true;
  59298. if (!$this->_config) { // never used?
  59299. $file = OS_WINDOWS ? 'pear.ini' : '.pearrc';
  59300. $this->_config = new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .
  59301. $file);
  59302. $this->_config->setRegistry($this);
  59303. $this->_config->set('php_dir', $this->install_dir);
  59304. }
  59305. $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
  59306. if (PEAR::isError($this->_dependencyDB)) {
  59307. // attempt to recover by removing the dep db
  59308. if (file_exists($this->_config->get('metadata_dir', null, 'pear.php.net') .
  59309. DIRECTORY_SEPARATOR . '.depdb')) {
  59310. @unlink($this->_config->get('metadata_dir', null, 'pear.php.net') .
  59311. DIRECTORY_SEPARATOR . '.depdb');
  59312. }
  59313. $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
  59314. if (PEAR::isError($this->_dependencyDB)) {
  59315. echo $this->_dependencyDB->getMessage();
  59316. echo 'Unrecoverable error';
  59317. exit(1);
  59318. }
  59319. }
  59320. $initializing = false;
  59321. }
  59322. }
  59323. }
  59324. /**
  59325. * PEAR_Registry destructor. Makes sure no locks are forgotten.
  59326. *
  59327. * @access private
  59328. */
  59329. function _PEAR_Registry()
  59330. {
  59331. parent::_PEAR();
  59332. if (is_resource($this->lock_fp)) {
  59333. $this->_unlock();
  59334. }
  59335. }
  59336. /**
  59337. * Make sure the directory where we keep registry files exists.
  59338. *
  59339. * @return bool TRUE if directory exists, FALSE if it could not be
  59340. * created
  59341. *
  59342. * @access private
  59343. */
  59344. function _assertStateDir($channel = false)
  59345. {
  59346. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
  59347. return $this->_assertChannelStateDir($channel);
  59348. }
  59349. static $init = false;
  59350. if (!file_exists($this->statedir)) {
  59351. if (!$this->hasWriteAccess()) {
  59352. return false;
  59353. }
  59354. require_once 'System.php';
  59355. if (!System::mkdir(array('-p', $this->statedir))) {
  59356. return $this->raiseError("could not create directory '{$this->statedir}'");
  59357. }
  59358. $init = true;
  59359. } elseif (!is_dir($this->statedir)) {
  59360. return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' .
  59361. 'it already exists and is not a directory');
  59362. }
  59363. $ds = DIRECTORY_SEPARATOR;
  59364. if (!file_exists($this->channelsdir)) {
  59365. if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
  59366. !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
  59367. !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
  59368. !file_exists($this->channelsdir . $ds . '__uri.reg')) {
  59369. $init = true;
  59370. }
  59371. } elseif (!is_dir($this->channelsdir)) {
  59372. return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' .
  59373. 'it already exists and is not a directory');
  59374. }
  59375. if ($init) {
  59376. static $running = false;
  59377. if (!$running) {
  59378. $running = true;
  59379. $this->_initializeDirs();
  59380. $running = false;
  59381. $init = false;
  59382. }
  59383. } else {
  59384. $this->_initializeDepDB();
  59385. }
  59386. return true;
  59387. }
  59388. /**
  59389. * Make sure the directory where we keep registry files exists for a non-standard channel.
  59390. *
  59391. * @param string channel name
  59392. * @return bool TRUE if directory exists, FALSE if it could not be
  59393. * created
  59394. *
  59395. * @access private
  59396. */
  59397. function _assertChannelStateDir($channel)
  59398. {
  59399. $ds = DIRECTORY_SEPARATOR;
  59400. if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
  59401. if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
  59402. $this->_initializeChannelDirs();
  59403. }
  59404. return $this->_assertStateDir($channel);
  59405. }
  59406. $channelDir = $this->_channelDirectoryName($channel);
  59407. if (!is_dir($this->channelsdir) ||
  59408. !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
  59409. $this->_initializeChannelDirs();
  59410. }
  59411. if (!file_exists($channelDir)) {
  59412. if (!$this->hasWriteAccess()) {
  59413. return false;
  59414. }
  59415. require_once 'System.php';
  59416. if (!System::mkdir(array('-p', $channelDir))) {
  59417. return $this->raiseError("could not create directory '" . $channelDir .
  59418. "'");
  59419. }
  59420. } elseif (!is_dir($channelDir)) {
  59421. return $this->raiseError("could not create directory '" . $channelDir .
  59422. "', already exists and is not a directory");
  59423. }
  59424. return true;
  59425. }
  59426. /**
  59427. * Make sure the directory where we keep registry files for channels exists
  59428. *
  59429. * @return bool TRUE if directory exists, FALSE if it could not be
  59430. * created
  59431. *
  59432. * @access private
  59433. */
  59434. function _assertChannelDir()
  59435. {
  59436. if (!file_exists($this->channelsdir)) {
  59437. if (!$this->hasWriteAccess()) {
  59438. return false;
  59439. }
  59440. require_once 'System.php';
  59441. if (!System::mkdir(array('-p', $this->channelsdir))) {
  59442. return $this->raiseError("could not create directory '{$this->channelsdir}'");
  59443. }
  59444. } elseif (!is_dir($this->channelsdir)) {
  59445. return $this->raiseError("could not create directory '{$this->channelsdir}" .
  59446. "', it already exists and is not a directory");
  59447. }
  59448. if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
  59449. if (!$this->hasWriteAccess()) {
  59450. return false;
  59451. }
  59452. require_once 'System.php';
  59453. if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {
  59454. return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
  59455. }
  59456. } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
  59457. return $this->raiseError("could not create directory '{$this->channelsdir}" .
  59458. "/.alias', it already exists and is not a directory");
  59459. }
  59460. return true;
  59461. }
  59462. /**
  59463. * Get the name of the file where data for a given package is stored.
  59464. *
  59465. * @param string channel name, or false if this is a PEAR package
  59466. * @param string package name
  59467. *
  59468. * @return string registry file name
  59469. *
  59470. * @access public
  59471. */
  59472. function _packageFileName($package, $channel = false)
  59473. {
  59474. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
  59475. return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR .
  59476. strtolower($package) . '.reg';
  59477. }
  59478. return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
  59479. }
  59480. /**
  59481. * Get the name of the file where data for a given channel is stored.
  59482. * @param string channel name
  59483. * @return string registry file name
  59484. */
  59485. function _channelFileName($channel, $noaliases = false)
  59486. {
  59487. if (!$noaliases) {
  59488. if (file_exists($this->_getChannelAliasFileName($channel))) {
  59489. $channel = implode('', file($this->_getChannelAliasFileName($channel)));
  59490. }
  59491. }
  59492. return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_',
  59493. strtolower($channel)) . '.reg';
  59494. }
  59495. /**
  59496. * @param string
  59497. * @return string
  59498. */
  59499. function _getChannelAliasFileName($alias)
  59500. {
  59501. return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .
  59502. DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';
  59503. }
  59504. /**
  59505. * Get the name of a channel from its alias
  59506. */
  59507. function _getChannelFromAlias($channel)
  59508. {
  59509. if (!$this->_channelExists($channel)) {
  59510. if ($channel == 'pear.php.net') {
  59511. return 'pear.php.net';
  59512. }
  59513. if ($channel == 'pecl.php.net') {
  59514. return 'pecl.php.net';
  59515. }
  59516. if ($channel == 'doc.php.net') {
  59517. return 'doc.php.net';
  59518. }
  59519. if ($channel == '__uri') {
  59520. return '__uri';
  59521. }
  59522. return false;
  59523. }
  59524. $channel = strtolower($channel);
  59525. if (file_exists($this->_getChannelAliasFileName($channel))) {
  59526. // translate an alias to an actual channel
  59527. return implode('', file($this->_getChannelAliasFileName($channel)));
  59528. }
  59529. return $channel;
  59530. }
  59531. /**
  59532. * Get the alias of a channel from its alias or its name
  59533. */
  59534. function _getAlias($channel)
  59535. {
  59536. if (!$this->_channelExists($channel)) {
  59537. if ($channel == 'pear.php.net') {
  59538. return 'pear';
  59539. }
  59540. if ($channel == 'pecl.php.net') {
  59541. return 'pecl';
  59542. }
  59543. if ($channel == 'doc.php.net') {
  59544. return 'phpdocs';
  59545. }
  59546. return false;
  59547. }
  59548. $channel = $this->_getChannel($channel);
  59549. if (PEAR::isError($channel)) {
  59550. return $channel;
  59551. }
  59552. return $channel->getAlias();
  59553. }
  59554. /**
  59555. * Get the name of the file where data for a given package is stored.
  59556. *
  59557. * @param string channel name, or false if this is a PEAR package
  59558. * @param string package name
  59559. *
  59560. * @return string registry file name
  59561. *
  59562. * @access public
  59563. */
  59564. function _channelDirectoryName($channel)
  59565. {
  59566. if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
  59567. return $this->statedir;
  59568. }
  59569. $ch = $this->_getChannelFromAlias($channel);
  59570. if (!$ch) {
  59571. $ch = $channel;
  59572. }
  59573. return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .
  59574. str_replace('/', '_', $ch));
  59575. }
  59576. function _openPackageFile($package, $mode, $channel = false)
  59577. {
  59578. if (!$this->_assertStateDir($channel)) {
  59579. return null;
  59580. }
  59581. if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
  59582. return null;
  59583. }
  59584. $file = $this->_packageFileName($package, $channel);
  59585. if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
  59586. return null;
  59587. }
  59588. $fp = @fopen($file, $mode);
  59589. if (!$fp) {
  59590. return null;
  59591. }
  59592. return $fp;
  59593. }
  59594. function _closePackageFile($fp)
  59595. {
  59596. fclose($fp);
  59597. }
  59598. function _openChannelFile($channel, $mode)
  59599. {
  59600. if (!$this->_assertChannelDir()) {
  59601. return null;
  59602. }
  59603. if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
  59604. return null;
  59605. }
  59606. $file = $this->_channelFileName($channel);
  59607. if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
  59608. return null;
  59609. }
  59610. $fp = @fopen($file, $mode);
  59611. if (!$fp) {
  59612. return null;
  59613. }
  59614. return $fp;
  59615. }
  59616. function _closeChannelFile($fp)
  59617. {
  59618. fclose($fp);
  59619. }
  59620. function _rebuildFileMap()
  59621. {
  59622. if (!class_exists('PEAR_Installer_Role')) {
  59623. require_once 'PEAR/Installer/Role.php';
  59624. }
  59625. $channels = $this->_listAllPackages();
  59626. $files = array();
  59627. foreach ($channels as $channel => $packages) {
  59628. foreach ($packages as $package) {
  59629. $version = $this->_packageInfo($package, 'version', $channel);
  59630. $filelist = $this->_packageInfo($package, 'filelist', $channel);
  59631. if (!is_array($filelist)) {
  59632. continue;
  59633. }
  59634. foreach ($filelist as $name => $attrs) {
  59635. if (isset($attrs['attribs'])) {
  59636. $attrs = $attrs['attribs'];
  59637. }
  59638. // it is possible for conflicting packages in different channels to
  59639. // conflict with data files/doc files
  59640. if ($name == 'dirtree') {
  59641. continue;
  59642. }
  59643. if (isset($attrs['role']) && !in_array($attrs['role'],
  59644. PEAR_Installer_Role::getInstallableRoles())) {
  59645. // these are not installed
  59646. continue;
  59647. }
  59648. if (isset($attrs['role']) && !in_array($attrs['role'],
  59649. PEAR_Installer_Role::getBaseinstallRoles())) {
  59650. $attrs['baseinstalldir'] = $package;
  59651. }
  59652. if (isset($attrs['baseinstalldir'])) {
  59653. $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  59654. } else {
  59655. $file = $name;
  59656. }
  59657. $file = preg_replace(',^/+,', '', $file);
  59658. if ($channel != 'pear.php.net') {
  59659. if (!isset($files[$attrs['role']])) {
  59660. $files[$attrs['role']] = array();
  59661. }
  59662. $files[$attrs['role']][$file] = array(strtolower($channel),
  59663. strtolower($package));
  59664. } else {
  59665. if (!isset($files[$attrs['role']])) {
  59666. $files[$attrs['role']] = array();
  59667. }
  59668. $files[$attrs['role']][$file] = strtolower($package);
  59669. }
  59670. }
  59671. }
  59672. }
  59673. $this->_assertStateDir();
  59674. if (!$this->hasWriteAccess()) {
  59675. return false;
  59676. }
  59677. $fp = @fopen($this->filemap, 'wb');
  59678. if (!$fp) {
  59679. return false;
  59680. }
  59681. $this->filemap_cache = $files;
  59682. fwrite($fp, serialize($files));
  59683. fclose($fp);
  59684. return true;
  59685. }
  59686. function _readFileMap()
  59687. {
  59688. if (!file_exists($this->filemap)) {
  59689. return array();
  59690. }
  59691. $fp = @fopen($this->filemap, 'r');
  59692. if (!$fp) {
  59693. return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
  59694. }
  59695. clearstatcache();
  59696. $fsize = filesize($this->filemap);
  59697. fclose($fp);
  59698. $data = file_get_contents($this->filemap);
  59699. $tmp = unserialize($data);
  59700. if (!$tmp && $fsize > 7) {
  59701. return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
  59702. }
  59703. $this->filemap_cache = $tmp;
  59704. return true;
  59705. }
  59706. /**
  59707. * Lock the registry.
  59708. *
  59709. * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
  59710. * See flock manual for more information.
  59711. *
  59712. * @return bool TRUE on success, FALSE if locking failed, or a
  59713. * PEAR error if some other error occurs (such as the
  59714. * lock file not being writable).
  59715. *
  59716. * @access private
  59717. */
  59718. function _lock($mode = LOCK_EX)
  59719. {
  59720. if (stristr(php_uname(), 'Windows 9')) {
  59721. return true;
  59722. }
  59723. if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
  59724. // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  59725. return true;
  59726. }
  59727. if (!$this->_assertStateDir()) {
  59728. if ($mode == LOCK_EX) {
  59729. return $this->raiseError('Registry directory is not writeable by the current user');
  59730. }
  59731. return true;
  59732. }
  59733. $open_mode = 'w';
  59734. // XXX People reported problems with LOCK_SH and 'w'
  59735. if ($mode === LOCK_SH || $mode === LOCK_UN) {
  59736. if (!file_exists($this->lockfile)) {
  59737. touch($this->lockfile);
  59738. }
  59739. $open_mode = 'r';
  59740. }
  59741. if (!is_resource($this->lock_fp)) {
  59742. $this->lock_fp = @fopen($this->lockfile, $open_mode);
  59743. }
  59744. if (!is_resource($this->lock_fp)) {
  59745. $this->lock_fp = null;
  59746. return $this->raiseError("could not create lock file" .
  59747. (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  59748. }
  59749. if (!(int)flock($this->lock_fp, $mode)) {
  59750. switch ($mode) {
  59751. case LOCK_SH: $str = 'shared'; break;
  59752. case LOCK_EX: $str = 'exclusive'; break;
  59753. case LOCK_UN: $str = 'unlock'; break;
  59754. default: $str = 'unknown'; break;
  59755. }
  59756. //is resource at this point, close it on error.
  59757. fclose($this->lock_fp);
  59758. $this->lock_fp = null;
  59759. return $this->raiseError("could not acquire $str lock ($this->lockfile)",
  59760. PEAR_REGISTRY_ERROR_LOCK);
  59761. }
  59762. return true;
  59763. }
  59764. function _unlock()
  59765. {
  59766. $ret = $this->_lock(LOCK_UN);
  59767. if (is_resource($this->lock_fp)) {
  59768. fclose($this->lock_fp);
  59769. }
  59770. $this->lock_fp = null;
  59771. return $ret;
  59772. }
  59773. function _packageExists($package, $channel = false)
  59774. {
  59775. return file_exists($this->_packageFileName($package, $channel));
  59776. }
  59777. /**
  59778. * Determine whether a channel exists in the registry
  59779. *
  59780. * @param string Channel name
  59781. * @param bool if true, then aliases will be ignored
  59782. * @return boolean
  59783. */
  59784. function _channelExists($channel, $noaliases = false)
  59785. {
  59786. $a = file_exists($this->_channelFileName($channel, $noaliases));
  59787. if (!$a && $channel == 'pear.php.net') {
  59788. return true;
  59789. }
  59790. if (!$a && $channel == 'pecl.php.net') {
  59791. return true;
  59792. }
  59793. if (!$a && $channel == 'doc.php.net') {
  59794. return true;
  59795. }
  59796. return $a;
  59797. }
  59798. /**
  59799. * Determine whether a mirror exists within the default channel in the registry
  59800. *
  59801. * @param string Channel name
  59802. * @param string Mirror name
  59803. *
  59804. * @return boolean
  59805. */
  59806. function _mirrorExists($channel, $mirror)
  59807. {
  59808. $data = $this->_channelInfo($channel);
  59809. if (!isset($data['servers']['mirror'])) {
  59810. return false;
  59811. }
  59812. foreach ($data['servers']['mirror'] as $m) {
  59813. if ($m['attribs']['host'] == $mirror) {
  59814. return true;
  59815. }
  59816. }
  59817. return false;
  59818. }
  59819. /**
  59820. * @param PEAR_ChannelFile Channel object
  59821. * @param donotuse
  59822. * @param string Last-Modified HTTP tag from remote request
  59823. * @return boolean|PEAR_Error True on creation, false if it already exists
  59824. */
  59825. function _addChannel($channel, $update = false, $lastmodified = false)
  59826. {
  59827. if (!is_a($channel, 'PEAR_ChannelFile')) {
  59828. return false;
  59829. }
  59830. if (!$channel->validate()) {
  59831. return false;
  59832. }
  59833. if (file_exists($this->_channelFileName($channel->getName()))) {
  59834. if (!$update) {
  59835. return false;
  59836. }
  59837. $checker = $this->_getChannel($channel->getName());
  59838. if (PEAR::isError($checker)) {
  59839. return $checker;
  59840. }
  59841. if ($channel->getAlias() != $checker->getAlias()) {
  59842. if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) {
  59843. @unlink($this->_getChannelAliasFileName($checker->getAlias()));
  59844. }
  59845. }
  59846. } else {
  59847. if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) {
  59848. return false;
  59849. }
  59850. }
  59851. $ret = $this->_assertChannelDir();
  59852. if (PEAR::isError($ret)) {
  59853. return $ret;
  59854. }
  59855. $ret = $this->_assertChannelStateDir($channel->getName());
  59856. if (PEAR::isError($ret)) {
  59857. return $ret;
  59858. }
  59859. if ($channel->getAlias() != $channel->getName()) {
  59860. if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&
  59861. $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {
  59862. $channel->setAlias($channel->getName());
  59863. }
  59864. if (!$this->hasWriteAccess()) {
  59865. return false;
  59866. }
  59867. $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');
  59868. if (!$fp) {
  59869. return false;
  59870. }
  59871. fwrite($fp, $channel->getName());
  59872. fclose($fp);
  59873. }
  59874. if (!$this->hasWriteAccess()) {
  59875. return false;
  59876. }
  59877. $fp = @fopen($this->_channelFileName($channel->getName()), 'wb');
  59878. if (!$fp) {
  59879. return false;
  59880. }
  59881. $info = $channel->toArray();
  59882. if ($lastmodified) {
  59883. $info['_lastmodified'] = $lastmodified;
  59884. } else {
  59885. $info['_lastmodified'] = self::getSourceDateEpoch();
  59886. }
  59887. fwrite($fp, serialize($info));
  59888. fclose($fp);
  59889. return true;
  59890. }
  59891. /**
  59892. * Deletion fails if there are any packages installed from the channel
  59893. * @param string|PEAR_ChannelFile channel name
  59894. * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
  59895. */
  59896. function _deleteChannel($channel)
  59897. {
  59898. if (!is_string($channel)) {
  59899. if (!is_a($channel, 'PEAR_ChannelFile')) {
  59900. return false;
  59901. }
  59902. if (!$channel->validate()) {
  59903. return false;
  59904. }
  59905. $channel = $channel->getName();
  59906. }
  59907. if ($this->_getChannelFromAlias($channel) == '__uri') {
  59908. return false;
  59909. }
  59910. if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
  59911. return false;
  59912. }
  59913. if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
  59914. return false;
  59915. }
  59916. if (!$this->_channelExists($channel)) {
  59917. return false;
  59918. }
  59919. if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
  59920. return false;
  59921. }
  59922. $channel = $this->_getChannelFromAlias($channel);
  59923. if ($channel == 'pear.php.net') {
  59924. return false;
  59925. }
  59926. $test = $this->_listChannelPackages($channel);
  59927. if (count($test)) {
  59928. return false;
  59929. }
  59930. $test = @rmdir($this->_channelDirectoryName($channel));
  59931. if (!$test) {
  59932. return false;
  59933. }
  59934. $file = $this->_getChannelAliasFileName($this->_getAlias($channel));
  59935. if (file_exists($file)) {
  59936. $test = @unlink($file);
  59937. if (!$test) {
  59938. return false;
  59939. }
  59940. }
  59941. $file = $this->_channelFileName($channel);
  59942. $ret = true;
  59943. if (file_exists($file)) {
  59944. $ret = @unlink($file);
  59945. }
  59946. return $ret;
  59947. }
  59948. /**
  59949. * Determine whether a channel exists in the registry
  59950. * @param string Channel Alias
  59951. * @return boolean
  59952. */
  59953. function _isChannelAlias($alias)
  59954. {
  59955. return file_exists($this->_getChannelAliasFileName($alias));
  59956. }
  59957. /**
  59958. * @param string|null
  59959. * @param string|null
  59960. * @param string|null
  59961. * @return array|null
  59962. * @access private
  59963. */
  59964. function _packageInfo($package = null, $key = null, $channel = 'pear.php.net')
  59965. {
  59966. if ($package === null) {
  59967. if ($channel === null) {
  59968. $channels = $this->_listChannels();
  59969. $ret = array();
  59970. foreach ($channels as $channel) {
  59971. $channel = strtolower($channel);
  59972. $ret[$channel] = array();
  59973. $packages = $this->_listPackages($channel);
  59974. foreach ($packages as $package) {
  59975. $ret[$channel][] = $this->_packageInfo($package, null, $channel);
  59976. }
  59977. }
  59978. return $ret;
  59979. }
  59980. $ps = $this->_listPackages($channel);
  59981. if (!count($ps)) {
  59982. return array();
  59983. }
  59984. return array_map(array(&$this, '_packageInfo'),
  59985. $ps, array_fill(0, count($ps), null),
  59986. array_fill(0, count($ps), $channel));
  59987. }
  59988. $fp = $this->_openPackageFile($package, 'r', $channel);
  59989. if ($fp === null) {
  59990. return null;
  59991. }
  59992. clearstatcache();
  59993. $this->_closePackageFile($fp);
  59994. $data = file_get_contents($this->_packageFileName($package, $channel));
  59995. $data = unserialize($data);
  59996. if ($key === null) {
  59997. return $data;
  59998. }
  59999. // compatibility for package.xml version 2.0
  60000. if (isset($data['old'][$key])) {
  60001. return $data['old'][$key];
  60002. }
  60003. if (isset($data[$key])) {
  60004. return $data[$key];
  60005. }
  60006. return null;
  60007. }
  60008. /**
  60009. * @param string Channel name
  60010. * @param bool whether to strictly retrieve info of channels, not just aliases
  60011. * @return array|null
  60012. */
  60013. function _channelInfo($channel, $noaliases = false)
  60014. {
  60015. if (!$this->_channelExists($channel, $noaliases)) {
  60016. return null;
  60017. }
  60018. $fp = $this->_openChannelFile($channel, 'r');
  60019. if ($fp === null) {
  60020. return null;
  60021. }
  60022. clearstatcache();
  60023. $this->_closeChannelFile($fp);
  60024. $data = file_get_contents($this->_channelFileName($channel));
  60025. $data = unserialize($data);
  60026. return $data;
  60027. }
  60028. function _listChannels()
  60029. {
  60030. $channellist = array();
  60031. if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) {
  60032. return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri');
  60033. }
  60034. $dp = opendir($this->channelsdir);
  60035. while ($ent = readdir($dp)) {
  60036. if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
  60037. continue;
  60038. }
  60039. if ($ent == '__uri.reg') {
  60040. $channellist[] = '__uri';
  60041. continue;
  60042. }
  60043. $channellist[] = str_replace('_', '/', substr($ent, 0, -4));
  60044. }
  60045. closedir($dp);
  60046. if (!in_array('pear.php.net', $channellist)) {
  60047. $channellist[] = 'pear.php.net';
  60048. }
  60049. if (!in_array('pecl.php.net', $channellist)) {
  60050. $channellist[] = 'pecl.php.net';
  60051. }
  60052. if (!in_array('doc.php.net', $channellist)) {
  60053. $channellist[] = 'doc.php.net';
  60054. }
  60055. if (!in_array('__uri', $channellist)) {
  60056. $channellist[] = '__uri';
  60057. }
  60058. natsort($channellist);
  60059. return $channellist;
  60060. }
  60061. function _listPackages($channel = false)
  60062. {
  60063. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
  60064. return $this->_listChannelPackages($channel);
  60065. }
  60066. if (!file_exists($this->statedir) || !is_dir($this->statedir)) {
  60067. return array();
  60068. }
  60069. $pkglist = array();
  60070. $dp = opendir($this->statedir);
  60071. if (!$dp) {
  60072. return $pkglist;
  60073. }
  60074. while ($ent = readdir($dp)) {
  60075. if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
  60076. continue;
  60077. }
  60078. $pkglist[] = substr($ent, 0, -4);
  60079. }
  60080. closedir($dp);
  60081. return $pkglist;
  60082. }
  60083. function _listChannelPackages($channel)
  60084. {
  60085. $pkglist = array();
  60086. if (!file_exists($this->_channelDirectoryName($channel)) ||
  60087. !is_dir($this->_channelDirectoryName($channel))) {
  60088. return array();
  60089. }
  60090. $dp = opendir($this->_channelDirectoryName($channel));
  60091. if (!$dp) {
  60092. return $pkglist;
  60093. }
  60094. while ($ent = readdir($dp)) {
  60095. if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
  60096. continue;
  60097. }
  60098. $pkglist[] = substr($ent, 0, -4);
  60099. }
  60100. closedir($dp);
  60101. return $pkglist;
  60102. }
  60103. function _listAllPackages()
  60104. {
  60105. $ret = array();
  60106. foreach ($this->_listChannels() as $channel) {
  60107. $ret[$channel] = $this->_listPackages($channel);
  60108. }
  60109. return $ret;
  60110. }
  60111. /**
  60112. * Add an installed package to the registry
  60113. * @param string package name
  60114. * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  60115. * @return bool success of saving
  60116. * @access private
  60117. */
  60118. function _addPackage($package, $info)
  60119. {
  60120. if ($this->_packageExists($package)) {
  60121. return false;
  60122. }
  60123. $fp = $this->_openPackageFile($package, 'wb');
  60124. if ($fp === null) {
  60125. return false;
  60126. }
  60127. $info['_lastmodified'] = self::getSourceDateEpoch();
  60128. fwrite($fp, serialize($info));
  60129. $this->_closePackageFile($fp);
  60130. if (isset($info['filelist'])) {
  60131. $this->_rebuildFileMap();
  60132. }
  60133. return true;
  60134. }
  60135. /**
  60136. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  60137. * @return bool
  60138. * @access private
  60139. */
  60140. function _addPackage2($info)
  60141. {
  60142. if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) {
  60143. return false;
  60144. }
  60145. if (!$info->validate()) {
  60146. if (class_exists('PEAR_Common')) {
  60147. $ui = PEAR_Frontend::singleton();
  60148. if ($ui) {
  60149. foreach ($info->getValidationWarnings() as $err) {
  60150. $ui->log($err['message'], true);
  60151. }
  60152. }
  60153. }
  60154. return false;
  60155. }
  60156. $channel = $info->getChannel();
  60157. $package = $info->getPackage();
  60158. $save = $info;
  60159. if ($this->_packageExists($package, $channel)) {
  60160. return false;
  60161. }
  60162. if (!$this->_channelExists($channel, true)) {
  60163. return false;
  60164. }
  60165. $info = $info->toArray(true);
  60166. if (!$info) {
  60167. return false;
  60168. }
  60169. $fp = $this->_openPackageFile($package, 'wb', $channel);
  60170. if ($fp === null) {
  60171. return false;
  60172. }
  60173. $info['_lastmodified'] = self::getSourceDateEpoch();
  60174. fwrite($fp, serialize($info));
  60175. $this->_closePackageFile($fp);
  60176. $this->_rebuildFileMap();
  60177. return true;
  60178. }
  60179. /**
  60180. * @param string Package name
  60181. * @param array parsed package.xml 1.0
  60182. * @param bool this parameter is only here for BC. Don't use it.
  60183. * @access private
  60184. */
  60185. function _updatePackage($package, $info, $merge = true)
  60186. {
  60187. $oldinfo = $this->_packageInfo($package);
  60188. if (empty($oldinfo)) {
  60189. return false;
  60190. }
  60191. $fp = $this->_openPackageFile($package, 'w');
  60192. if ($fp === null) {
  60193. return false;
  60194. }
  60195. if (is_object($info)) {
  60196. $info = $info->toArray();
  60197. }
  60198. $info['_lastmodified'] = self::getSourceDateEpoch();
  60199. $newinfo = $info;
  60200. if ($merge) {
  60201. $info = array_merge($oldinfo, $info);
  60202. } else {
  60203. $diff = $info;
  60204. }
  60205. fwrite($fp, serialize($info));
  60206. $this->_closePackageFile($fp);
  60207. if (isset($newinfo['filelist'])) {
  60208. $this->_rebuildFileMap();
  60209. }
  60210. return true;
  60211. }
  60212. /**
  60213. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  60214. * @return bool
  60215. * @access private
  60216. */
  60217. function _updatePackage2($info)
  60218. {
  60219. if (!$this->_packageExists($info->getPackage(), $info->getChannel())) {
  60220. return false;
  60221. }
  60222. $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());
  60223. if ($fp === null) {
  60224. return false;
  60225. }
  60226. $save = $info;
  60227. $info = $save->getArray(true);
  60228. $info['_lastmodified'] = self::getSourceDateEpoch();
  60229. fwrite($fp, serialize($info));
  60230. $this->_closePackageFile($fp);
  60231. $this->_rebuildFileMap();
  60232. return true;
  60233. }
  60234. /**
  60235. * @param string Package name
  60236. * @param string Channel name
  60237. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  60238. * @access private
  60239. */
  60240. function &_getPackage($package, $channel = 'pear.php.net')
  60241. {
  60242. $info = $this->_packageInfo($package, null, $channel);
  60243. if ($info === null) {
  60244. return $info;
  60245. }
  60246. $a = $this->_config;
  60247. if (!$a) {
  60248. $this->_config = new PEAR_Config;
  60249. $this->_config->set('php_dir', $this->statedir);
  60250. }
  60251. if (!class_exists('PEAR_PackageFile')) {
  60252. require_once 'PEAR/PackageFile.php';
  60253. }
  60254. $pkg = new PEAR_PackageFile($this->_config);
  60255. $pf = &$pkg->fromArray($info);
  60256. return $pf;
  60257. }
  60258. /**
  60259. * @param string channel name
  60260. * @param bool whether to strictly retrieve channel names
  60261. * @return PEAR_ChannelFile|PEAR_Error
  60262. * @access private
  60263. */
  60264. function &_getChannel($channel, $noaliases = false)
  60265. {
  60266. $ch = false;
  60267. if ($this->_channelExists($channel, $noaliases)) {
  60268. $chinfo = $this->_channelInfo($channel, $noaliases);
  60269. if ($chinfo) {
  60270. if (!class_exists('PEAR_ChannelFile')) {
  60271. require_once 'PEAR/ChannelFile.php';
  60272. }
  60273. $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo);
  60274. }
  60275. }
  60276. if ($ch) {
  60277. if ($ch->validate()) {
  60278. return $ch;
  60279. }
  60280. foreach ($ch->getErrors(true) as $err) {
  60281. $message = $err['message'] . "\n";
  60282. }
  60283. $ch = PEAR::raiseError($message);
  60284. return $ch;
  60285. }
  60286. if ($this->_getChannelFromAlias($channel) == 'pear.php.net') {
  60287. // the registry is not properly set up, so use defaults
  60288. if (!class_exists('PEAR_ChannelFile')) {
  60289. require_once 'PEAR/ChannelFile.php';
  60290. }
  60291. $pear_channel = new PEAR_ChannelFile;
  60292. $pear_channel->setServer('pear.php.net');
  60293. $pear_channel->setAlias('pear');
  60294. $pear_channel->setSummary('PHP Extension and Application Repository');
  60295. $pear_channel->setDefaultPEARProtocols();
  60296. $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
  60297. $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
  60298. $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
  60299. return $pear_channel;
  60300. }
  60301. if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
  60302. // the registry is not properly set up, so use defaults
  60303. if (!class_exists('PEAR_ChannelFile')) {
  60304. require_once 'PEAR/ChannelFile.php';
  60305. }
  60306. $pear_channel = new PEAR_ChannelFile;
  60307. $pear_channel->setServer('pecl.php.net');
  60308. $pear_channel->setAlias('pecl');
  60309. $pear_channel->setSummary('PHP Extension Community Library');
  60310. $pear_channel->setDefaultPEARProtocols();
  60311. $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
  60312. $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
  60313. $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
  60314. return $pear_channel;
  60315. }
  60316. if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
  60317. // the registry is not properly set up, so use defaults
  60318. if (!class_exists('PEAR_ChannelFile')) {
  60319. require_once 'PEAR/ChannelFile.php';
  60320. }
  60321. $doc_channel = new PEAR_ChannelFile;
  60322. $doc_channel->setServer('doc.php.net');
  60323. $doc_channel->setAlias('phpdocs');
  60324. $doc_channel->setSummary('PHP Documentation Team');
  60325. $doc_channel->setDefaultPEARProtocols();
  60326. $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
  60327. $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
  60328. $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
  60329. return $doc_channel;
  60330. }
  60331. if ($this->_getChannelFromAlias($channel) == '__uri') {
  60332. // the registry is not properly set up, so use defaults
  60333. if (!class_exists('PEAR_ChannelFile')) {
  60334. require_once 'PEAR/ChannelFile.php';
  60335. }
  60336. $private = new PEAR_ChannelFile;
  60337. $private->setName('__uri');
  60338. $private->setDefaultPEARProtocols();
  60339. $private->setBaseURL('REST1.0', '****');
  60340. $private->setSummary('Pseudo-channel for static packages');
  60341. return $private;
  60342. }
  60343. return $ch;
  60344. }
  60345. /**
  60346. * @param string Package name
  60347. * @param string Channel name
  60348. * @return bool
  60349. */
  60350. function packageExists($package, $channel = 'pear.php.net')
  60351. {
  60352. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60353. return $e;
  60354. }
  60355. $ret = $this->_packageExists($package, $channel);
  60356. $this->_unlock();
  60357. return $ret;
  60358. }
  60359. // }}}
  60360. // {{{ channelExists()
  60361. /**
  60362. * @param string channel name
  60363. * @param bool if true, then aliases will be ignored
  60364. * @return bool
  60365. */
  60366. function channelExists($channel, $noaliases = false)
  60367. {
  60368. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60369. return $e;
  60370. }
  60371. $ret = $this->_channelExists($channel, $noaliases);
  60372. $this->_unlock();
  60373. return $ret;
  60374. }
  60375. // }}}
  60376. /**
  60377. * @param string channel name mirror is in
  60378. * @param string mirror name
  60379. *
  60380. * @return bool
  60381. */
  60382. function mirrorExists($channel, $mirror)
  60383. {
  60384. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60385. return $e;
  60386. }
  60387. $ret = $this->_mirrorExists($channel, $mirror);
  60388. $this->_unlock();
  60389. return $ret;
  60390. }
  60391. // {{{ isAlias()
  60392. /**
  60393. * Determines whether the parameter is an alias of a channel
  60394. * @param string
  60395. * @return bool
  60396. */
  60397. function isAlias($alias)
  60398. {
  60399. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60400. return $e;
  60401. }
  60402. $ret = $this->_isChannelAlias($alias);
  60403. $this->_unlock();
  60404. return $ret;
  60405. }
  60406. // }}}
  60407. // {{{ packageInfo()
  60408. /**
  60409. * @param string|null
  60410. * @param string|null
  60411. * @param string
  60412. * @return array|null
  60413. */
  60414. function packageInfo($package = null, $key = null, $channel = 'pear.php.net')
  60415. {
  60416. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60417. return $e;
  60418. }
  60419. $ret = $this->_packageInfo($package, $key, $channel);
  60420. $this->_unlock();
  60421. return $ret;
  60422. }
  60423. // }}}
  60424. // {{{ channelInfo()
  60425. /**
  60426. * Retrieve a raw array of channel data.
  60427. *
  60428. * Do not use this, instead use {@link getChannel()} for normal
  60429. * operations. Array structure is undefined in this method
  60430. * @param string channel name
  60431. * @param bool whether to strictly retrieve information only on non-aliases
  60432. * @return array|null|PEAR_Error
  60433. */
  60434. function channelInfo($channel = null, $noaliases = false)
  60435. {
  60436. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60437. return $e;
  60438. }
  60439. $ret = $this->_channelInfo($channel, $noaliases);
  60440. $this->_unlock();
  60441. return $ret;
  60442. }
  60443. // }}}
  60444. /**
  60445. * @param string
  60446. */
  60447. function channelName($channel)
  60448. {
  60449. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60450. return $e;
  60451. }
  60452. $ret = $this->_getChannelFromAlias($channel);
  60453. $this->_unlock();
  60454. return $ret;
  60455. }
  60456. /**
  60457. * @param string
  60458. */
  60459. function channelAlias($channel)
  60460. {
  60461. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60462. return $e;
  60463. }
  60464. $ret = $this->_getAlias($channel);
  60465. $this->_unlock();
  60466. return $ret;
  60467. }
  60468. // {{{ listPackages()
  60469. function listPackages($channel = false)
  60470. {
  60471. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60472. return $e;
  60473. }
  60474. $ret = $this->_listPackages($channel);
  60475. $this->_unlock();
  60476. return $ret;
  60477. }
  60478. // }}}
  60479. // {{{ listAllPackages()
  60480. function listAllPackages()
  60481. {
  60482. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60483. return $e;
  60484. }
  60485. $ret = $this->_listAllPackages();
  60486. $this->_unlock();
  60487. return $ret;
  60488. }
  60489. // }}}
  60490. // {{{ listChannel()
  60491. function listChannels()
  60492. {
  60493. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60494. return $e;
  60495. }
  60496. $ret = $this->_listChannels();
  60497. $this->_unlock();
  60498. return $ret;
  60499. }
  60500. // }}}
  60501. // {{{ addPackage()
  60502. /**
  60503. * Add an installed package to the registry
  60504. * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object
  60505. * that will be passed to {@link addPackage2()}
  60506. * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  60507. * @return bool success of saving
  60508. */
  60509. function addPackage($package, $info)
  60510. {
  60511. if (is_object($info)) {
  60512. return $this->addPackage2($info);
  60513. }
  60514. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60515. return $e;
  60516. }
  60517. $ret = $this->_addPackage($package, $info);
  60518. $this->_unlock();
  60519. if ($ret) {
  60520. if (!class_exists('PEAR_PackageFile_v1')) {
  60521. require_once 'PEAR/PackageFile/v1.php';
  60522. }
  60523. $pf = new PEAR_PackageFile_v1;
  60524. $pf->setConfig($this->_config);
  60525. $pf->fromArray($info);
  60526. $this->_dependencyDB->uninstallPackage($pf);
  60527. $this->_dependencyDB->installPackage($pf);
  60528. }
  60529. return $ret;
  60530. }
  60531. // }}}
  60532. // {{{ addPackage2()
  60533. function addPackage2($info)
  60534. {
  60535. if (!is_object($info)) {
  60536. return $this->addPackage($info['package'], $info);
  60537. }
  60538. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60539. return $e;
  60540. }
  60541. $ret = $this->_addPackage2($info);
  60542. $this->_unlock();
  60543. if ($ret) {
  60544. $this->_dependencyDB->uninstallPackage($info);
  60545. $this->_dependencyDB->installPackage($info);
  60546. }
  60547. return $ret;
  60548. }
  60549. // }}}
  60550. // {{{ updateChannel()
  60551. /**
  60552. * For future expandibility purposes, separate this
  60553. * @param PEAR_ChannelFile
  60554. */
  60555. function updateChannel($channel, $lastmodified = null)
  60556. {
  60557. if ($channel->getName() == '__uri') {
  60558. return false;
  60559. }
  60560. return $this->addChannel($channel, $lastmodified, true);
  60561. }
  60562. // }}}
  60563. // {{{ deleteChannel()
  60564. /**
  60565. * Deletion fails if there are any packages installed from the channel
  60566. * @param string|PEAR_ChannelFile channel name
  60567. * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
  60568. */
  60569. function deleteChannel($channel)
  60570. {
  60571. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60572. return $e;
  60573. }
  60574. $ret = $this->_deleteChannel($channel);
  60575. $this->_unlock();
  60576. if ($ret && is_a($this->_config, 'PEAR_Config')) {
  60577. $this->_config->setChannels($this->listChannels());
  60578. }
  60579. return $ret;
  60580. }
  60581. // }}}
  60582. // {{{ addChannel()
  60583. /**
  60584. * @param PEAR_ChannelFile Channel object
  60585. * @param string Last-Modified header from HTTP for caching
  60586. * @return boolean|PEAR_Error True on creation, false if it already exists
  60587. */
  60588. function addChannel($channel, $lastmodified = false, $update = false)
  60589. {
  60590. if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) {
  60591. return false;
  60592. }
  60593. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60594. return $e;
  60595. }
  60596. $ret = $this->_addChannel($channel, $update, $lastmodified);
  60597. $this->_unlock();
  60598. if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) {
  60599. $this->_config->setChannels($this->listChannels());
  60600. }
  60601. return $ret;
  60602. }
  60603. // }}}
  60604. // {{{ deletePackage()
  60605. function deletePackage($package, $channel = 'pear.php.net')
  60606. {
  60607. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60608. return $e;
  60609. }
  60610. $file = $this->_packageFileName($package, $channel);
  60611. $ret = file_exists($file) ? @unlink($file) : false;
  60612. $this->_rebuildFileMap();
  60613. $this->_unlock();
  60614. $p = array('channel' => $channel, 'package' => $package);
  60615. $this->_dependencyDB->uninstallPackage($p);
  60616. return $ret;
  60617. }
  60618. // }}}
  60619. // {{{ updatePackage()
  60620. function updatePackage($package, $info, $merge = true)
  60621. {
  60622. if (is_object($info)) {
  60623. return $this->updatePackage2($info, $merge);
  60624. }
  60625. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60626. return $e;
  60627. }
  60628. $ret = $this->_updatePackage($package, $info, $merge);
  60629. $this->_unlock();
  60630. if ($ret) {
  60631. if (!class_exists('PEAR_PackageFile_v1')) {
  60632. require_once 'PEAR/PackageFile/v1.php';
  60633. }
  60634. $pf = new PEAR_PackageFile_v1;
  60635. $pf->setConfig($this->_config);
  60636. $pf->fromArray($this->packageInfo($package));
  60637. $this->_dependencyDB->uninstallPackage($pf);
  60638. $this->_dependencyDB->installPackage($pf);
  60639. }
  60640. return $ret;
  60641. }
  60642. // }}}
  60643. // {{{ updatePackage2()
  60644. function updatePackage2($info)
  60645. {
  60646. if (!is_object($info)) {
  60647. return $this->updatePackage($info['package'], $info, $merge);
  60648. }
  60649. if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {
  60650. return false;
  60651. }
  60652. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  60653. return $e;
  60654. }
  60655. $ret = $this->_updatePackage2($info);
  60656. $this->_unlock();
  60657. if ($ret) {
  60658. $this->_dependencyDB->uninstallPackage($info);
  60659. $this->_dependencyDB->installPackage($info);
  60660. }
  60661. return $ret;
  60662. }
  60663. // }}}
  60664. // {{{ getChannel()
  60665. /**
  60666. * @param string channel name
  60667. * @param bool whether to strictly return raw channels (no aliases)
  60668. * @return PEAR_ChannelFile|PEAR_Error
  60669. */
  60670. function getChannel($channel, $noaliases = false)
  60671. {
  60672. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60673. return $e;
  60674. }
  60675. $ret = $this->_getChannel($channel, $noaliases);
  60676. $this->_unlock();
  60677. if (!$ret) {
  60678. return PEAR::raiseError('Unknown channel: ' . $channel);
  60679. }
  60680. return $ret;
  60681. }
  60682. // }}}
  60683. // {{{ getPackage()
  60684. /**
  60685. * @param string package name
  60686. * @param string channel name
  60687. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  60688. */
  60689. function &getPackage($package, $channel = 'pear.php.net')
  60690. {
  60691. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60692. return $e;
  60693. }
  60694. $pf = &$this->_getPackage($package, $channel);
  60695. $this->_unlock();
  60696. return $pf;
  60697. }
  60698. // }}}
  60699. /**
  60700. * Get PEAR_PackageFile_v[1/2] objects representing the contents of
  60701. * a dependency group that are installed.
  60702. *
  60703. * This is used at uninstall-time
  60704. * @param array
  60705. * @return array|false
  60706. */
  60707. function getInstalledGroup($group)
  60708. {
  60709. $ret = array();
  60710. if (isset($group['package'])) {
  60711. if (!isset($group['package'][0])) {
  60712. $group['package'] = array($group['package']);
  60713. }
  60714. foreach ($group['package'] as $package) {
  60715. $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
  60716. $p = &$this->getPackage($package['name'], $depchannel);
  60717. if ($p) {
  60718. $save = &$p;
  60719. $ret[] = &$save;
  60720. }
  60721. }
  60722. }
  60723. if (isset($group['subpackage'])) {
  60724. if (!isset($group['subpackage'][0])) {
  60725. $group['subpackage'] = array($group['subpackage']);
  60726. }
  60727. foreach ($group['subpackage'] as $package) {
  60728. $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
  60729. $p = &$this->getPackage($package['name'], $depchannel);
  60730. if ($p) {
  60731. $save = &$p;
  60732. $ret[] = &$save;
  60733. }
  60734. }
  60735. }
  60736. if (!count($ret)) {
  60737. return false;
  60738. }
  60739. return $ret;
  60740. }
  60741. // {{{ getChannelValidator()
  60742. /**
  60743. * @param string channel name
  60744. * @return PEAR_Validate|false
  60745. */
  60746. function &getChannelValidator($channel)
  60747. {
  60748. $chan = $this->getChannel($channel);
  60749. if (PEAR::isError($chan)) {
  60750. return $chan;
  60751. }
  60752. $val = $chan->getValidationObject();
  60753. return $val;
  60754. }
  60755. // }}}
  60756. // {{{ getChannels()
  60757. /**
  60758. * @param string channel name
  60759. * @return array an array of PEAR_ChannelFile objects representing every installed channel
  60760. */
  60761. function &getChannels()
  60762. {
  60763. $ret = array();
  60764. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60765. return $e;
  60766. }
  60767. foreach ($this->_listChannels() as $channel) {
  60768. $e = &$this->_getChannel($channel);
  60769. if (!$e || PEAR::isError($e)) {
  60770. continue;
  60771. }
  60772. $ret[] = $e;
  60773. }
  60774. $this->_unlock();
  60775. return $ret;
  60776. }
  60777. // }}}
  60778. // {{{ checkFileMap()
  60779. /**
  60780. * Test whether a file or set of files belongs to a package.
  60781. *
  60782. * If an array is passed in
  60783. * @param string|array file path, absolute or relative to the pear
  60784. * install dir
  60785. * @param string|array name of PEAR package or array('package' => name, 'channel' =>
  60786. * channel) of a package that will be ignored
  60787. * @param string API version - 1.1 will exclude any files belonging to a package
  60788. * @param array private recursion variable
  60789. * @return array|false which package and channel the file belongs to, or an empty
  60790. * string if the file does not belong to an installed package,
  60791. * or belongs to the second parameter's package
  60792. */
  60793. function checkFileMap($path, $package = false, $api = '1.0', $attrs = false)
  60794. {
  60795. if (is_array($path)) {
  60796. static $notempty;
  60797. if (empty($notempty)) {
  60798. if (!class_exists('PEAR_Installer_Role')) {
  60799. require_once 'PEAR/Installer/Role.php';
  60800. }
  60801. $notempty = function($a) { return !empty($a); };
  60802. }
  60803. $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1]))
  60804. : strtolower($package);
  60805. $pkgs = array();
  60806. foreach ($path as $name => $attrs) {
  60807. if (is_array($attrs)) {
  60808. if (isset($attrs['install-as'])) {
  60809. $name = $attrs['install-as'];
  60810. }
  60811. if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) {
  60812. // these are not installed
  60813. continue;
  60814. }
  60815. if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) {
  60816. $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;
  60817. }
  60818. if (isset($attrs['baseinstalldir'])) {
  60819. $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
  60820. }
  60821. }
  60822. $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);
  60823. if (PEAR::isError($pkgs[$name])) {
  60824. return $pkgs[$name];
  60825. }
  60826. }
  60827. return array_filter($pkgs, $notempty);
  60828. }
  60829. if (empty($this->filemap_cache)) {
  60830. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  60831. return $e;
  60832. }
  60833. $err = $this->_readFileMap();
  60834. $this->_unlock();
  60835. if (PEAR::isError($err)) {
  60836. return $err;
  60837. }
  60838. }
  60839. if (!$attrs) {
  60840. $attrs = array('role' => 'php'); // any old call would be for PHP role only
  60841. }
  60842. if (isset($this->filemap_cache[$attrs['role']][$path])) {
  60843. if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
  60844. return false;
  60845. }
  60846. return $this->filemap_cache[$attrs['role']][$path];
  60847. }
  60848. $l = strlen($this->install_dir);
  60849. if (substr($path, 0, $l) == $this->install_dir) {
  60850. $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
  60851. }
  60852. if (isset($this->filemap_cache[$attrs['role']][$path])) {
  60853. if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
  60854. return false;
  60855. }
  60856. return $this->filemap_cache[$attrs['role']][$path];
  60857. }
  60858. return false;
  60859. }
  60860. // }}}
  60861. // {{{ flush()
  60862. /**
  60863. * Force a reload of the filemap
  60864. * @since 1.5.0RC3
  60865. */
  60866. function flushFileMap()
  60867. {
  60868. $this->filemap_cache = null;
  60869. clearstatcache(); // ensure that the next read gets the full, current filemap
  60870. }
  60871. // }}}
  60872. // {{{ apiVersion()
  60873. /**
  60874. * Get the expected API version. Channels API is version 1.1, as it is backwards
  60875. * compatible with 1.0
  60876. * @return string
  60877. */
  60878. function apiVersion()
  60879. {
  60880. return '1.1';
  60881. }
  60882. // }}}
  60883. /**
  60884. * Parse a package name, or validate a parsed package name array
  60885. * @param string|array pass in an array of format
  60886. * array(
  60887. * 'package' => 'pname',
  60888. * ['channel' => 'channame',]
  60889. * ['version' => 'version',]
  60890. * ['state' => 'state',]
  60891. * ['group' => 'groupname'])
  60892. * or a string of format
  60893. * [channel://][channame/]pname[-version|-state][/group=groupname]
  60894. * @return array|PEAR_Error
  60895. */
  60896. function parsePackageName($param, $defaultchannel = 'pear.php.net')
  60897. {
  60898. $saveparam = $param;
  60899. if (is_array($param)) {
  60900. // convert to string for error messages
  60901. $saveparam = $this->parsedPackageNameToString($param);
  60902. // process the array
  60903. if (!isset($param['package'])) {
  60904. return PEAR::raiseError('parsePackageName(): array $param ' .
  60905. 'must contain a valid package name in index "param"',
  60906. 'package', null, null, $param);
  60907. }
  60908. if (!isset($param['uri'])) {
  60909. if (!isset($param['channel'])) {
  60910. $param['channel'] = $defaultchannel;
  60911. }
  60912. } else {
  60913. $param['channel'] = '__uri';
  60914. }
  60915. } else {
  60916. $components = @parse_url((string) $param);
  60917. if (isset($components['scheme'])) {
  60918. if ($components['scheme'] == 'http') {
  60919. // uri package
  60920. $param = array('uri' => $param, 'channel' => '__uri');
  60921. } elseif($components['scheme'] != 'channel') {
  60922. return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .
  60923. 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);
  60924. }
  60925. }
  60926. if (!isset($components['path'])) {
  60927. return PEAR::raiseError('parsePackageName(): array $param ' .
  60928. 'must contain a valid package name in "' . $param . '"',
  60929. 'package', null, null, $param);
  60930. }
  60931. if (isset($components['host'])) {
  60932. // remove the leading "/"
  60933. $components['path'] = substr($components['path'], 1);
  60934. }
  60935. if (!isset($components['scheme'])) {
  60936. if (strpos($components['path'], '/') !== false) {
  60937. if ($components['path'][0] == '/') {
  60938. return PEAR::raiseError('parsePackageName(): this is not ' .
  60939. 'a package name, it begins with "/" in "' . $param . '"',
  60940. 'invalid', null, null, $param);
  60941. }
  60942. $parts = explode('/', $components['path']);
  60943. $components['host'] = array_shift($parts);
  60944. if (count($parts) > 1) {
  60945. $components['path'] = array_pop($parts);
  60946. $components['host'] .= '/' . implode('/', $parts);
  60947. } else {
  60948. $components['path'] = implode('/', $parts);
  60949. }
  60950. } else {
  60951. $components['host'] = $defaultchannel;
  60952. }
  60953. } else {
  60954. if (strpos($components['path'], '/')) {
  60955. $parts = explode('/', $components['path']);
  60956. $components['path'] = array_pop($parts);
  60957. $components['host'] .= '/' . implode('/', $parts);
  60958. }
  60959. }
  60960. if (is_array($param)) {
  60961. $param['package'] = $components['path'];
  60962. } else {
  60963. $param = array(
  60964. 'package' => $components['path']
  60965. );
  60966. if (isset($components['host'])) {
  60967. $param['channel'] = $components['host'];
  60968. }
  60969. }
  60970. if (isset($components['fragment'])) {
  60971. $param['group'] = $components['fragment'];
  60972. }
  60973. if (isset($components['user'])) {
  60974. $param['user'] = $components['user'];
  60975. }
  60976. if (isset($components['pass'])) {
  60977. $param['pass'] = $components['pass'];
  60978. }
  60979. if (isset($components['query'])) {
  60980. parse_str($components['query'], $param['opts']);
  60981. }
  60982. // check for extension
  60983. $pathinfo = pathinfo($param['package']);
  60984. if (isset($pathinfo['extension']) &&
  60985. in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) {
  60986. $param['extension'] = $pathinfo['extension'];
  60987. $param['package'] = substr($pathinfo['basename'], 0,
  60988. strlen($pathinfo['basename']) - 4);
  60989. }
  60990. // check for version
  60991. if (strpos($param['package'], '-')) {
  60992. $test = explode('-', $param['package']);
  60993. if (count($test) != 2) {
  60994. return PEAR::raiseError('parsePackageName(): only one version/state ' .
  60995. 'delimiter "-" is allowed in "' . $saveparam . '"',
  60996. 'version', null, null, $param);
  60997. }
  60998. list($param['package'], $param['version']) = $test;
  60999. }
  61000. }
  61001. // validation
  61002. $info = $this->channelExists($param['channel']);
  61003. if (PEAR::isError($info)) {
  61004. return $info;
  61005. }
  61006. if (!$info) {
  61007. return PEAR::raiseError('unknown channel "' . $param['channel'] .
  61008. '" in "' . $saveparam . '"', 'channel', null, null, $param);
  61009. }
  61010. $chan = $this->getChannel($param['channel']);
  61011. if (PEAR::isError($chan)) {
  61012. return $chan;
  61013. }
  61014. if (!$chan) {
  61015. return PEAR::raiseError("Exception: corrupt registry, could not " .
  61016. "retrieve channel " . $param['channel'] . " information",
  61017. 'registry', null, null, $param);
  61018. }
  61019. $param['channel'] = $chan->getName();
  61020. $validate = $chan->getValidationObject();
  61021. $vpackage = $chan->getValidationPackage();
  61022. // validate package name
  61023. if (!$validate->validPackageName($param['package'], $vpackage['_content'])) {
  61024. return PEAR::raiseError('parsePackageName(): invalid package name "' .
  61025. $param['package'] . '" in "' . $saveparam . '"',
  61026. 'package', null, null, $param);
  61027. }
  61028. if (isset($param['group'])) {
  61029. if (!PEAR_Validate::validGroupName($param['group'])) {
  61030. return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] .
  61031. '" is not a valid group name in "' . $saveparam . '"', 'group', null, null,
  61032. $param);
  61033. }
  61034. }
  61035. if (isset($param['state'])) {
  61036. if (!in_array(strtolower($param['state']), $validate->getValidStates())) {
  61037. return PEAR::raiseError('parsePackageName(): state "' . $param['state']
  61038. . '" is not a valid state in "' . $saveparam . '"',
  61039. 'state', null, null, $param);
  61040. }
  61041. }
  61042. if (isset($param['version'])) {
  61043. if (isset($param['state'])) {
  61044. return PEAR::raiseError('parsePackageName(): cannot contain both ' .
  61045. 'a version and a stability (state) in "' . $saveparam . '"',
  61046. 'version/state', null, null, $param);
  61047. }
  61048. // check whether version is actually a state
  61049. if (in_array(strtolower($param['version']), $validate->getValidStates())) {
  61050. $param['state'] = strtolower($param['version']);
  61051. unset($param['version']);
  61052. } else {
  61053. if (!$validate->validVersion($param['version'])) {
  61054. return PEAR::raiseError('parsePackageName(): "' . $param['version'] .
  61055. '" is neither a valid version nor a valid state in "' .
  61056. $saveparam . '"', 'version/state', null, null, $param);
  61057. }
  61058. }
  61059. }
  61060. return $param;
  61061. }
  61062. /**
  61063. * @param array
  61064. * @return string
  61065. */
  61066. function parsedPackageNameToString($parsed, $brief = false)
  61067. {
  61068. if (is_string($parsed)) {
  61069. return $parsed;
  61070. }
  61071. if (is_object($parsed)) {
  61072. $p = $parsed;
  61073. $parsed = array(
  61074. 'package' => $p->getPackage(),
  61075. 'channel' => $p->getChannel(),
  61076. 'version' => $p->getVersion(),
  61077. );
  61078. }
  61079. if (isset($parsed['uri'])) {
  61080. return $parsed['uri'];
  61081. }
  61082. if ($brief) {
  61083. if ($channel = $this->channelAlias($parsed['channel'])) {
  61084. return $channel . '/' . $parsed['package'];
  61085. }
  61086. }
  61087. $upass = '';
  61088. if (isset($parsed['user'])) {
  61089. $upass = $parsed['user'];
  61090. if (isset($parsed['pass'])) {
  61091. $upass .= ':' . $parsed['pass'];
  61092. }
  61093. $upass = "$upass@";
  61094. }
  61095. $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];
  61096. if (isset($parsed['version']) || isset($parsed['state'])) {
  61097. $ver = isset($parsed['version']) ? $parsed['version'] : '';
  61098. $ver .= isset($parsed['state']) ? $parsed['state'] : '';
  61099. $ret .= '-' . $ver;
  61100. }
  61101. if (isset($parsed['extension'])) {
  61102. $ret .= '.' . $parsed['extension'];
  61103. }
  61104. if (isset($parsed['opts'])) {
  61105. $ret .= '?';
  61106. foreach ($parsed['opts'] as $name => $value) {
  61107. $parsed['opts'][$name] = "$name=$value";
  61108. }
  61109. $ret .= implode('&', $parsed['opts']);
  61110. }
  61111. if (isset($parsed['group'])) {
  61112. $ret .= '#' . $parsed['group'];
  61113. }
  61114. return $ret;
  61115. }
  61116. }
  61117. ����������������������������������������PEAR-1.10.10/PEAR/REST.php��������������������������������������������������������������������������0000644�0001750�0001750�00000040457�13565304531�014305� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  61118. /**
  61119. * PEAR_REST
  61120. *
  61121. * PHP versions 4 and 5
  61122. *
  61123. * @category pear
  61124. * @package PEAR
  61125. * @author Greg Beaver <cellog@php.net>
  61126. * @copyright 1997-2009 The Authors
  61127. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  61128. * @link http://pear.php.net/package/PEAR
  61129. * @since File available since Release 1.4.0a1
  61130. */
  61131. /**
  61132. * For downloading xml files
  61133. */
  61134. require_once 'PEAR.php';
  61135. require_once 'PEAR/XMLParser.php';
  61136. require_once 'PEAR/Proxy.php';
  61137. /**
  61138. * Intelligently retrieve data, following hyperlinks if necessary, and re-directing
  61139. * as well
  61140. * @category pear
  61141. * @package PEAR
  61142. * @author Greg Beaver <cellog@php.net>
  61143. * @copyright 1997-2009 The Authors
  61144. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  61145. * @version Release: 1.10.10
  61146. * @link http://pear.php.net/package/PEAR
  61147. * @since Class available since Release 1.4.0a1
  61148. */
  61149. class PEAR_REST
  61150. {
  61151. var $config;
  61152. var $_options;
  61153. function __construct(&$config, $options = array())
  61154. {
  61155. $this->config = &$config;
  61156. $this->_options = $options;
  61157. }
  61158. /**
  61159. * Retrieve REST data, but always retrieve the local cache if it is available.
  61160. *
  61161. * This is useful for elements that should never change, such as information on a particular
  61162. * release
  61163. * @param string full URL to this resource
  61164. * @param array|false contents of the accept-encoding header
  61165. * @param boolean if true, xml will be returned as a string, otherwise, xml will be
  61166. * parsed using PEAR_XMLParser
  61167. * @return string|array
  61168. */
  61169. function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false)
  61170. {
  61171. $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
  61172. md5($url) . 'rest.cachefile';
  61173. if (file_exists($cachefile)) {
  61174. return unserialize(implode('', file($cachefile)));
  61175. }
  61176. return $this->retrieveData($url, $accept, $forcestring, $channel);
  61177. }
  61178. /**
  61179. * Retrieve a remote REST resource
  61180. * @param string full URL to this resource
  61181. * @param array|false contents of the accept-encoding header
  61182. * @param boolean if true, xml will be returned as a string, otherwise, xml will be
  61183. * parsed using PEAR_XMLParser
  61184. * @return string|array
  61185. */
  61186. function retrieveData($url, $accept = false, $forcestring = false, $channel = false)
  61187. {
  61188. $cacheId = $this->getCacheId($url);
  61189. if ($ret = $this->useLocalCache($url, $cacheId)) {
  61190. return $ret;
  61191. }
  61192. $file = $trieddownload = false;
  61193. if (!isset($this->_options['offline'])) {
  61194. $trieddownload = true;
  61195. $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel);
  61196. }
  61197. if (PEAR::isError($file)) {
  61198. if ($file->getCode() !== -9276) {
  61199. return $file;
  61200. }
  61201. $trieddownload = false;
  61202. $file = false; // use local copy if available on socket connect error
  61203. }
  61204. if (!$file) {
  61205. $ret = $this->getCache($url);
  61206. if (!PEAR::isError($ret) && $trieddownload) {
  61207. // reset the age of the cache if the server says it was unmodified
  61208. $result = $this->saveCache($url, $ret, null, true, $cacheId);
  61209. if (PEAR::isError($result)) {
  61210. return PEAR::raiseError($result->getMessage());
  61211. }
  61212. }
  61213. return $ret;
  61214. }
  61215. if (is_array($file)) {
  61216. $headers = $file[2];
  61217. $lastmodified = $file[1];
  61218. $content = $file[0];
  61219. } else {
  61220. $headers = array();
  61221. $lastmodified = false;
  61222. $content = $file;
  61223. }
  61224. if ($forcestring) {
  61225. $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
  61226. if (PEAR::isError($result)) {
  61227. return PEAR::raiseError($result->getMessage());
  61228. }
  61229. return $content;
  61230. }
  61231. if (isset($headers['content-type'])) {
  61232. $content_type = explode(";", $headers['content-type']);
  61233. $content_type = $content_type[0];
  61234. switch ($content_type) {
  61235. case 'text/xml' :
  61236. case 'application/xml' :
  61237. case 'text/plain' :
  61238. if ($content_type === 'text/plain') {
  61239. $check = substr($content, 0, 5);
  61240. if ($check !== '<?xml') {
  61241. break;
  61242. }
  61243. }
  61244. $parser = new PEAR_XMLParser;
  61245. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  61246. $err = $parser->parse($content);
  61247. PEAR::popErrorHandling();
  61248. if (PEAR::isError($err)) {
  61249. return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' .
  61250. $err->getMessage());
  61251. }
  61252. $content = $parser->getData();
  61253. case 'text/html' :
  61254. default :
  61255. // use it as a string
  61256. }
  61257. } else {
  61258. // assume XML
  61259. $parser = new PEAR_XMLParser;
  61260. $parser->parse($content);
  61261. $content = $parser->getData();
  61262. }
  61263. $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
  61264. if (PEAR::isError($result)) {
  61265. return PEAR::raiseError($result->getMessage());
  61266. }
  61267. return $content;
  61268. }
  61269. function useLocalCache($url, $cacheid = null)
  61270. {
  61271. if (!is_array($cacheid)) {
  61272. $cacheid = $this->getCacheId($url);
  61273. }
  61274. $cachettl = $this->config->get('cache_ttl');
  61275. // If cache is newer than $cachettl seconds, we use the cache!
  61276. if (time() - $cacheid['age'] < $cachettl) {
  61277. return $this->getCache($url);
  61278. }
  61279. return false;
  61280. }
  61281. /**
  61282. * @param string $url
  61283. *
  61284. * @return bool|mixed
  61285. */
  61286. function getCacheId($url)
  61287. {
  61288. $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
  61289. md5($url) . 'rest.cacheid';
  61290. if (!file_exists($cacheidfile)) {
  61291. return false;
  61292. }
  61293. $ret = unserialize(implode('', file($cacheidfile)));
  61294. return $ret;
  61295. }
  61296. function getCache($url)
  61297. {
  61298. $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
  61299. md5($url) . 'rest.cachefile';
  61300. if (!file_exists($cachefile)) {
  61301. return PEAR::raiseError('No cached content available for "' . $url . '"');
  61302. }
  61303. return unserialize(implode('', file($cachefile)));
  61304. }
  61305. /**
  61306. * @param string full URL to REST resource
  61307. * @param string original contents of the REST resource
  61308. * @param array HTTP Last-Modified and ETag headers
  61309. * @param bool if true, then the cache id file should be regenerated to
  61310. * trigger a new time-to-live value
  61311. */
  61312. function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null)
  61313. {
  61314. $cache_dir = $this->config->get('cache_dir');
  61315. $d = $cache_dir . DIRECTORY_SEPARATOR . md5($url);
  61316. $cacheidfile = $d . 'rest.cacheid';
  61317. $cachefile = $d . 'rest.cachefile';
  61318. if (!is_dir($cache_dir)) {
  61319. if (System::mkdir(array('-p', $cache_dir)) === false) {
  61320. return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed.");
  61321. }
  61322. }
  61323. if (!is_writeable($cache_dir)) {
  61324. // If writing to the cache dir is not going to work, silently do nothing.
  61325. // An ugly hack, but retains compat with PEAR 1.9.1 where many commands
  61326. // work fine as non-root user (w/out write access to default cache dir).
  61327. return true;
  61328. }
  61329. if ($cacheid === null && $nochange) {
  61330. $cacheid = unserialize(implode('', file($cacheidfile)));
  61331. }
  61332. $idData = serialize(array(
  61333. 'age' => time(),
  61334. 'lastChange' => ($nochange ? $cacheid['lastChange'] : $lastmodified),
  61335. ));
  61336. $result = $this->saveCacheFile($cacheidfile, $idData);
  61337. if (PEAR::isError($result)) {
  61338. return $result;
  61339. } elseif ($nochange) {
  61340. return true;
  61341. }
  61342. $result = $this->saveCacheFile($cachefile, serialize($contents));
  61343. if (PEAR::isError($result)) {
  61344. if (file_exists($cacheidfile)) {
  61345. @unlink($cacheidfile);
  61346. }
  61347. return $result;
  61348. }
  61349. return true;
  61350. }
  61351. function saveCacheFile($file, $contents)
  61352. {
  61353. $len = strlen($contents);
  61354. $cachefile_fp = @fopen($file, 'xb'); // x is the O_CREAT|O_EXCL mode
  61355. if ($cachefile_fp !== false) { // create file
  61356. if (fwrite($cachefile_fp, $contents, $len) < $len) {
  61357. fclose($cachefile_fp);
  61358. return PEAR::raiseError("Could not write $file.");
  61359. }
  61360. } else { // update file
  61361. $cachefile_fp = @fopen($file, 'r+b'); // do not truncate file
  61362. if (!$cachefile_fp) {
  61363. return PEAR::raiseError("Could not open $file for writing.");
  61364. }
  61365. if (OS_WINDOWS) {
  61366. $not_symlink = !is_link($file); // see bug #18834
  61367. } else {
  61368. $cachefile_lstat = lstat($file);
  61369. $cachefile_fstat = fstat($cachefile_fp);
  61370. $not_symlink = $cachefile_lstat['mode'] == $cachefile_fstat['mode']
  61371. && $cachefile_lstat['ino'] == $cachefile_fstat['ino']
  61372. && $cachefile_lstat['dev'] == $cachefile_fstat['dev']
  61373. && $cachefile_fstat['nlink'] === 1;
  61374. }
  61375. if ($not_symlink) {
  61376. ftruncate($cachefile_fp, 0); // NOW truncate
  61377. if (fwrite($cachefile_fp, $contents, $len) < $len) {
  61378. fclose($cachefile_fp);
  61379. return PEAR::raiseError("Could not write $file.");
  61380. }
  61381. } else {
  61382. fclose($cachefile_fp);
  61383. $link = function_exists('readlink') ? readlink($file) : $file;
  61384. return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $file . ' as it is symlinked to ' . $link . ' - Possible symlink attack');
  61385. }
  61386. }
  61387. fclose($cachefile_fp);
  61388. return true;
  61389. }
  61390. /**
  61391. * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory
  61392. * This is best used for small files
  61393. *
  61394. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  61395. * setting), the proxy will be used.
  61396. *
  61397. * @param string $url the URL to download
  61398. * @param string $save_dir directory to save file in
  61399. * @param false|string|array $lastmodified header values to check against for caching
  61400. * use false to return the header values from this download
  61401. * @param false|array $accept Accept headers to send
  61402. * @return string|array Returns the contents of the downloaded file or a PEAR
  61403. * error on failure. If the error is caused by
  61404. * socket-related errors, the error object will
  61405. * have the fsockopen error code available through
  61406. * getCode(). If caching is requested, then return the header
  61407. * values.
  61408. *
  61409. * @access public
  61410. */
  61411. function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false)
  61412. {
  61413. static $redirect = 0;
  61414. // always reset , so we are clean case of error
  61415. $wasredirect = $redirect;
  61416. $redirect = 0;
  61417. $info = parse_url($url);
  61418. if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
  61419. return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
  61420. }
  61421. if (!isset($info['host'])) {
  61422. return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
  61423. }
  61424. $host = isset($info['host']) ? $info['host'] : null;
  61425. $port = isset($info['port']) ? $info['port'] : null;
  61426. $path = isset($info['path']) ? $info['path'] : null;
  61427. $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
  61428. $proxy = new PEAR_Proxy($this->config);
  61429. if (empty($port)) {
  61430. $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
  61431. }
  61432. if ($proxy->isProxyConfigured() && $schema === 'http') {
  61433. $request = "GET $url HTTP/1.1\r\n";
  61434. } else {
  61435. $request = "GET $path HTTP/1.1\r\n";
  61436. }
  61437. $request .= "Host: $host\r\n";
  61438. $ifmodifiedsince = '';
  61439. if (is_array($lastmodified)) {
  61440. if (isset($lastmodified['Last-Modified'])) {
  61441. $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
  61442. }
  61443. if (isset($lastmodified['ETag'])) {
  61444. $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
  61445. }
  61446. } else {
  61447. $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
  61448. }
  61449. $request .= $ifmodifiedsince .
  61450. "User-Agent: PEAR/1.10.10/PHP/" . PHP_VERSION . "\r\n";
  61451. $username = $this->config->get('username', null, $channel);
  61452. $password = $this->config->get('password', null, $channel);
  61453. if ($username && $password) {
  61454. $tmp = base64_encode("$username:$password");
  61455. $request .= "Authorization: Basic $tmp\r\n";
  61456. }
  61457. $proxyAuth = $proxy->getProxyAuth();
  61458. if ($proxyAuth) {
  61459. $request .= 'Proxy-Authorization: Basic ' .
  61460. $proxyAuth . "\r\n";
  61461. }
  61462. if ($accept) {
  61463. $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
  61464. }
  61465. $request .= "Accept-Encoding:\r\n";
  61466. $request .= "Connection: close\r\n";
  61467. $request .= "\r\n";
  61468. $secure = ($schema == 'https');
  61469. $fp = $proxy->openSocket($host, $port, $secure);
  61470. if (PEAR::isError($fp)) {
  61471. return $fp;
  61472. }
  61473. fwrite($fp, $request);
  61474. $headers = array();
  61475. $reply = 0;
  61476. while ($line = trim(fgets($fp, 1024))) {
  61477. if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
  61478. $headers[strtolower($matches[1])] = trim($matches[2]);
  61479. } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  61480. $reply = (int)$matches[1];
  61481. if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
  61482. return false;
  61483. }
  61484. if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
  61485. return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)");
  61486. }
  61487. }
  61488. }
  61489. if ($reply != 200) {
  61490. if (!isset($headers['location'])) {
  61491. return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)");
  61492. }
  61493. if ($wasredirect > 4) {
  61494. return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)");
  61495. }
  61496. $redirect = $wasredirect + 1;
  61497. return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel);
  61498. }
  61499. $length = isset($headers['content-length']) ? $headers['content-length'] : -1;
  61500. $data = '';
  61501. while ($chunk = @fread($fp, 8192)) {
  61502. $data .= $chunk;
  61503. }
  61504. fclose($fp);
  61505. if ($lastmodified === false || $lastmodified) {
  61506. if (isset($headers['etag'])) {
  61507. $lastmodified = array('ETag' => $headers['etag']);
  61508. }
  61509. if (isset($headers['last-modified'])) {
  61510. if (is_array($lastmodified)) {
  61511. $lastmodified['Last-Modified'] = $headers['last-modified'];
  61512. } else {
  61513. $lastmodified = $headers['last-modified'];
  61514. }
  61515. }
  61516. return array($data, $lastmodified, $headers);
  61517. }
  61518. return $data;
  61519. }
  61520. }
  61521. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/RunTest.php�����������������������������������������������������������������������0000644�0001750�0001750�00000106173�13565304531�015132� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  61522. /**
  61523. * PEAR_RunTest
  61524. *
  61525. * PHP versions 4 and 5
  61526. *
  61527. * @category pear
  61528. * @package PEAR
  61529. * @author Tomas V.V.Cox <cox@idecnet.com>
  61530. * @author Greg Beaver <cellog@php.net>
  61531. * @copyright 1997-2009 The Authors
  61532. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  61533. * @link http://pear.php.net/package/PEAR
  61534. * @since File available since Release 1.3.3
  61535. */
  61536. /**
  61537. * for error handling
  61538. */
  61539. require_once 'PEAR.php';
  61540. require_once 'PEAR/Config.php';
  61541. define('DETAILED', 1);
  61542. putenv("PHP_PEAR_RUNTESTS=1");
  61543. /**
  61544. * Simplified version of PHP's test suite
  61545. *
  61546. * Try it with:
  61547. *
  61548. * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);'
  61549. *
  61550. *
  61551. * @category pear
  61552. * @package PEAR
  61553. * @author Tomas V.V.Cox <cox@idecnet.com>
  61554. * @author Greg Beaver <cellog@php.net>
  61555. * @copyright 1997-2009 The Authors
  61556. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  61557. * @version Release: 1.10.10
  61558. * @link http://pear.php.net/package/PEAR
  61559. * @since Class available since Release 1.3.3
  61560. */
  61561. class PEAR_RunTest
  61562. {
  61563. var $_headers = array();
  61564. var $_logger;
  61565. var $_options;
  61566. var $_php;
  61567. var $tests_count;
  61568. var $xdebug_loaded;
  61569. /**
  61570. * Saved value of php executable, used to reset $_php when we
  61571. * have a test that uses cgi
  61572. *
  61573. * @var unknown_type
  61574. */
  61575. var $_savephp;
  61576. var $ini_overwrites = array(
  61577. 'output_handler=',
  61578. 'open_basedir=',
  61579. 'disable_functions=',
  61580. 'output_buffering=Off',
  61581. 'display_errors=1',
  61582. 'log_errors=0',
  61583. 'html_errors=0',
  61584. 'report_memleaks=0',
  61585. 'report_zend_debug=0',
  61586. 'docref_root=',
  61587. 'docref_ext=.html',
  61588. 'error_prepend_string=',
  61589. 'error_append_string=',
  61590. 'auto_prepend_file=',
  61591. 'auto_append_file=',
  61592. 'xdebug.default_enable=0',
  61593. 'allow_url_fopen=1',
  61594. );
  61595. /**
  61596. * An object that supports the PEAR_Common->log() signature, or null
  61597. * @param PEAR_Common|null
  61598. */
  61599. function __construct($logger = null, $options = array())
  61600. {
  61601. if (!defined('E_DEPRECATED')) {
  61602. define('E_DEPRECATED', 0);
  61603. }
  61604. if (!defined('E_STRICT')) {
  61605. define('E_STRICT', 0);
  61606. }
  61607. $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT));
  61608. if (is_null($logger)) {
  61609. require_once 'PEAR/Common.php';
  61610. $logger = new PEAR_Common;
  61611. }
  61612. $this->_logger = $logger;
  61613. $this->_options = $options;
  61614. $conf = &PEAR_Config::singleton();
  61615. $this->_php = $conf->get('php_bin');
  61616. }
  61617. /**
  61618. * Taken from php-src/run-tests.php
  61619. *
  61620. * @param string $commandline command name
  61621. * @param array $env
  61622. * @param string $stdin standard input to pass to the command
  61623. * @return unknown
  61624. */
  61625. function system_with_timeout($commandline, $env = null, $stdin = null)
  61626. {
  61627. $data = '';
  61628. $proc = proc_open($commandline, array(
  61629. 0 => array('pipe', 'r'),
  61630. 1 => array('pipe', 'w'),
  61631. 2 => array('pipe', 'w')
  61632. ), $pipes, null, $env, array('suppress_errors' => true));
  61633. if (!$proc) {
  61634. return false;
  61635. }
  61636. if (is_string($stdin)) {
  61637. fwrite($pipes[0], $stdin);
  61638. }
  61639. fclose($pipes[0]);
  61640. while (true) {
  61641. /* hide errors from interrupted syscalls */
  61642. $r = $pipes;
  61643. $e = $w = null;
  61644. $n = @stream_select($r, $w, $e, 60);
  61645. if ($n === 0) {
  61646. /* timed out */
  61647. $data .= "\n ** ERROR: process timed out **\n";
  61648. proc_terminate($proc);
  61649. return array(1234567890, $data);
  61650. } else if ($n > 0) {
  61651. $line = fread($pipes[1], 8192);
  61652. if (strlen($line) == 0) {
  61653. /* EOF */
  61654. break;
  61655. }
  61656. $data .= $line;
  61657. }
  61658. }
  61659. if (function_exists('proc_get_status')) {
  61660. $stat = proc_get_status($proc);
  61661. if ($stat['signaled']) {
  61662. $data .= "\nTermsig=".$stat['stopsig'];
  61663. }
  61664. }
  61665. $code = proc_close($proc);
  61666. if (function_exists('proc_get_status')) {
  61667. $code = $stat['exitcode'];
  61668. }
  61669. return array($code, $data);
  61670. }
  61671. /**
  61672. * Turns a PHP INI string into an array
  61673. *
  61674. * Turns -d "include_path=/foo/bar" into this:
  61675. * array(
  61676. * 'include_path' => array(
  61677. * 'operator' => '-d',
  61678. * 'value' => '/foo/bar',
  61679. * )
  61680. * )
  61681. * Works both with quotes and without
  61682. *
  61683. * @param string an PHP INI string, -d "include_path=/foo/bar"
  61684. * @return array
  61685. */
  61686. function iniString2array($ini_string)
  61687. {
  61688. if (!$ini_string) {
  61689. return array();
  61690. }
  61691. $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY);
  61692. $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1];
  61693. $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2];
  61694. // FIXME review if this is really the struct to go with
  61695. $array = array($key => array('operator' => $split[0], 'value' => $value));
  61696. return $array;
  61697. }
  61698. function settings2array($settings, $ini_settings)
  61699. {
  61700. foreach ($settings as $setting) {
  61701. if (strpos($setting, '=') !== false) {
  61702. $setting = explode('=', $setting, 2);
  61703. $name = trim(strtolower($setting[0]));
  61704. $value = trim($setting[1]);
  61705. $ini_settings[$name] = $value;
  61706. }
  61707. }
  61708. return $ini_settings;
  61709. }
  61710. function settings2params($ini_settings)
  61711. {
  61712. $settings = '';
  61713. foreach ($ini_settings as $name => $value) {
  61714. if (is_array($value)) {
  61715. $operator = $value['operator'];
  61716. $value = $value['value'];
  61717. } else {
  61718. $operator = '-d';
  61719. }
  61720. $value = addslashes($value);
  61721. $settings .= " $operator \"$name=$value\"";
  61722. }
  61723. return $settings;
  61724. }
  61725. function _preparePhpBin($php, $file, $ini_settings)
  61726. {
  61727. $file = escapeshellarg($file);
  61728. $cmd = $php . $ini_settings . ' -f ' . $file;
  61729. return $cmd;
  61730. }
  61731. function runPHPUnit($file, $ini_settings = '')
  61732. {
  61733. if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) {
  61734. $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file);
  61735. } elseif (file_exists($file)) {
  61736. $file = realpath($file);
  61737. }
  61738. $cmd = $this->_preparePhpBin($this->_php, $file, $ini_settings);
  61739. if (isset($this->_logger)) {
  61740. $this->_logger->log(2, 'Running command "' . $cmd . '"');
  61741. }
  61742. $savedir = getcwd(); // in case the test moves us around
  61743. chdir(dirname($file));
  61744. echo `$cmd`;
  61745. chdir($savedir);
  61746. return 'PASSED'; // we have no way of knowing this information so assume passing
  61747. }
  61748. /**
  61749. * Runs an individual test case.
  61750. *
  61751. * @param string The filename of the test
  61752. * @param array|string INI settings to be applied to the test run
  61753. * @param integer Number what the current running test is of the
  61754. * whole test suite being runned.
  61755. *
  61756. * @return string|object Returns PASSED, WARNED, FAILED depending on how the
  61757. * test came out.
  61758. * PEAR Error when the tester it self fails
  61759. */
  61760. function run($file, $ini_settings = array(), $test_number = 1)
  61761. {
  61762. $this->_restorePHPBinary();
  61763. if (empty($this->_options['cgi'])) {
  61764. // try to see if php-cgi is in the path
  61765. $res = $this->system_with_timeout('php-cgi -v');
  61766. if (false !== $res && !(is_array($res) && in_array($res[0], array(-1, 127)))) {
  61767. $this->_options['cgi'] = 'php-cgi';
  61768. }
  61769. }
  61770. if (1 < $len = strlen($this->tests_count)) {
  61771. $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT);
  61772. $test_nr = "[$test_number/$this->tests_count] ";
  61773. } else {
  61774. $test_nr = '';
  61775. }
  61776. $file = realpath($file);
  61777. $section_text = $this->_readFile($file);
  61778. if (PEAR::isError($section_text)) {
  61779. return $section_text;
  61780. }
  61781. if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) {
  61782. return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file");
  61783. }
  61784. $cwd = getcwd();
  61785. $pass_options = '';
  61786. if (!empty($this->_options['ini'])) {
  61787. $pass_options = $this->_options['ini'];
  61788. }
  61789. if (is_string($ini_settings)) {
  61790. $ini_settings = $this->iniString2array($ini_settings);
  61791. }
  61792. $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings);
  61793. if ($section_text['INI']) {
  61794. if (strpos($section_text['INI'], '{PWD}') !== false) {
  61795. $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
  61796. }
  61797. $ini = preg_split( "/[\n\r]+/", $section_text['INI']);
  61798. $ini_settings = $this->settings2array($ini, $ini_settings);
  61799. }
  61800. $ini_settings = $this->settings2params($ini_settings);
  61801. $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file);
  61802. $tested = trim($section_text['TEST']);
  61803. $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' ';
  61804. if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) ||
  61805. !empty($section_text['UPLOAD']) || !empty($section_text['GET']) ||
  61806. !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
  61807. if (empty($this->_options['cgi'])) {
  61808. if (!isset($this->_options['quiet'])) {
  61809. $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')");
  61810. }
  61811. if (isset($this->_options['tapoutput'])) {
  61812. return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info');
  61813. }
  61814. return 'SKIPPED';
  61815. }
  61816. $this->_savePHPBinary();
  61817. $this->_php = $this->_options['cgi'];
  61818. }
  61819. $temp_dir = realpath(dirname($file));
  61820. $main_file_name = basename($file, 'phpt');
  61821. $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff';
  61822. $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log';
  61823. $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp';
  61824. $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out';
  61825. $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem';
  61826. $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
  61827. $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
  61828. $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
  61829. $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.');
  61830. // unlink old test results
  61831. $this->_cleanupOldFiles($file);
  61832. // Check if test should be skipped.
  61833. $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings);
  61834. if ($res == 'SKIPPED' || count($res) != 2) {
  61835. return $res;
  61836. }
  61837. $info = $res['info'];
  61838. $warn = $res['warn'];
  61839. // We've satisfied the preconditions - run the test!
  61840. if (isset($this->_options['coverage']) && $this->xdebug_loaded) {
  61841. $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug';
  61842. $text = "\n" . 'function coverage_shutdown() {' .
  61843. "\n" . ' $xdebug = var_export(xdebug_get_code_coverage(), true);';
  61844. if (!function_exists('file_put_contents')) {
  61845. $text .= "\n" . ' $fh = fopen(\'' . $xdebug_file . '\', "wb");' .
  61846. "\n" . ' if ($fh !== false) {' .
  61847. "\n" . ' fwrite($fh, $xdebug);' .
  61848. "\n" . ' fclose($fh);' .
  61849. "\n" . ' }';
  61850. } else {
  61851. $text .= "\n" . ' file_put_contents(\'' . $xdebug_file . '\', $xdebug);';
  61852. }
  61853. // Workaround for http://pear.php.net/bugs/bug.php?id=17292
  61854. $lines = explode("\n", $section_text['FILE']);
  61855. $numLines = count($lines);
  61856. $namespace = '';
  61857. $coverage_shutdown = 'coverage_shutdown';
  61858. if (
  61859. substr($lines[0], 0, 2) == '<?' ||
  61860. substr($lines[0], 0, 5) == '<?php'
  61861. ) {
  61862. unset($lines[0]);
  61863. }
  61864. for ($i = 0; $i < $numLines; $i++) {
  61865. if (isset($lines[$i]) && substr($lines[$i], 0, 9) == 'namespace') {
  61866. $namespace = substr($lines[$i], 10, -1);
  61867. $coverage_shutdown = $namespace . '\\coverage_shutdown';
  61868. $namespace = "namespace " . $namespace . ";\n";
  61869. unset($lines[$i]);
  61870. break;
  61871. }
  61872. }
  61873. $text .= "\n xdebug_stop_code_coverage();" .
  61874. "\n" . '} // end coverage_shutdown()' .
  61875. "\n\n" . 'register_shutdown_function("' . $coverage_shutdown . '");';
  61876. $text .= "\n" . 'xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);' . "\n";
  61877. $this->save_text($temp_file, "<?php\n" . $namespace . $text . "\n" . implode("\n", $lines));
  61878. } else {
  61879. $this->save_text($temp_file, $section_text['FILE']);
  61880. }
  61881. $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
  61882. $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings);
  61883. $cmd.= "$args 2>&1";
  61884. if (isset($this->_logger)) {
  61885. $this->_logger->log(2, 'Running command "' . $cmd . '"');
  61886. }
  61887. // Reset environment from any previous test.
  61888. $env = $this->_resetEnv($section_text, $temp_file);
  61889. $section_text = $this->_processUpload($section_text, $file);
  61890. if (PEAR::isError($section_text)) {
  61891. return $section_text;
  61892. }
  61893. if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
  61894. $post = trim($section_text['POST_RAW']);
  61895. $raw_lines = explode("\n", $post);
  61896. $request = '';
  61897. $started = false;
  61898. foreach ($raw_lines as $i => $line) {
  61899. if (empty($env['CONTENT_TYPE']) &&
  61900. preg_match('/^Content-Type:(.*)/i', $line, $res)) {
  61901. $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
  61902. continue;
  61903. }
  61904. if ($started) {
  61905. $request .= "\n";
  61906. }
  61907. $started = true;
  61908. $request .= $line;
  61909. }
  61910. $env['CONTENT_LENGTH'] = strlen($request);
  61911. $env['REQUEST_METHOD'] = 'POST';
  61912. $this->save_text($tmp_post, $request);
  61913. $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post";
  61914. } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
  61915. $post = trim($section_text['POST']);
  61916. $this->save_text($tmp_post, $post);
  61917. $content_length = strlen($post);
  61918. $env['REQUEST_METHOD'] = 'POST';
  61919. $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
  61920. $env['CONTENT_LENGTH'] = $content_length;
  61921. $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post";
  61922. } else {
  61923. $env['REQUEST_METHOD'] = 'GET';
  61924. $env['CONTENT_TYPE'] = '';
  61925. $env['CONTENT_LENGTH'] = '';
  61926. }
  61927. if (OS_WINDOWS && isset($section_text['RETURNS'])) {
  61928. ob_start();
  61929. system($cmd, $return_value);
  61930. $out = ob_get_contents();
  61931. ob_end_clean();
  61932. $section_text['RETURNS'] = (int) trim($section_text['RETURNS']);
  61933. $returnfail = ($return_value != $section_text['RETURNS']);
  61934. } else {
  61935. $returnfail = false;
  61936. $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null;
  61937. $out = $this->system_with_timeout($cmd, $env, $stdin);
  61938. $return_value = $out[0];
  61939. $out = $out[1];
  61940. }
  61941. $output = preg_replace('/\r\n/', "\n", trim($out));
  61942. if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) {
  61943. @unlink(realpath($tmp_post));
  61944. }
  61945. chdir($cwd); // in case the test moves us around
  61946. /* when using CGI, strip the headers from the output */
  61947. $output = $this->_stripHeadersCGI($output);
  61948. if (isset($section_text['EXPECTHEADERS'])) {
  61949. $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']);
  61950. $missing = array_diff_assoc($testheaders, $this->_headers);
  61951. $changed = '';
  61952. foreach ($missing as $header => $value) {
  61953. if (isset($this->_headers[$header])) {
  61954. $changed .= "-$header: $value\n+$header: ";
  61955. $changed .= $this->_headers[$header];
  61956. } else {
  61957. $changed .= "-$header: $value\n";
  61958. }
  61959. }
  61960. if ($missing) {
  61961. // tack on failed headers to output:
  61962. $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed";
  61963. }
  61964. }
  61965. $this->_testCleanup($section_text, $temp_clean);
  61966. // Does the output match what is expected?
  61967. do {
  61968. if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
  61969. if (isset($section_text['EXPECTF'])) {
  61970. $wanted = trim($section_text['EXPECTF']);
  61971. } else {
  61972. $wanted = trim($section_text['EXPECTREGEX']);
  61973. }
  61974. $wanted_re = preg_replace('/\r\n/', "\n", $wanted);
  61975. if (isset($section_text['EXPECTF'])) {
  61976. $wanted_re = preg_quote($wanted_re, '/');
  61977. // Stick to basics
  61978. $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy
  61979. $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re);
  61980. $wanted_re = str_replace("%d", "[0-9]+", $wanted_re);
  61981. $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re);
  61982. $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re);
  61983. $wanted_re = str_replace("%c", ".", $wanted_re);
  61984. // %f allows two points "-.0.0" but that is the best *simple* expression
  61985. }
  61986. /* DEBUG YOUR REGEX HERE
  61987. var_dump($wanted_re);
  61988. print(str_repeat('=', 80) . "\n");
  61989. var_dump($output);
  61990. */
  61991. if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) {
  61992. if (file_exists($temp_file)) {
  61993. unlink($temp_file);
  61994. }
  61995. if (array_key_exists('FAIL', $section_text)) {
  61996. break;
  61997. }
  61998. if (!isset($this->_options['quiet'])) {
  61999. $this->_logger->log(0, "PASS $test_nr$tested$info");
  62000. }
  62001. if (isset($this->_options['tapoutput'])) {
  62002. return array('ok', ' - ' . $tested);
  62003. }
  62004. return 'PASSED';
  62005. }
  62006. } else {
  62007. if (isset($section_text['EXPECTFILE'])) {
  62008. $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']);
  62009. if (!($fp = @fopen($f, 'rb'))) {
  62010. return PEAR::raiseError('--EXPECTFILE-- section file ' .
  62011. $f . ' not found');
  62012. }
  62013. fclose($fp);
  62014. $section_text['EXPECT'] = file_get_contents($f);
  62015. }
  62016. if (isset($section_text['EXPECT'])) {
  62017. $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT']));
  62018. } else {
  62019. $wanted = '';
  62020. }
  62021. // compare and leave on success
  62022. if (!$returnfail && 0 == strcmp($output, $wanted)) {
  62023. if (file_exists($temp_file)) {
  62024. unlink($temp_file);
  62025. }
  62026. if (array_key_exists('FAIL', $section_text)) {
  62027. break;
  62028. }
  62029. if (!isset($this->_options['quiet'])) {
  62030. $this->_logger->log(0, "PASS $test_nr$tested$info");
  62031. }
  62032. if (isset($this->_options['tapoutput'])) {
  62033. return array('ok', ' - ' . $tested);
  62034. }
  62035. return 'PASSED';
  62036. }
  62037. }
  62038. } while (false);
  62039. if (array_key_exists('FAIL', $section_text)) {
  62040. // we expect a particular failure
  62041. // this is only used for testing PEAR_RunTest
  62042. $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null;
  62043. $faildiff = $this->generate_diff($wanted, $output, null, $expectf);
  62044. $faildiff = preg_replace('/\r/', '', $faildiff);
  62045. $wanted = preg_replace('/\r/', '', trim($section_text['FAIL']));
  62046. if ($faildiff == $wanted) {
  62047. if (!isset($this->_options['quiet'])) {
  62048. $this->_logger->log(0, "PASS $test_nr$tested$info");
  62049. }
  62050. if (isset($this->_options['tapoutput'])) {
  62051. return array('ok', ' - ' . $tested);
  62052. }
  62053. return 'PASSED';
  62054. }
  62055. unset($section_text['EXPECTF']);
  62056. $output = $faildiff;
  62057. if (isset($section_text['RETURNS'])) {
  62058. return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' .
  62059. $file);
  62060. }
  62061. }
  62062. // Test failed so we need to report details.
  62063. $txt = $warn ? 'WARN ' : 'FAIL ';
  62064. $this->_logger->log(0, $txt . $test_nr . $tested . $info);
  62065. // write .exp
  62066. $res = $this->_writeLog($exp_filename, $wanted);
  62067. if (PEAR::isError($res)) {
  62068. return $res;
  62069. }
  62070. // write .out
  62071. $res = $this->_writeLog($output_filename, $output);
  62072. if (PEAR::isError($res)) {
  62073. return $res;
  62074. }
  62075. // write .diff
  62076. $returns = isset($section_text['RETURNS']) ?
  62077. array(trim($section_text['RETURNS']), $return_value) : null;
  62078. $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null;
  62079. $data = $this->generate_diff($wanted, $output, $returns, $expectf);
  62080. $res = $this->_writeLog($diff_filename, $data);
  62081. if (isset($this->_options['showdiff'])) {
  62082. $this->_logger->log(0, "========DIFF========");
  62083. $this->_logger->log(0, $data);
  62084. $this->_logger->log(0, "========DONE========");
  62085. }
  62086. if (PEAR::isError($res)) {
  62087. return $res;
  62088. }
  62089. // write .log
  62090. $data = "
  62091. ---- EXPECTED OUTPUT
  62092. $wanted
  62093. ---- ACTUAL OUTPUT
  62094. $output
  62095. ---- FAILED
  62096. ";
  62097. if ($returnfail) {
  62098. $data .= "
  62099. ---- EXPECTED RETURN
  62100. $section_text[RETURNS]
  62101. ---- ACTUAL RETURN
  62102. $return_value
  62103. ";
  62104. }
  62105. $res = $this->_writeLog($log_filename, $data);
  62106. if (PEAR::isError($res)) {
  62107. return $res;
  62108. }
  62109. if (isset($this->_options['tapoutput'])) {
  62110. $wanted = explode("\n", $wanted);
  62111. $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted);
  62112. $output = explode("\n", $output);
  62113. $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output);
  62114. return array($wanted . $output . 'not ok', ' - ' . $tested);
  62115. }
  62116. return $warn ? 'WARNED' : 'FAILED';
  62117. }
  62118. function generate_diff($wanted, $output, $rvalue, $wanted_re)
  62119. {
  62120. $w = explode("\n", $wanted);
  62121. $o = explode("\n", $output);
  62122. $wr = explode("\n", $wanted_re);
  62123. $w1 = array_diff_assoc($w, $o);
  62124. $o1 = array_diff_assoc($o, $w);
  62125. $o2 = $w2 = array();
  62126. foreach ($w1 as $idx => $val) {
  62127. if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) ||
  62128. !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) {
  62129. $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val;
  62130. }
  62131. }
  62132. foreach ($o1 as $idx => $val) {
  62133. if (!$wanted_re || !isset($wr[$idx]) ||
  62134. !preg_match('/^' . $wr[$idx] . '\\z/', $val)) {
  62135. $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val;
  62136. }
  62137. }
  62138. $diff = array_merge($w2, $o2);
  62139. ksort($diff);
  62140. $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : '';
  62141. return implode("\r\n", $diff) . $extra;
  62142. }
  62143. // Write the given text to a temporary file, and return the filename.
  62144. function save_text($filename, $text)
  62145. {
  62146. if (!$fp = fopen($filename, 'w')) {
  62147. return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)");
  62148. }
  62149. fwrite($fp, $text);
  62150. fclose($fp);
  62151. if (1 < DETAILED) echo "
  62152. FILE $filename {{{
  62153. $text
  62154. }}}
  62155. ";
  62156. }
  62157. function _cleanupOldFiles($file)
  62158. {
  62159. $temp_dir = realpath(dirname($file));
  62160. $mainFileName = basename($file, 'phpt');
  62161. $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff';
  62162. $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log';
  62163. $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp';
  62164. $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out';
  62165. $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem';
  62166. $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php';
  62167. $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php';
  62168. $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php';
  62169. $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.');
  62170. // unlink old test results
  62171. @unlink($diff_filename);
  62172. @unlink($log_filename);
  62173. @unlink($exp_filename);
  62174. @unlink($output_filename);
  62175. @unlink($memcheck_filename);
  62176. @unlink($temp_file);
  62177. @unlink($temp_skipif);
  62178. @unlink($tmp_post);
  62179. @unlink($temp_clean);
  62180. }
  62181. function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings)
  62182. {
  62183. $info = '';
  62184. $warn = false;
  62185. if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) {
  62186. $this->save_text($temp_skipif, $section_text['SKIPIF']);
  62187. $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\"");
  62188. $output = $output[1];
  62189. $loutput = ltrim($output);
  62190. unlink($temp_skipif);
  62191. if (!strncasecmp('skip', $loutput, 4)) {
  62192. $skipreason = "SKIP $tested";
  62193. if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
  62194. $skipreason .= '(reason: ' . $m[1] . ')';
  62195. }
  62196. if (!isset($this->_options['quiet'])) {
  62197. $this->_logger->log(0, $skipreason);
  62198. }
  62199. if (isset($this->_options['tapoutput'])) {
  62200. return array('ok', ' # skip ' . $reason);
  62201. }
  62202. return 'SKIPPED';
  62203. }
  62204. if (!strncasecmp('info', $loutput, 4)
  62205. && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
  62206. $info = " (info: $m[1])";
  62207. }
  62208. if (!strncasecmp('warn', $loutput, 4)
  62209. && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
  62210. $warn = true; /* only if there is a reason */
  62211. $info = " (warn: $m[1])";
  62212. }
  62213. }
  62214. return array('warn' => $warn, 'info' => $info);
  62215. }
  62216. function _stripHeadersCGI($output)
  62217. {
  62218. $this->headers = array();
  62219. if (!empty($this->_options['cgi']) &&
  62220. $this->_php == $this->_options['cgi'] &&
  62221. preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) {
  62222. $output = isset($match[2]) ? trim($match[2]) : '';
  62223. $this->_headers = $this->_processHeaders($match[1]);
  62224. }
  62225. return $output;
  62226. }
  62227. /**
  62228. * Return an array that can be used with array_diff() to compare headers
  62229. *
  62230. * @param string $text
  62231. */
  62232. function _processHeaders($text)
  62233. {
  62234. $headers = array();
  62235. $rh = preg_split("/[\n\r]+/", $text);
  62236. foreach ($rh as $line) {
  62237. if (strpos($line, ':')!== false) {
  62238. $line = explode(':', $line, 2);
  62239. $headers[trim($line[0])] = trim($line[1]);
  62240. }
  62241. }
  62242. return $headers;
  62243. }
  62244. function _readFile($file)
  62245. {
  62246. // Load the sections of the test file.
  62247. $section_text = array(
  62248. 'TEST' => '(unnamed test)',
  62249. 'SKIPIF' => '',
  62250. 'GET' => '',
  62251. 'COOKIE' => '',
  62252. 'POST' => '',
  62253. 'ARGS' => '',
  62254. 'INI' => '',
  62255. 'CLEAN' => '',
  62256. );
  62257. if (!is_file($file) || !$fp = fopen($file, "r")) {
  62258. return PEAR::raiseError("Cannot open test file: $file");
  62259. }
  62260. $section = '';
  62261. while (!feof($fp)) {
  62262. $line = fgets($fp);
  62263. // Match the beginning of a section.
  62264. if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
  62265. $section = $r[1];
  62266. $section_text[$section] = '';
  62267. continue;
  62268. } elseif (empty($section)) {
  62269. fclose($fp);
  62270. return PEAR::raiseError("Invalid sections formats in test file: $file");
  62271. }
  62272. // Add to the section text.
  62273. $section_text[$section] .= $line;
  62274. }
  62275. fclose($fp);
  62276. return $section_text;
  62277. }
  62278. function _writeLog($logname, $data)
  62279. {
  62280. if (!$log = fopen($logname, 'w')) {
  62281. return PEAR::raiseError("Cannot create test log - $logname");
  62282. }
  62283. fwrite($log, $data);
  62284. fclose($log);
  62285. }
  62286. function _resetEnv($section_text, $temp_file)
  62287. {
  62288. $env = $_ENV;
  62289. $env['REDIRECT_STATUS'] = '';
  62290. $env['QUERY_STRING'] = '';
  62291. $env['PATH_TRANSLATED'] = '';
  62292. $env['SCRIPT_FILENAME'] = '';
  62293. $env['REQUEST_METHOD'] = '';
  62294. $env['CONTENT_TYPE'] = '';
  62295. $env['CONTENT_LENGTH'] = '';
  62296. if (!empty($section_text['ENV'])) {
  62297. if (strpos($section_text['ENV'], '{PWD}') !== false) {
  62298. $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']);
  62299. }
  62300. foreach (explode("\n", trim($section_text['ENV'])) as $e) {
  62301. $e = explode('=', trim($e), 2);
  62302. if (!empty($e[0]) && isset($e[1])) {
  62303. $env[$e[0]] = $e[1];
  62304. }
  62305. }
  62306. }
  62307. if (array_key_exists('GET', $section_text)) {
  62308. $env['QUERY_STRING'] = trim($section_text['GET']);
  62309. } else {
  62310. $env['QUERY_STRING'] = '';
  62311. }
  62312. if (array_key_exists('COOKIE', $section_text)) {
  62313. $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
  62314. } else {
  62315. $env['HTTP_COOKIE'] = '';
  62316. }
  62317. $env['REDIRECT_STATUS'] = '1';
  62318. $env['PATH_TRANSLATED'] = $temp_file;
  62319. $env['SCRIPT_FILENAME'] = $temp_file;
  62320. return $env;
  62321. }
  62322. function _processUpload($section_text, $file)
  62323. {
  62324. if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) {
  62325. $upload_files = trim($section_text['UPLOAD']);
  62326. $upload_files = explode("\n", $upload_files);
  62327. $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" .
  62328. "-----------------------------20896060251896012921717172737\n";
  62329. foreach ($upload_files as $fileinfo) {
  62330. $fileinfo = explode('=', $fileinfo);
  62331. if (count($fileinfo) != 2) {
  62332. return PEAR::raiseError("Invalid UPLOAD section in test file: $file");
  62333. }
  62334. if (!realpath(dirname($file) . '/' . $fileinfo[1])) {
  62335. return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " .
  62336. "in test file: $file");
  62337. }
  62338. $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]);
  62339. $fileinfo[1] = basename($fileinfo[1]);
  62340. $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n";
  62341. $request .= "Content-Type: text/plain\n\n";
  62342. $request .= $file_contents . "\n" .
  62343. "-----------------------------20896060251896012921717172737\n";
  62344. }
  62345. if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
  62346. // encode POST raw
  62347. $post = trim($section_text['POST']);
  62348. $post = explode('&', $post);
  62349. foreach ($post as $i => $post_info) {
  62350. $post_info = explode('=', $post_info);
  62351. if (count($post_info) != 2) {
  62352. return PEAR::raiseError("Invalid POST data in test file: $file");
  62353. }
  62354. $post_info[0] = rawurldecode($post_info[0]);
  62355. $post_info[1] = rawurldecode($post_info[1]);
  62356. $post[$i] = $post_info;
  62357. }
  62358. foreach ($post as $post_info) {
  62359. $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n";
  62360. $request .= $post_info[1] . "\n" .
  62361. "-----------------------------20896060251896012921717172737\n";
  62362. }
  62363. unset($section_text['POST']);
  62364. }
  62365. $section_text['POST_RAW'] = $request;
  62366. }
  62367. return $section_text;
  62368. }
  62369. function _testCleanup($section_text, $temp_clean)
  62370. {
  62371. if ($section_text['CLEAN']) {
  62372. $this->_restorePHPBinary();
  62373. // perform test cleanup
  62374. $this->save_text($temp_clean, $section_text['CLEAN']);
  62375. $output = $this->system_with_timeout("$this->_php $temp_clean 2>&1");
  62376. if (strlen($output[1])) {
  62377. echo "BORKED --CLEAN-- section! output:\n", $output[1];
  62378. }
  62379. if (file_exists($temp_clean)) {
  62380. unlink($temp_clean);
  62381. }
  62382. }
  62383. }
  62384. function _savePHPBinary()
  62385. {
  62386. $this->_savephp = $this->_php;
  62387. }
  62388. function _restorePHPBinary()
  62389. {
  62390. if (isset($this->_savephp))
  62391. {
  62392. $this->_php = $this->_savephp;
  62393. unset($this->_savephp);
  62394. }
  62395. }
  62396. }
  62397. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR/Validate.php����������������������������������������������������������������������0000644�0001750�0001750�00000052765�13565304531�015266� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  62398. /**
  62399. * PEAR_Validate
  62400. *
  62401. * PHP versions 4 and 5
  62402. *
  62403. * @category pear
  62404. * @package PEAR
  62405. * @author Greg Beaver <cellog@php.net>
  62406. * @copyright 1997-2009 The Authors
  62407. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  62408. * @link http://pear.php.net/package/PEAR
  62409. * @since File available since Release 1.4.0a1
  62410. */
  62411. /**#@+
  62412. * Constants for install stage
  62413. */
  62414. define('PEAR_VALIDATE_INSTALLING', 1);
  62415. define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others
  62416. define('PEAR_VALIDATE_NORMAL', 3);
  62417. define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others
  62418. define('PEAR_VALIDATE_PACKAGING', 7);
  62419. /**#@-*/
  62420. require_once 'PEAR/Common.php';
  62421. require_once 'PEAR/Validator/PECL.php';
  62422. /**
  62423. * Validation class for package.xml - channel-level advanced validation
  62424. * @category pear
  62425. * @package PEAR
  62426. * @author Greg Beaver <cellog@php.net>
  62427. * @copyright 1997-2009 The Authors
  62428. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  62429. * @version Release: 1.10.10
  62430. * @link http://pear.php.net/package/PEAR
  62431. * @since Class available since Release 1.4.0a1
  62432. */
  62433. class PEAR_Validate
  62434. {
  62435. var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG;
  62436. /**
  62437. * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2
  62438. */
  62439. var $_packagexml;
  62440. /**
  62441. * @var int one of the PEAR_VALIDATE_* constants
  62442. */
  62443. var $_state = PEAR_VALIDATE_NORMAL;
  62444. /**
  62445. * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same)
  62446. * @var array
  62447. * @access private
  62448. */
  62449. var $_failures = array('error' => array(), 'warning' => array());
  62450. /**
  62451. * Override this method to handle validation of normal package names
  62452. * @param string
  62453. * @return bool
  62454. * @access protected
  62455. */
  62456. function _validPackageName($name)
  62457. {
  62458. return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name);
  62459. }
  62460. /**
  62461. * @param string package name to validate
  62462. * @param string name of channel-specific validation package
  62463. * @final
  62464. */
  62465. function validPackageName($name, $validatepackagename = false)
  62466. {
  62467. if ($validatepackagename) {
  62468. if (strtolower($name) == strtolower($validatepackagename)) {
  62469. return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name);
  62470. }
  62471. }
  62472. return $this->_validPackageName($name);
  62473. }
  62474. /**
  62475. * This validates a bundle name, and bundle names must conform
  62476. * to the PEAR naming convention, so the method is final and static.
  62477. * @param string
  62478. * @final
  62479. */
  62480. public static function validGroupName($name)
  62481. {
  62482. return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name);
  62483. }
  62484. /**
  62485. * Determine whether $state represents a valid stability level
  62486. * @param string
  62487. * @return bool
  62488. * @final
  62489. */
  62490. public static function validState($state)
  62491. {
  62492. return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable'));
  62493. }
  62494. /**
  62495. * Get a list of valid stability levels
  62496. * @return array
  62497. * @final
  62498. */
  62499. public static function getValidStates()
  62500. {
  62501. return array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  62502. }
  62503. /**
  62504. * Determine whether a version is a properly formatted version number that can be used
  62505. * by version_compare
  62506. * @param string
  62507. * @return bool
  62508. * @final
  62509. */
  62510. public static function validVersion($ver)
  62511. {
  62512. return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
  62513. }
  62514. /**
  62515. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  62516. */
  62517. function setPackageFile(&$pf)
  62518. {
  62519. $this->_packagexml = &$pf;
  62520. }
  62521. /**
  62522. * @access private
  62523. */
  62524. function _addFailure($field, $reason)
  62525. {
  62526. $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason);
  62527. }
  62528. /**
  62529. * @access private
  62530. */
  62531. function _addWarning($field, $reason)
  62532. {
  62533. $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason);
  62534. }
  62535. function getFailures()
  62536. {
  62537. $failures = $this->_failures;
  62538. $this->_failures = array('warnings' => array(), 'errors' => array());
  62539. return $failures;
  62540. }
  62541. /**
  62542. * @param int one of the PEAR_VALIDATE_* constants
  62543. */
  62544. function validate($state = null)
  62545. {
  62546. if (!isset($this->_packagexml)) {
  62547. return false;
  62548. }
  62549. if ($state !== null) {
  62550. $this->_state = $state;
  62551. }
  62552. $this->_failures = array('warnings' => array(), 'errors' => array());
  62553. $this->validatePackageName();
  62554. $this->validateVersion();
  62555. $this->validateMaintainers();
  62556. $this->validateDate();
  62557. $this->validateSummary();
  62558. $this->validateDescription();
  62559. $this->validateLicense();
  62560. $this->validateNotes();
  62561. if ($this->_packagexml->getPackagexmlVersion() == '1.0') {
  62562. $this->validateState();
  62563. $this->validateFilelist();
  62564. } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' ||
  62565. $this->_packagexml->getPackagexmlVersion() == '2.1') {
  62566. $this->validateTime();
  62567. $this->validateStability();
  62568. $this->validateDeps();
  62569. $this->validateMainFilelist();
  62570. $this->validateReleaseFilelist();
  62571. //$this->validateGlobalTasks();
  62572. $this->validateChangelog();
  62573. }
  62574. return !((bool) count($this->_failures['errors']));
  62575. }
  62576. /**
  62577. * @access protected
  62578. */
  62579. function validatePackageName()
  62580. {
  62581. if ($this->_state == PEAR_VALIDATE_PACKAGING ||
  62582. $this->_state == PEAR_VALIDATE_NORMAL) {
  62583. if (($this->_packagexml->getPackagexmlVersion() == '2.0' ||
  62584. $this->_packagexml->getPackagexmlVersion() == '2.1') &&
  62585. $this->_packagexml->getExtends()) {
  62586. $version = $this->_packagexml->getVersion() . '';
  62587. $name = $this->_packagexml->getPackage();
  62588. $a = explode('.', $version);
  62589. $test = array_shift($a);
  62590. if ($test == '0') {
  62591. return true;
  62592. }
  62593. $vlen = strlen($test);
  62594. $majver = substr($name, strlen($name) - $vlen);
  62595. while ($majver && !is_numeric($majver[0])) {
  62596. $majver = substr($majver, 1);
  62597. }
  62598. if ($majver != $test) {
  62599. $this->_addWarning('package', "package $name extends package " .
  62600. $this->_packagexml->getExtends() . ' and so the name should ' .
  62601. 'have a postfix equal to the major version like "' .
  62602. $this->_packagexml->getExtends() . $test . '"');
  62603. return true;
  62604. } elseif (substr($name, 0, strlen($name) - $vlen) !=
  62605. $this->_packagexml->getExtends()) {
  62606. $this->_addWarning('package', "package $name extends package " .
  62607. $this->_packagexml->getExtends() . ' and so the name must ' .
  62608. 'be an extension like "' . $this->_packagexml->getExtends() .
  62609. $test . '"');
  62610. return true;
  62611. }
  62612. }
  62613. }
  62614. if (!$this->validPackageName($this->_packagexml->getPackage())) {
  62615. $this->_addFailure('name', 'package name "' .
  62616. $this->_packagexml->getPackage() . '" is invalid');
  62617. return false;
  62618. }
  62619. }
  62620. /**
  62621. * @access protected
  62622. */
  62623. function validateVersion()
  62624. {
  62625. if ($this->_state != PEAR_VALIDATE_PACKAGING) {
  62626. if (!$this->validVersion($this->_packagexml->getVersion())) {
  62627. $this->_addFailure('version',
  62628. 'Invalid version number "' . $this->_packagexml->getVersion() . '"');
  62629. }
  62630. return false;
  62631. }
  62632. $version = $this->_packagexml->getVersion();
  62633. $versioncomponents = explode('.', $version);
  62634. if (count($versioncomponents) != 3) {
  62635. $this->_addWarning('version',
  62636. 'A version number should have 3 decimals (x.y.z)');
  62637. return true;
  62638. }
  62639. $name = $this->_packagexml->getPackage();
  62640. // version must be based upon state
  62641. switch ($this->_packagexml->getState()) {
  62642. case 'snapshot' :
  62643. return true;
  62644. case 'devel' :
  62645. if ($versioncomponents[0] . 'a' == '0a') {
  62646. return true;
  62647. }
  62648. if ($versioncomponents[0] == 0) {
  62649. $versioncomponents[0] = '0';
  62650. $this->_addWarning('version',
  62651. 'version "' . $version . '" should be "' .
  62652. implode('.' ,$versioncomponents) . '"');
  62653. } else {
  62654. $this->_addWarning('version',
  62655. 'packages with devel stability must be < version 1.0.0');
  62656. }
  62657. return true;
  62658. break;
  62659. case 'alpha' :
  62660. case 'beta' :
  62661. // check for a package that extends a package,
  62662. // like Foo and Foo2
  62663. if ($this->_state == PEAR_VALIDATE_PACKAGING) {
  62664. if (substr($versioncomponents[2], 1, 2) == 'rc') {
  62665. $this->_addFailure('version', 'Release Candidate versions ' .
  62666. 'must have capital RC, not lower-case rc');
  62667. return false;
  62668. }
  62669. }
  62670. if (!$this->_packagexml->getExtends()) {
  62671. if ($versioncomponents[0] == '1') {
  62672. if ($versioncomponents[2][0] == '0') {
  62673. if ($versioncomponents[2] == '0') {
  62674. // version 1.*.0000
  62675. $this->_addWarning('version',
  62676. 'version 1.' . $versioncomponents[1] .
  62677. '.0 probably should not be alpha or beta');
  62678. return true;
  62679. } elseif (strlen($versioncomponents[2]) > 1) {
  62680. // version 1.*.0RC1 or 1.*.0beta24 etc.
  62681. return true;
  62682. } else {
  62683. // version 1.*.0
  62684. $this->_addWarning('version',
  62685. 'version 1.' . $versioncomponents[1] .
  62686. '.0 probably should not be alpha or beta');
  62687. return true;
  62688. }
  62689. } else {
  62690. $this->_addWarning('version',
  62691. 'bugfix versions (1.3.x where x > 0) probably should ' .
  62692. 'not be alpha or beta');
  62693. return true;
  62694. }
  62695. } elseif ($versioncomponents[0] != '0') {
  62696. $this->_addWarning('version',
  62697. 'major versions greater than 1 are not allowed for packages ' .
  62698. 'without an <extends> tag or an identical postfix (foo2 v2.0.0)');
  62699. return true;
  62700. }
  62701. if ($versioncomponents[0] . 'a' == '0a') {
  62702. return true;
  62703. }
  62704. if ($versioncomponents[0] == 0) {
  62705. $versioncomponents[0] = '0';
  62706. $this->_addWarning('version',
  62707. 'version "' . $version . '" should be "' .
  62708. implode('.' ,$versioncomponents) . '"');
  62709. }
  62710. } else {
  62711. $vlen = strlen($versioncomponents[0] . '');
  62712. $majver = substr($name, strlen($name) - $vlen);
  62713. while ($majver && !is_numeric($majver[0])) {
  62714. $majver = substr($majver, 1);
  62715. }
  62716. if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
  62717. $this->_addWarning('version', 'first version number "' .
  62718. $versioncomponents[0] . '" must match the postfix of ' .
  62719. 'package name "' . $name . '" (' .
  62720. $majver . ')');
  62721. return true;
  62722. }
  62723. if ($versioncomponents[0] == $majver) {
  62724. if ($versioncomponents[2][0] == '0') {
  62725. if ($versioncomponents[2] == '0') {
  62726. // version 2.*.0000
  62727. $this->_addWarning('version',
  62728. "version $majver." . $versioncomponents[1] .
  62729. '.0 probably should not be alpha or beta');
  62730. return false;
  62731. } elseif (strlen($versioncomponents[2]) > 1) {
  62732. // version 2.*.0RC1 or 2.*.0beta24 etc.
  62733. return true;
  62734. } else {
  62735. // version 2.*.0
  62736. $this->_addWarning('version',
  62737. "version $majver." . $versioncomponents[1] .
  62738. '.0 cannot be alpha or beta');
  62739. return true;
  62740. }
  62741. } else {
  62742. $this->_addWarning('version',
  62743. "bugfix versions ($majver.x.y where y > 0) should " .
  62744. 'not be alpha or beta');
  62745. return true;
  62746. }
  62747. } elseif ($versioncomponents[0] != '0') {
  62748. $this->_addWarning('version',
  62749. "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases");
  62750. return true;
  62751. }
  62752. if ($versioncomponents[0] . 'a' == '0a') {
  62753. return true;
  62754. }
  62755. if ($versioncomponents[0] == 0) {
  62756. $versioncomponents[0] = '0';
  62757. $this->_addWarning('version',
  62758. 'version "' . $version . '" should be "' .
  62759. implode('.' ,$versioncomponents) . '"');
  62760. }
  62761. }
  62762. return true;
  62763. break;
  62764. case 'stable' :
  62765. if ($versioncomponents[0] == '0') {
  62766. $this->_addWarning('version', 'versions less than 1.0.0 cannot ' .
  62767. 'be stable');
  62768. return true;
  62769. }
  62770. if (!is_numeric($versioncomponents[2])) {
  62771. if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i',
  62772. $versioncomponents[2])) {
  62773. $this->_addWarning('version', 'version "' . $version . '" or any ' .
  62774. 'RC/beta/alpha version cannot be stable');
  62775. return true;
  62776. }
  62777. }
  62778. // check for a package that extends a package,
  62779. // like Foo and Foo2
  62780. if ($this->_packagexml->getExtends()) {
  62781. $vlen = strlen($versioncomponents[0] . '');
  62782. $majver = substr($name, strlen($name) - $vlen);
  62783. while ($majver && !is_numeric($majver[0])) {
  62784. $majver = substr($majver, 1);
  62785. }
  62786. if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
  62787. $this->_addWarning('version', 'first version number "' .
  62788. $versioncomponents[0] . '" must match the postfix of ' .
  62789. 'package name "' . $name . '" (' .
  62790. $majver . ')');
  62791. return true;
  62792. }
  62793. } elseif ($versioncomponents[0] > 1) {
  62794. $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' .
  62795. '1 for any package that does not have an <extends> tag');
  62796. }
  62797. return true;
  62798. break;
  62799. default :
  62800. return false;
  62801. break;
  62802. }
  62803. }
  62804. /**
  62805. * @access protected
  62806. */
  62807. function validateMaintainers()
  62808. {
  62809. // maintainers can only be truly validated server-side for most channels
  62810. // but allow this customization for those who wish it
  62811. return true;
  62812. }
  62813. /**
  62814. * @access protected
  62815. */
  62816. function validateDate()
  62817. {
  62818. if ($this->_state == PEAR_VALIDATE_NORMAL ||
  62819. $this->_state == PEAR_VALIDATE_PACKAGING) {
  62820. if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/',
  62821. $this->_packagexml->getDate(), $res) ||
  62822. count($res) < 4
  62823. || !checkdate($res[2], $res[3], $res[1])
  62824. ) {
  62825. $this->_addFailure('date', 'invalid release date "' .
  62826. $this->_packagexml->getDate() . '"');
  62827. return false;
  62828. }
  62829. if ($this->_state == PEAR_VALIDATE_PACKAGING &&
  62830. $this->_packagexml->getDate() != date('Y-m-d')) {
  62831. $this->_addWarning('date', 'Release Date "' .
  62832. $this->_packagexml->getDate() . '" is not today');
  62833. }
  62834. }
  62835. return true;
  62836. }
  62837. /**
  62838. * @access protected
  62839. */
  62840. function validateTime()
  62841. {
  62842. if (!$this->_packagexml->getTime()) {
  62843. // default of no time value set
  62844. return true;
  62845. }
  62846. // packager automatically sets time, so only validate if pear validate is called
  62847. if ($this->_state = PEAR_VALIDATE_NORMAL) {
  62848. if (!preg_match('/\d\d:\d\d:\d\d/',
  62849. $this->_packagexml->getTime())) {
  62850. $this->_addFailure('time', 'invalid release time "' .
  62851. $this->_packagexml->getTime() . '"');
  62852. return false;
  62853. }
  62854. $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches);
  62855. if ($result === false || empty($matches)) {
  62856. $this->_addFailure('time', 'invalid release time "' .
  62857. $this->_packagexml->getTime() . '"');
  62858. return false;
  62859. }
  62860. }
  62861. return true;
  62862. }
  62863. /**
  62864. * @access protected
  62865. */
  62866. function validateState()
  62867. {
  62868. // this is the closest to "final" php4 can get
  62869. if (!PEAR_Validate::validState($this->_packagexml->getState())) {
  62870. if (strtolower($this->_packagexml->getState() == 'rc')) {
  62871. $this->_addFailure('state', 'RC is not a state, it is a version ' .
  62872. 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta');
  62873. }
  62874. $this->_addFailure('state', 'invalid release state "' .
  62875. $this->_packagexml->getState() . '", must be one of: ' .
  62876. implode(', ', PEAR_Validate::getValidStates()));
  62877. return false;
  62878. }
  62879. return true;
  62880. }
  62881. /**
  62882. * @access protected
  62883. */
  62884. function validateStability()
  62885. {
  62886. $ret = true;
  62887. $packagestability = $this->_packagexml->getState();
  62888. $apistability = $this->_packagexml->getState('api');
  62889. if (!PEAR_Validate::validState($packagestability)) {
  62890. $this->_addFailure('state', 'invalid release stability "' .
  62891. $this->_packagexml->getState() . '", must be one of: ' .
  62892. implode(', ', PEAR_Validate::getValidStates()));
  62893. $ret = false;
  62894. }
  62895. $apistates = PEAR_Validate::getValidStates();
  62896. array_shift($apistates); // snapshot is not allowed
  62897. if (!in_array($apistability, $apistates)) {
  62898. $this->_addFailure('state', 'invalid API stability "' .
  62899. $this->_packagexml->getState('api') . '", must be one of: ' .
  62900. implode(', ', $apistates));
  62901. $ret = false;
  62902. }
  62903. return $ret;
  62904. }
  62905. /**
  62906. * @access protected
  62907. */
  62908. function validateSummary()
  62909. {
  62910. return true;
  62911. }
  62912. /**
  62913. * @access protected
  62914. */
  62915. function validateDescription()
  62916. {
  62917. return true;
  62918. }
  62919. /**
  62920. * @access protected
  62921. */
  62922. function validateLicense()
  62923. {
  62924. return true;
  62925. }
  62926. /**
  62927. * @access protected
  62928. */
  62929. function validateNotes()
  62930. {
  62931. return true;
  62932. }
  62933. /**
  62934. * for package.xml 2.0 only - channels can't use package.xml 1.0
  62935. * @access protected
  62936. */
  62937. function validateDependencies()
  62938. {
  62939. return true;
  62940. }
  62941. /**
  62942. * for package.xml 1.0 only
  62943. * @access private
  62944. */
  62945. function _validateFilelist()
  62946. {
  62947. return true; // placeholder for now
  62948. }
  62949. /**
  62950. * for package.xml 2.0 only
  62951. * @access protected
  62952. */
  62953. function validateMainFilelist()
  62954. {
  62955. return true; // placeholder for now
  62956. }
  62957. /**
  62958. * for package.xml 2.0 only
  62959. * @access protected
  62960. */
  62961. function validateReleaseFilelist()
  62962. {
  62963. return true; // placeholder for now
  62964. }
  62965. /**
  62966. * @access protected
  62967. */
  62968. function validateChangelog()
  62969. {
  62970. return true;
  62971. }
  62972. /**
  62973. * @access protected
  62974. */
  62975. function validateFilelist()
  62976. {
  62977. return true;
  62978. }
  62979. /**
  62980. * @access protected
  62981. */
  62982. function validateDeps()
  62983. {
  62984. return true;
  62985. }
  62986. }�����������PEAR-1.10.10/PEAR/XMLParser.php���������������������������������������������������������������������0000644�0001750�0001750�00000015377�13565304531�015350� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  62987. /**
  62988. * PEAR_XMLParser
  62989. *
  62990. * PHP versions 4 and 5
  62991. *
  62992. * @category pear
  62993. * @package PEAR
  62994. * @author Greg Beaver <cellog@php.net>
  62995. * @author Stephan Schmidt (original XML_Unserializer code)
  62996. * @copyright 1997-2009 The Authors
  62997. * @license http://opensource.org/licenses/bsd-license New BSD License
  62998. * @link http://pear.php.net/package/PEAR
  62999. * @since File available since Release 1.4.0a1
  63000. */
  63001. /**
  63002. * Parser for any xml file
  63003. * @category pear
  63004. * @package PEAR
  63005. * @author Greg Beaver <cellog@php.net>
  63006. * @author Stephan Schmidt (original XML_Unserializer code)
  63007. * @copyright 1997-2009 The Authors
  63008. * @license http://opensource.org/licenses/bsd-license New BSD License
  63009. * @version Release: 1.10.10
  63010. * @link http://pear.php.net/package/PEAR
  63011. * @since Class available since Release 1.4.0a1
  63012. */
  63013. class PEAR_XMLParser
  63014. {
  63015. /**
  63016. * unserilialized data
  63017. * @var string $_serializedData
  63018. */
  63019. var $_unserializedData = null;
  63020. /**
  63021. * name of the root tag
  63022. * @var string $_root
  63023. */
  63024. var $_root = null;
  63025. /**
  63026. * stack for all data that is found
  63027. * @var array $_dataStack
  63028. */
  63029. var $_dataStack = array();
  63030. /**
  63031. * stack for all values that are generated
  63032. * @var array $_valStack
  63033. */
  63034. var $_valStack = array();
  63035. /**
  63036. * current tag depth
  63037. * @var int $_depth
  63038. */
  63039. var $_depth = 0;
  63040. /**
  63041. * The XML encoding to use
  63042. * @var string $encoding
  63043. */
  63044. var $encoding = 'ISO-8859-1';
  63045. /**
  63046. * @return array
  63047. */
  63048. function getData()
  63049. {
  63050. return $this->_unserializedData;
  63051. }
  63052. /**
  63053. * @param string xml content
  63054. * @return true|PEAR_Error
  63055. */
  63056. function parse($data)
  63057. {
  63058. if (!extension_loaded('xml')) {
  63059. include_once 'PEAR.php';
  63060. return PEAR::raiseError("XML Extension not found", 1);
  63061. }
  63062. $this->_dataStack = $this->_valStack = array();
  63063. $this->_depth = 0;
  63064. if (
  63065. strpos($data, 'encoding="UTF-8"')
  63066. || strpos($data, 'encoding="utf-8"')
  63067. || strpos($data, "encoding='UTF-8'")
  63068. || strpos($data, "encoding='utf-8'")
  63069. ) {
  63070. $this->encoding = 'UTF-8';
  63071. }
  63072. $xp = xml_parser_create($this->encoding);
  63073. xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0);
  63074. xml_set_object($xp, $this);
  63075. xml_set_element_handler($xp, 'startHandler', 'endHandler');
  63076. xml_set_character_data_handler($xp, 'cdataHandler');
  63077. if (!xml_parse($xp, $data)) {
  63078. $msg = xml_error_string(xml_get_error_code($xp));
  63079. $line = xml_get_current_line_number($xp);
  63080. xml_parser_free($xp);
  63081. include_once 'PEAR.php';
  63082. return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2);
  63083. }
  63084. xml_parser_free($xp);
  63085. return true;
  63086. }
  63087. /**
  63088. * Start element handler for XML parser
  63089. *
  63090. * @access private
  63091. * @param object $parser XML parser object
  63092. * @param string $element XML element
  63093. * @param array $attribs attributes of XML tag
  63094. * @return void
  63095. */
  63096. function startHandler($parser, $element, $attribs)
  63097. {
  63098. $this->_depth++;
  63099. $this->_dataStack[$this->_depth] = null;
  63100. $val = array(
  63101. 'name' => $element,
  63102. 'value' => null,
  63103. 'type' => 'string',
  63104. 'childrenKeys' => array(),
  63105. 'aggregKeys' => array()
  63106. );
  63107. if (count($attribs) > 0) {
  63108. $val['children'] = array();
  63109. $val['type'] = 'array';
  63110. $val['children']['attribs'] = $attribs;
  63111. }
  63112. array_push($this->_valStack, $val);
  63113. }
  63114. /**
  63115. * post-process data
  63116. *
  63117. * @param string $data
  63118. * @param string $element element name
  63119. */
  63120. function postProcess($data, $element)
  63121. {
  63122. return trim($data);
  63123. }
  63124. /**
  63125. * End element handler for XML parser
  63126. *
  63127. * @access private
  63128. * @param object XML parser object
  63129. * @param string
  63130. * @return void
  63131. */
  63132. function endHandler($parser, $element)
  63133. {
  63134. $value = array_pop($this->_valStack);
  63135. $data = $this->postProcess($this->_dataStack[$this->_depth], $element);
  63136. // adjust type of the value
  63137. switch (strtolower($value['type'])) {
  63138. // unserialize an array
  63139. case 'array':
  63140. if ($data !== '') {
  63141. $value['children']['_content'] = $data;
  63142. }
  63143. $value['value'] = isset($value['children']) ? $value['children'] : array();
  63144. break;
  63145. /*
  63146. * unserialize a null value
  63147. */
  63148. case 'null':
  63149. $data = null;
  63150. break;
  63151. /*
  63152. * unserialize any scalar value
  63153. */
  63154. default:
  63155. settype($data, $value['type']);
  63156. $value['value'] = $data;
  63157. break;
  63158. }
  63159. $parent = array_pop($this->_valStack);
  63160. if ($parent === null) {
  63161. $this->_unserializedData = &$value['value'];
  63162. $this->_root = &$value['name'];
  63163. return true;
  63164. }
  63165. // parent has to be an array
  63166. if (!isset($parent['children']) || !is_array($parent['children'])) {
  63167. $parent['children'] = array();
  63168. if ($parent['type'] != 'array') {
  63169. $parent['type'] = 'array';
  63170. }
  63171. }
  63172. if (!empty($value['name'])) {
  63173. // there already has been a tag with this name
  63174. if (in_array($value['name'], $parent['childrenKeys'])) {
  63175. // no aggregate has been created for this tag
  63176. if (!in_array($value['name'], $parent['aggregKeys'])) {
  63177. if (isset($parent['children'][$value['name']])) {
  63178. $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
  63179. } else {
  63180. $parent['children'][$value['name']] = array();
  63181. }
  63182. array_push($parent['aggregKeys'], $value['name']);
  63183. }
  63184. array_push($parent['children'][$value['name']], $value['value']);
  63185. } else {
  63186. $parent['children'][$value['name']] = &$value['value'];
  63187. array_push($parent['childrenKeys'], $value['name']);
  63188. }
  63189. } else {
  63190. array_push($parent['children'],$value['value']);
  63191. }
  63192. array_push($this->_valStack, $parent);
  63193. $this->_depth--;
  63194. }
  63195. /**
  63196. * Handler for character data
  63197. *
  63198. * @access private
  63199. * @param object XML parser object
  63200. * @param string CDATA
  63201. * @return void
  63202. */
  63203. function cdataHandler($parser, $cdata)
  63204. {
  63205. $this->_dataStack[$this->_depth] .= $cdata;
  63206. }
  63207. }�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/pear.bat�����������������������������������������������������������������������0000755�0001750�0001750�00000010361�13565304531�015370� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@ECHO OFF
  63208. REM ----------------------------------------------------------------------
  63209. REM PHP version 5
  63210. REM ----------------------------------------------------------------------
  63211. REM Copyright (c) 1997-2010 The Authors
  63212. REM ----------------------------------------------------------------------
  63213. REM http://opensource.org/licenses/bsd-license.php New BSD License
  63214. REM ----------------------------------------------------------------------
  63215. REM Authors: Alexander Merz (alexmerz@php.net)
  63216. REM ----------------------------------------------------------------------
  63217. REM
  63218. REM Last updated 12/29/2004 ($Id$ is not replaced if the file is binary)
  63219. REM change this lines to match the paths of your system
  63220. REM -------------------
  63221. REM Test to see if this is a raw pear.bat (uninstalled version)
  63222. SET TMPTMPTMPTMPT=@includ
  63223. SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@
  63224. FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED)
  63225. REM Check PEAR global ENV, set them if they do not exist
  63226. IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@"
  63227. IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@"
  63228. IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@"
  63229. GOTO :INSTALLED
  63230. :NOTINSTALLED
  63231. ECHO WARNING: This is a raw, uninstalled pear.bat
  63232. REM Check to see if we can grab the directory of this file (Windows NT+)
  63233. IF %~n0 == pear (
  63234. FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" (
  63235. SET "PHP_PEAR_PHP_BIN=%%~$PATH:x"
  63236. echo Using PHP Executable "%PHP_PEAR_PHP_BIN%"
  63237. "%PHP_PEAR_PHP_BIN%" -v
  63238. GOTO :NEXTTEST
  63239. ))
  63240. GOTO :FAILAUTODETECT
  63241. :NEXTTEST
  63242. IF "%PHP_PEAR_PHP_BIN%" NEQ "" (
  63243. REM We can use this PHP to run a temporary php file to get the dirname of pear
  63244. echo ^<?php $s=getcwd^(^);chdir^($a=dirname^(__FILE__^).'\\'^);if^(stristr^($a,'\\scripts'^)^)$a=dirname^(dirname^($a^)^).'\\';$f=fopen^($s.'\\~a.a','wb'^);echo$s.'\\~a.a';fwrite^($f,$a^);fclose^($f^);chdir^($s^);?^> > ~~getloc.php
  63245. "%PHP_PEAR_PHP_BIN%" ~~getloc.php
  63246. set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a
  63247. DEL ~a.a
  63248. DEL ~~getloc.php
  63249. set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear"
  63250. REM Make sure there is a pearcmd.php at our disposal
  63251. IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php (
  63252. IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63253. IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63254. IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63255. )
  63256. )
  63257. GOTO :INSTALLED
  63258. ) ELSE (
  63259. REM Windows Me/98 cannot succeed, so allow the batch to fail
  63260. )
  63261. :FAILAUTODETECT
  63262. echo WARNING: failed to auto-detect pear information
  63263. :INSTALLED
  63264. REM Check Folders and files
  63265. IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR
  63266. IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2
  63267. IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR
  63268. IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR
  63269. REM launch pearcmd
  63270. GOTO RUN
  63271. :PEAR_INSTALL_ERROR
  63272. ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
  63273. ECHO Please fix it using your environment variable or modify
  63274. ECHO the default value in pear.bat
  63275. ECHO The current value is:
  63276. ECHO %PHP_PEAR_INSTALL_DIR%
  63277. GOTO END
  63278. :PEAR_INSTALL_ERROR2
  63279. ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
  63280. ECHO pearcmd.php could not be found there.
  63281. ECHO Please fix it using your environment variable or modify
  63282. ECHO the default value in pear.bat
  63283. ECHO The current value is:
  63284. ECHO %PHP_PEAR_INSTALL_DIR%
  63285. GOTO END
  63286. :PEAR_BIN_ERROR
  63287. ECHO PHP_PEAR_BIN_DIR is not set correctly.
  63288. ECHO Please fix it using your environment variable or modify
  63289. ECHO the default value in pear.bat
  63290. ECHO The current value is:
  63291. ECHO %PHP_PEAR_BIN_DIR%
  63292. GOTO END
  63293. :PEAR_PHPBIN_ERROR
  63294. ECHO PHP_PEAR_PHP_BIN is not set correctly.
  63295. ECHO Please fix it using your environment variable or modify
  63296. ECHO the default value in pear.bat
  63297. ECHO The current value is:
  63298. ECHO %PHP_PEAR_PHP_BIN%
  63299. GOTO END
  63300. :RUN
  63301. "%PHP_PEAR_PHP_BIN%" -C -d date.timezone=UTC -d output_buffering=1 -d safe_mode=0 -d open_basedir="" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d register_argc_argv="On" -d "include_path='%PHP_PEAR_INSTALL_DIR%'" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9
  63302. :END
  63303. @ECHO ON�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/peardev.bat��������������������������������������������������������������������0000644�0001750�0001750�00000011137�13565304531�016066� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@ECHO OFF
  63304. REM ----------------------------------------------------------------------
  63305. REM PHP version 5
  63306. REM ----------------------------------------------------------------------
  63307. REM Copyright (c) 1997-2004 The PHP Group
  63308. REM ----------------------------------------------------------------------
  63309. REM This source file is subject to version 3.0 of the PHP license,
  63310. REM that is bundled with this package in the file LICENSE, and is
  63311. REM available at through the world-wide-web at
  63312. REM http://www.php.net/license/3_0.txt.
  63313. REM If you did not receive a copy of the PHP license and are unable to
  63314. REM obtain it through the world-wide-web, please send a note to
  63315. REM license@php.net so we can mail you a copy immediately.
  63316. REM ----------------------------------------------------------------------
  63317. REM Authors: Alexander Merz (alexmerz@php.net)
  63318. REM ----------------------------------------------------------------------
  63319. REM
  63320. REM $Id: peardev.bat,v 1.6 2007-09-03 03:00:17 cellog Exp $
  63321. REM change this lines to match the paths of your system
  63322. REM -------------------
  63323. REM Test to see if this is a raw pear.bat (uninstalled version)
  63324. SET TMPTMPTMPTMPT=@includ
  63325. SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@
  63326. FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED)
  63327. REM Check PEAR global ENV, set them if they do not exist
  63328. IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@"
  63329. IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@"
  63330. IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@"
  63331. GOTO :INSTALLED
  63332. :NOTINSTALLED
  63333. ECHO WARNING: This is a raw, uninstalled pear.bat
  63334. REM Check to see if we can grab the directory of this file (Windows NT+)
  63335. IF %~n0 == pear (
  63336. FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" (
  63337. SET "PHP_PEAR_PHP_BIN=%%~$PATH:x"
  63338. echo Using PHP Executable "%PHP_PEAR_PHP_BIN%"
  63339. "%PHP_PEAR_PHP_BIN%" -v
  63340. GOTO :NEXTTEST
  63341. ))
  63342. GOTO :FAILAUTODETECT
  63343. :NEXTTEST
  63344. IF "%PHP_PEAR_PHP_BIN%" NEQ "" (
  63345. REM We can use this PHP to run a temporary php file to get the dirname of pear
  63346. echo ^<?php $s=getcwd^(^);chdir^($a=dirname^(__FILE__^).'\\'^);if^(stristr^($a,'\\scripts'^)^)$a=dirname^(dirname^($a^)^).'\\';$f=fopen^($s.'\\~a.a','wb'^);echo$s.'\\~a.a';fwrite^($f,$a^);fclose^($f^);chdir^($s^);?^> > ~~getloc.php
  63347. "%PHP_PEAR_PHP_BIN%" ~~getloc.php
  63348. set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a
  63349. DEL ~a.a
  63350. DEL ~~getloc.php
  63351. set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear"
  63352. REM Make sure there is a pearcmd.php at our disposal
  63353. IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php (
  63354. IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63355. IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63356. IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63357. )
  63358. )
  63359. GOTO :INSTALLED
  63360. ) ELSE (
  63361. REM Windows Me/98 cannot succeed, so allow the batch to fail
  63362. )
  63363. :FAILAUTODETECT
  63364. echo WARNING: failed to auto-detect pear information
  63365. :INSTALLED
  63366. REM Check Folders and files
  63367. IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR
  63368. IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2
  63369. IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR
  63370. IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR
  63371. REM launch pearcmd
  63372. GOTO RUN
  63373. :PEAR_INSTALL_ERROR
  63374. ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
  63375. ECHO Please fix it using your environment variable or modify
  63376. ECHO the default value in pear.bat
  63377. ECHO The current value is:
  63378. ECHO %PHP_PEAR_INSTALL_DIR%
  63379. GOTO END
  63380. :PEAR_INSTALL_ERROR2
  63381. ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
  63382. ECHO pearcmd.php could not be found there.
  63383. ECHO Please fix it using your environment variable or modify
  63384. ECHO the default value in pear.bat
  63385. ECHO The current value is:
  63386. ECHO %PHP_PEAR_INSTALL_DIR%
  63387. GOTO END
  63388. :PEAR_BIN_ERROR
  63389. ECHO PHP_PEAR_BIN_DIR is not set correctly.
  63390. ECHO Please fix it using your environment variable or modify
  63391. ECHO the default value in pear.bat
  63392. ECHO The current value is:
  63393. ECHO %PHP_PEAR_BIN_DIR%
  63394. GOTO END
  63395. :PEAR_PHPBIN_ERROR
  63396. ECHO PHP_PEAR_PHP_BIN is not set correctly.
  63397. ECHO Please fix it using your environment variable or modify
  63398. ECHO the default value in pear.bat
  63399. ECHO The current value is:
  63400. ECHO %PHP_PEAR_PHP_BIN%
  63401. GOTO END
  63402. :RUN
  63403. "%PHP_PEAR_PHP_BIN%" -C -d date.timezone=UTC -d memory_limit="-1" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d open_basedir="" -d output_buffering=1 -d "include_path='%PHP_PEAR_INSTALL_DIR%'" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9
  63404. :END
  63405. @ECHO ON���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/pecl.bat�����������������������������������������������������������������������0000644�0001750�0001750�00000011030�13565304531�015353� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@ECHO OFF
  63406. REM ----------------------------------------------------------------------
  63407. REM PHP version 5
  63408. REM ----------------------------------------------------------------------
  63409. REM Copyright (c) 1997-2004 The PHP Group
  63410. REM ----------------------------------------------------------------------
  63411. REM This source file is subject to version 3.0 of the PHP license,
  63412. REM that is bundled with this package in the file LICENSE, and is
  63413. REM available at through the world-wide-web at
  63414. REM http://www.php.net/license/3_0.txt.
  63415. REM If you did not receive a copy of the PHP license and are unable to
  63416. REM obtain it through the world-wide-web, please send a note to
  63417. REM license@php.net so we can mail you a copy immediately.
  63418. REM ----------------------------------------------------------------------
  63419. REM Authors: Alexander Merz (alexmerz@php.net)
  63420. REM ----------------------------------------------------------------------
  63421. REM
  63422. REM Last updated 02/08/2004 ($Id$ is not replaced if the file is binary)
  63423. REM change this lines to match the paths of your system
  63424. REM -------------------
  63425. REM Test to see if this is a raw pear.bat (uninstalled version)
  63426. SET TMPTMPTMPTMPT=@includ
  63427. SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@
  63428. FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED)
  63429. REM Check PEAR global ENV, set them if they do not exist
  63430. IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@"
  63431. IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@"
  63432. IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@"
  63433. GOTO :INSTALLED
  63434. :NOTINSTALLED
  63435. ECHO WARNING: This is a raw, uninstalled pear.bat
  63436. REM Check to see if we can grab the directory of this file (Windows NT+)
  63437. IF %~n0 == pear (
  63438. FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" (
  63439. SET "PHP_PEAR_PHP_BIN=%%~$PATH:x"
  63440. echo Using PHP Executable "%PHP_PEAR_PHP_BIN%"
  63441. "%PHP_PEAR_PHP_BIN%" -v
  63442. GOTO :NEXTTEST
  63443. ))
  63444. GOTO :FAILAUTODETECT
  63445. :NEXTTEST
  63446. IF "%PHP_PEAR_PHP_BIN%" NEQ "" (
  63447. REM We can use this PHP to run a temporary php file to get the dirname of pear
  63448. echo ^<?php $s=getcwd^(^);chdir^($a=dirname^(__FILE__^).'\\'^);if^(stristr^($a,'\\scripts'^)^)$a=dirname^(dirname^($a^)^).'\\';$f=fopen^($s.'\\~a.a','wb'^);echo$s.'\\~a.a';fwrite^($f,$a^);fclose^($f^);chdir^($s^);?^> > ~~getloc.php
  63449. "%PHP_PEAR_PHP_BIN%" ~~getloc.php
  63450. set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a
  63451. DEL ~a.a
  63452. DEL ~~getloc.php
  63453. set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear"
  63454. REM Make sure there is a pearcmd.php at our disposal
  63455. IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php (
  63456. IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63457. IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63458. IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php
  63459. )
  63460. )
  63461. GOTO :INSTALLED
  63462. ) ELSE (
  63463. REM Windows Me/98 cannot succeed, so allow the batch to fail
  63464. )
  63465. :FAILAUTODETECT
  63466. echo WARNING: failed to auto-detect pear information
  63467. :INSTALLED
  63468. REM Check Folders and files
  63469. IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR
  63470. IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2
  63471. IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR
  63472. IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR
  63473. REM launch pearcmd
  63474. GOTO RUN
  63475. :PEAR_INSTALL_ERROR
  63476. ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
  63477. ECHO Please fix it using your environment variable or modify
  63478. ECHO the default value in pear.bat
  63479. ECHO The current value is:
  63480. ECHO %PHP_PEAR_INSTALL_DIR%
  63481. GOTO END
  63482. :PEAR_INSTALL_ERROR2
  63483. ECHO PHP_PEAR_INSTALL_DIR is not set correctly.
  63484. ECHO pearcmd.php could not be found there.
  63485. ECHO Please fix it using your environment variable or modify
  63486. ECHO the default value in pear.bat
  63487. ECHO The current value is:
  63488. ECHO %PHP_PEAR_INSTALL_DIR%
  63489. GOTO END
  63490. :PEAR_BIN_ERROR
  63491. ECHO PHP_PEAR_BIN_DIR is not set correctly.
  63492. ECHO Please fix it using your environment variable or modify
  63493. ECHO the default value in pear.bat
  63494. ECHO The current value is:
  63495. ECHO %PHP_PEAR_BIN_DIR%
  63496. GOTO END
  63497. :PEAR_PHPBIN_ERROR
  63498. ECHO PHP_PEAR_PHP_BIN is not set correctly.
  63499. ECHO Please fix it using your environment variable or modify
  63500. ECHO the default value in pear.bat
  63501. ECHO The current value is:
  63502. ECHO %PHP_PEAR_PHP_BIN%
  63503. GOTO END
  63504. :RUN
  63505. "%PHP_PEAR_PHP_BIN%" -C -n -d date.timezone=UTC -d output_buffering=1 -d safe_mode=0 -d "include_path='%PHP_PEAR_INSTALL_DIR%'" -d register_argc_argv="On" -d variables_order=EGPCS -f "%PHP_PEAR_INSTALL_DIR%\peclcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9
  63506. :END
  63507. @ECHO ON��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/pear.sh������������������������������������������������������������������������0000755�0001750�0001750�00000001404�13565304531�015232� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh
  63508. # first find which PHP binary to use
  63509. if test "x$PHP_PEAR_PHP_BIN" != "x"; then
  63510. PHP="$PHP_PEAR_PHP_BIN"
  63511. else
  63512. if test "@php_bin@" = '@'php_bin'@'; then
  63513. PHP=php
  63514. else
  63515. PHP="@php_bin@"
  63516. fi
  63517. fi
  63518. # then look for the right pear include dir
  63519. if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
  63520. INCDIR=$PHP_PEAR_INSTALL_DIR
  63521. INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
  63522. else
  63523. if test "@php_dir@" = '@'php_dir'@'; then
  63524. INCDIR=`dirname $0`
  63525. INCARG=""
  63526. else
  63527. INCDIR="@php_dir@"
  63528. INCARG="-d include_path=@php_dir@"
  63529. fi
  63530. fi
  63531. exec $PHP -C -q $INCARG -d date.timezone=UTC -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@"
  63532. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/peardev.sh���������������������������������������������������������������������0000755�0001750�0001750�00000001431�13565304531�015731� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh
  63533. # first find which PHP binary to use
  63534. if test "x$PHP_PEAR_PHP_BIN" != "x"; then
  63535. PHP="$PHP_PEAR_PHP_BIN"
  63536. else
  63537. if test "@php_bin@" = '@'php_bin'@'; then
  63538. PHP=php
  63539. else
  63540. PHP="@php_bin@"
  63541. fi
  63542. fi
  63543. # then look for the right pear include dir
  63544. if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
  63545. INCDIR=$PHP_PEAR_INSTALL_DIR
  63546. INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
  63547. else
  63548. if test "@php_dir@" = '@'php_dir'@'; then
  63549. INCDIR=`dirname $0`
  63550. INCARG=""
  63551. else
  63552. INCDIR="@php_dir@"
  63553. INCARG="-d include_path=@php_dir@"
  63554. fi
  63555. fi
  63556. exec $PHP -d date.timezone=UTC -d memory_limit="-1" -C -q $INCARG -d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d variables_order=EGPCS -d auto_append_file="" $INCDIR/pearcmd.php "$@"
  63557. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/pecl.sh������������������������������������������������������������������������0000755�0001750�0001750�00000001302�13565304531�015223� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh
  63558. # first find which PHP binary to use
  63559. if test "x$PHP_PEAR_PHP_BIN" != "x"; then
  63560. PHP="$PHP_PEAR_PHP_BIN"
  63561. else
  63562. if test "@php_bin@" = '@'php_bin'@'; then
  63563. PHP=php
  63564. else
  63565. PHP="@php_bin@"
  63566. fi
  63567. fi
  63568. # then look for the right pear include dir
  63569. if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
  63570. INCDIR=$PHP_PEAR_INSTALL_DIR
  63571. INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
  63572. else
  63573. if test "@php_dir@" = '@'php_dir'@'; then
  63574. INCDIR=`dirname $0`
  63575. INCARG=""
  63576. else
  63577. INCDIR="@php_dir@"
  63578. INCARG="-d include_path=@php_dir@"
  63579. fi
  63580. fi
  63581. exec $PHP -C -q $INCARG -d date.timezone=UTC -d output_buffering=1 -d variables_order=EGPCS -d safe_mode=0 -d register_argc_argv="On" $INCDIR/peclcmd.php "$@"
  63582. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/pearcmd.php��������������������������������������������������������������������0000644�0001750�0001750�00000035411�13565304531�016075� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  63583. /**
  63584. * PEAR, the PHP Extension and Application Repository
  63585. *
  63586. * Command line interface
  63587. *
  63588. * PHP versions 4 and 5
  63589. *
  63590. * @category pear
  63591. * @package PEAR
  63592. * @author Stig Bakken <ssb@php.net>
  63593. * @author Tomas V.V.Cox <cox@idecnet.com>
  63594. * @copyright 1997-2009 The Authors
  63595. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  63596. * @link http://pear.php.net/package/PEAR
  63597. */
  63598. @ob_end_clean();
  63599. if (!defined('PEAR_RUNTYPE')) {
  63600. // this is defined in peclcmd.php as 'pecl'
  63601. define('PEAR_RUNTYPE', 'pear');
  63602. }
  63603. define('PEAR_IGNORE_BACKTRACE', 1);
  63604. /**
  63605. * @nodep Gtk
  63606. */
  63607. //the space is needed for windows include paths with trailing backslash
  63608. // http://pear.php.net/bugs/bug.php?id=19482
  63609. if ('@include_path@ ' != '@'.'include_path'.'@ ') {
  63610. ini_set('include_path', trim('@include_path@ '). PATH_SEPARATOR . get_include_path());
  63611. $raw = false;
  63612. } else {
  63613. // this is a raw, uninstalled pear, either a cvs checkout, or php distro
  63614. ini_set('include_path', dirname(__DIR__) . PATH_SEPARATOR . get_include_path());
  63615. $raw = true;
  63616. }
  63617. @ini_set('allow_url_fopen', true);
  63618. @set_time_limit(0);
  63619. ob_implicit_flush(true);
  63620. @ini_set('track_errors', true);
  63621. @ini_set('html_errors', false);
  63622. $_PEAR_PHPDIR = '#$%^&*';
  63623. set_error_handler('error_handler');
  63624. $pear_package_version = "@pear_version@";
  63625. require_once 'PEAR.php';
  63626. require_once 'PEAR/Frontend.php';
  63627. require_once 'PEAR/Config.php';
  63628. require_once 'PEAR/Command.php';
  63629. require_once 'Console/Getopt.php';
  63630. PEAR_Command::setFrontendType('CLI');
  63631. $all_commands = PEAR_Command::getCommands();
  63632. // remove this next part when we stop supporting that crap-ass PHP 4.2
  63633. if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) {
  63634. echo 'ERROR: either use the CLI php executable, ' .
  63635. 'or set register_argc_argv=On in php.ini';
  63636. exit(1);
  63637. }
  63638. $argv = Console_Getopt::readPHPArgv();
  63639. // fix CGI sapi oddity - the -- in pear.bat/pear is not removed
  63640. if (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') {
  63641. unset($argv[1]);
  63642. $argv = array_values($argv);
  63643. }
  63644. $progname = PEAR_RUNTYPE;
  63645. array_shift($argv);
  63646. $options = Console_Getopt::getopt2($argv, "c:C:d:D:Gh?sSqu:vV");
  63647. if (PEAR::isError($options)) {
  63648. usage($options);
  63649. }
  63650. $opts = $options[0];
  63651. $fetype = 'CLI';
  63652. if ($progname == 'gpear' || $progname == 'pear-gtk') {
  63653. $fetype = 'Gtk2';
  63654. } else {
  63655. foreach ($opts as $opt) {
  63656. if ($opt[0] == 'G') {
  63657. $fetype = 'Gtk2';
  63658. }
  63659. }
  63660. }
  63661. $pear_user_config = '';
  63662. $pear_system_config = '';
  63663. $store_user_config = false;
  63664. $store_system_config = false;
  63665. $verbose = 1;
  63666. foreach ($opts as $opt) {
  63667. switch ($opt[0]) {
  63668. case 'c':
  63669. $pear_user_config = $opt[1];
  63670. break;
  63671. case 'C':
  63672. $pear_system_config = $opt[1];
  63673. break;
  63674. }
  63675. }
  63676. PEAR_Command::setFrontendType($fetype);
  63677. $ui = &PEAR_Command::getFrontendObject();
  63678. $config = &PEAR_Config::singleton($pear_user_config, $pear_system_config);
  63679. if (PEAR::isError($config)) {
  63680. $_file = '';
  63681. if ($pear_user_config !== false) {
  63682. $_file .= $pear_user_config;
  63683. }
  63684. if ($pear_system_config !== false) {
  63685. $_file .= '/' . $pear_system_config;
  63686. }
  63687. if ($_file == '/') {
  63688. $_file = 'The default config file';
  63689. }
  63690. $config->getMessage();
  63691. $ui->outputData("ERROR: $_file is not a valid config file or is corrupted.");
  63692. // We stop, we have no idea where we are :)
  63693. exit(1);
  63694. }
  63695. // this is used in the error handler to retrieve a relative path
  63696. $_PEAR_PHPDIR = $config->get('php_dir');
  63697. $ui->setConfig($config);
  63698. PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError"));
  63699. $verbose = $config->get("verbose");
  63700. $cmdopts = array();
  63701. if ($raw) {
  63702. if (!$config->isDefinedLayer('user') && !$config->isDefinedLayer('system')) {
  63703. $found = false;
  63704. foreach ($opts as $opt) {
  63705. if ($opt[0] == 'd' || $opt[0] == 'D') {
  63706. // the user knows what they are doing, and are setting config values
  63707. $found = true;
  63708. }
  63709. }
  63710. if (!$found) {
  63711. // no prior runs, try to install PEAR
  63712. $parent = dirname(__FILE__);
  63713. if (strpos($parent, 'scripts')) {
  63714. $grandparent = dirname($parent);
  63715. $packagexml = $grandparent . DIRECTORY_SEPARATOR . 'package2.xml';
  63716. $pearbase = $grandparent;
  63717. } else {
  63718. $packagexml = $parent . DIRECTORY_SEPARATOR . 'package2.xml';
  63719. $pearbase = $parent;
  63720. }
  63721. if (file_exists($packagexml)) {
  63722. $options[1] = array(
  63723. 'install',
  63724. $packagexml
  63725. );
  63726. $config->set('php_dir', $pearbase . DIRECTORY_SEPARATOR . 'php');
  63727. $config->set('data_dir', $pearbase . DIRECTORY_SEPARATOR . 'data');
  63728. $config->set('doc_dir', $pearbase . DIRECTORY_SEPARATOR . 'docs');
  63729. $config->set('test_dir', $pearbase . DIRECTORY_SEPARATOR . 'tests');
  63730. $config->set(
  63731. 'ext_dir',
  63732. $pearbase . DIRECTORY_SEPARATOR . 'extensions'
  63733. );
  63734. $config->set('bin_dir', $pearbase);
  63735. $config->mergeConfigFile($pearbase . 'pear.ini', false);
  63736. $config->store();
  63737. $config->set('auto_discover', 1);
  63738. }
  63739. }
  63740. }
  63741. }
  63742. foreach ($opts as $opt) {
  63743. $param = !empty($opt[1]) ? $opt[1] : true;
  63744. switch ($opt[0]) {
  63745. case 'd':
  63746. if ($param === true) {
  63747. die(
  63748. 'Invalid usage of "-d" option, expected -d config_value=value, ' .
  63749. 'received "-d"' . "\n"
  63750. );
  63751. }
  63752. $possible = explode('=', $param);
  63753. if (count($possible) != 2) {
  63754. die(
  63755. 'Invalid usage of "-d" option, expected ' .
  63756. '-d config_value=value, received "' . $param . '"' . "\n"
  63757. );
  63758. }
  63759. list($key, $value) = explode('=', $param);
  63760. $config->set($key, $value, 'user');
  63761. break;
  63762. case 'D':
  63763. if ($param === true) {
  63764. die(
  63765. 'Invalid usage of "-d" option, expected ' .
  63766. '-d config_value=value, received "-d"' . "\n"
  63767. );
  63768. }
  63769. $possible = explode('=', $param);
  63770. if (count($possible) != 2) {
  63771. die(
  63772. 'Invalid usage of "-d" option, expected ' .
  63773. '-d config_value=value, received "' . $param . '"' . "\n"
  63774. );
  63775. }
  63776. list($key, $value) = explode('=', $param);
  63777. $config->set($key, $value, 'system');
  63778. break;
  63779. case 's':
  63780. $store_user_config = true;
  63781. break;
  63782. case 'S':
  63783. $store_system_config = true;
  63784. break;
  63785. case 'u':
  63786. $config->remove($param, 'user');
  63787. break;
  63788. case 'v':
  63789. $config->set('verbose', $config->get('verbose') + 1);
  63790. break;
  63791. case 'q':
  63792. $config->set('verbose', $config->get('verbose') - 1);
  63793. break;
  63794. case 'V':
  63795. usage(null, 'version');
  63796. case 'c':
  63797. case 'C':
  63798. break;
  63799. default:
  63800. // all non pear params goes to the command
  63801. $cmdopts[$opt[0]] = $param;
  63802. break;
  63803. }
  63804. }
  63805. if ($store_system_config) {
  63806. $config->store('system');
  63807. }
  63808. if ($store_user_config) {
  63809. $config->store('user');
  63810. }
  63811. $command = (isset($options[1][0])) ? $options[1][0] : null;
  63812. if (empty($command) && ($store_user_config || $store_system_config)) {
  63813. exit;
  63814. }
  63815. if ($fetype == 'Gtk2') {
  63816. if (!$config->validConfiguration()) {
  63817. PEAR::raiseError(
  63818. "CRITICAL ERROR: no existing valid configuration files found in " .
  63819. "files '$pear_user_config' or '$pear_system_config', " .
  63820. "please copy an existing configuration file to one of these " .
  63821. "locations, or use the -c and -s options to create one"
  63822. );
  63823. }
  63824. Gtk::main();
  63825. } else {
  63826. do {
  63827. if ($command == 'help') {
  63828. usage(null, isset($options[1][1]) ? $options[1][1] : null);
  63829. }
  63830. if (!$config->validConfiguration()) {
  63831. PEAR::raiseError(
  63832. "CRITICAL ERROR: no existing valid configuration files found " .
  63833. "in files '$pear_user_config' or '$pear_system_config', " .
  63834. "please copy an existing configuration file to one of " .
  63835. "these locations, or use the -c and -s options to create one"
  63836. );
  63837. }
  63838. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  63839. $cmd = PEAR_Command::factory($command, $config);
  63840. PEAR::popErrorHandling();
  63841. if (PEAR::isError($cmd)) {
  63842. usage(null, isset($options[1][0]) ? $options[1][0] : null);
  63843. }
  63844. $short_args = $long_args = null;
  63845. PEAR_Command::getGetoptArgs($command, $short_args, $long_args);
  63846. array_shift($options[1]);
  63847. $tmp = Console_Getopt::getopt2($options[1], $short_args, $long_args);
  63848. if (PEAR::isError($tmp)) {
  63849. break;
  63850. }
  63851. list($tmpopt, $params) = $tmp;
  63852. $opts = array();
  63853. foreach ($tmpopt as $foo => $tmp2) {
  63854. list($opt, $value) = $tmp2;
  63855. if ($value === null) {
  63856. $value = true; // options without args
  63857. }
  63858. if (strlen($opt) == 1) {
  63859. $cmdoptions = $cmd->getOptions($command);
  63860. foreach ($cmdoptions as $o => $d) {
  63861. if (isset($d['shortopt']) && $d['shortopt'] == $opt) {
  63862. $opts[$o] = $value;
  63863. }
  63864. }
  63865. } else {
  63866. if (substr($opt, 0, 2) == '--') {
  63867. $opts[substr($opt, 2)] = $value;
  63868. }
  63869. }
  63870. }
  63871. $ok = $cmd->run($command, $opts, $params);
  63872. if ($ok === false) {
  63873. PEAR::raiseError("unknown command `$command'");
  63874. }
  63875. if (PEAR::isError($ok)) {
  63876. PEAR::setErrorHandling(
  63877. PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")
  63878. );
  63879. PEAR::raiseError($ok);
  63880. }
  63881. } while (false);
  63882. }
  63883. // {{{ usage()
  63884. /**
  63885. * Display usage information
  63886. *
  63887. * @param mixed $error Optional error message
  63888. * @param mixed $helpsubject Optional subject/command to display help for
  63889. *
  63890. * @return void
  63891. */
  63892. function usage($error = null, $helpsubject = null)
  63893. {
  63894. global $progname, $all_commands;
  63895. $stdout = fopen('php://stdout', 'w');
  63896. if (PEAR::isError($error)) {
  63897. fputs($stdout, $error->getMessage() . "\n");
  63898. } elseif ($error !== null) {
  63899. fputs($stdout, "$error\n");
  63900. }
  63901. if ($helpsubject != null) {
  63902. $put = cmdHelp($helpsubject);
  63903. } else {
  63904. $put = "Commands:\n";
  63905. $maxlen = max(array_map("strlen", $all_commands));
  63906. $formatstr = "%-{$maxlen}s %s\n";
  63907. ksort($all_commands);
  63908. foreach ($all_commands as $cmd => $class) {
  63909. $put .= sprintf($formatstr, $cmd, PEAR_Command::getDescription($cmd));
  63910. }
  63911. $put .=
  63912. "Usage: $progname [options] command [command-options] <parameters>\n".
  63913. "Type \"$progname help options\" to list all options.\n".
  63914. "Type \"$progname help shortcuts\" to list all command shortcuts.\n".
  63915. "Type \"$progname help version\" or ".
  63916. "\"$progname version\" to list version information.\n".
  63917. "Type \"$progname help <command>\" to get the help ".
  63918. "for the specified command.";
  63919. }
  63920. fputs($stdout, "$put\n");
  63921. fclose($stdout);
  63922. if ($error === null) {
  63923. exit(0);
  63924. }
  63925. exit(1);
  63926. }
  63927. /**
  63928. * Return help string for specified command
  63929. *
  63930. * @param string $command Command to return help for
  63931. *
  63932. * @return void
  63933. */
  63934. function cmdHelp($command)
  63935. {
  63936. global $progname, $all_commands, $config;
  63937. if ($command == "options") {
  63938. return
  63939. "Options:\n".
  63940. " -v increase verbosity level (default 1)\n".
  63941. " -q be quiet, decrease verbosity level\n".
  63942. " -c file find user configuration in `file'\n".
  63943. " -C file find system configuration in `file'\n".
  63944. " -d foo=bar set user config variable `foo' to `bar'\n".
  63945. " -D foo=bar set system config variable `foo' to `bar'\n".
  63946. " -G start in graphical (Gtk) mode\n".
  63947. " -s store user configuration\n".
  63948. " -S store system configuration\n".
  63949. " -u foo unset `foo' in the user configuration\n".
  63950. " -h, -? display help/usage (this message)\n".
  63951. " -V version information\n";
  63952. } elseif ($command == "shortcuts") {
  63953. $sc = PEAR_Command::getShortcuts();
  63954. $ret = "Shortcuts:\n";
  63955. foreach ($sc as $s => $c) {
  63956. $ret .= sprintf(" %-8s %s\n", $s, $c);
  63957. }
  63958. return $ret;
  63959. } elseif ($command == "version") {
  63960. return "PEAR Version: ".$GLOBALS['pear_package_version'].
  63961. "\nPHP Version: ".phpversion().
  63962. "\nZend Engine Version: ".zend_version().
  63963. "\nRunning on: ".php_uname();
  63964. } elseif ($help = PEAR_Command::getHelp($command)) {
  63965. if (is_string($help)) {
  63966. return "$progname $command [options] $help\n";
  63967. }
  63968. if ($help[1] === null) {
  63969. return "$progname $command $help[0]";
  63970. }
  63971. return "$progname $command [options] $help[0]\n$help[1]";
  63972. }
  63973. return "Command '$command' is not valid, try '$progname help'";
  63974. }
  63975. // }}}
  63976. /**
  63977. * error_handler
  63978. *
  63979. * @param mixed $errno Error number
  63980. * @param mixed $errmsg Message
  63981. * @param mixed $file Filename
  63982. * @param mixed $line Line number
  63983. *
  63984. * @access public
  63985. * @return boolean
  63986. */
  63987. function error_handler($errno, $errmsg, $file, $line)
  63988. {
  63989. if ($errno & E_STRICT) {
  63990. return; // E_STRICT
  63991. }
  63992. if ($errno & E_DEPRECATED) {
  63993. return; // E_DEPRECATED
  63994. }
  63995. if (!(error_reporting() & $errno) &&
  63996. isset($GLOBALS['config']) &&
  63997. $GLOBALS['config']->get('verbose') < 4
  63998. ) {
  63999. return false; // @silenced error, show all if debug is high enough
  64000. }
  64001. $errortype = array (
  64002. E_DEPRECATED => 'Deprecated Warning',
  64003. E_ERROR => "Error",
  64004. E_WARNING => "Warning",
  64005. E_PARSE => "Parsing Error",
  64006. E_STRICT => 'Strict Warning',
  64007. E_NOTICE => "Notice",
  64008. E_CORE_ERROR => "Core Error",
  64009. E_CORE_WARNING => "Core Warning",
  64010. E_COMPILE_ERROR => "Compile Error",
  64011. E_COMPILE_WARNING => "Compile Warning",
  64012. E_USER_ERROR => "User Error",
  64013. E_USER_WARNING => "User Warning",
  64014. E_USER_NOTICE => "User Notice"
  64015. );
  64016. $prefix = $errortype[$errno];
  64017. global $_PEAR_PHPDIR;
  64018. if (stristr($file, $_PEAR_PHPDIR)) {
  64019. $file = substr($file, strlen($_PEAR_PHPDIR) + 1);
  64020. } else {
  64021. $file = basename($file);
  64022. }
  64023. print "\n$prefix: $errmsg in $file on line $line\n";
  64024. return false;
  64025. }
  64026. /*
  64027. * Local variables:
  64028. * tab-width: 4
  64029. * c-basic-offset: 4
  64030. * indent-tabs-mode: nil
  64031. * mode: php
  64032. * End:
  64033. */
  64034. // vim600:syn=php
  64035. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/scripts/peclcmd.php��������������������������������������������������������������������0000644�0001750�0001750�00000002105�13565304531�016063� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  64036. /**
  64037. * PEAR, the PHP Extension and Application Repository
  64038. *
  64039. * Command line interface
  64040. *
  64041. * PHP versions 4 and 5
  64042. *
  64043. * @category pear
  64044. * @package PEAR
  64045. * @author Stig Bakken <ssb@php.net>
  64046. * @author Tomas V.V.Cox <cox@idecnet.com>
  64047. * @copyright 1997-2009 The Authors
  64048. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  64049. * @link http://pear.php.net/package/PEAR
  64050. */
  64051. /**
  64052. * @nodep Gtk
  64053. */
  64054. //the space is needed for windows include paths with trailing backslash
  64055. // http://pear.php.net/bugs/bug.php?id=19482
  64056. if ('@include_path@ ' != '@'.'include_path'.'@ ') {
  64057. ini_set('include_path', trim('@include_path@ '). PATH_SEPARATOR . get_include_path());
  64058. $raw = false;
  64059. } else {
  64060. // this is a raw, uninstalled pear, either a cvs checkout, or php distro
  64061. ini_set('include_path', __DIR__ . PATH_SEPARATOR . get_include_path());
  64062. $raw = true;
  64063. }
  64064. define('PEAR_RUNTYPE', 'pecl');
  64065. require_once 'pearcmd.php';
  64066. /*
  64067. * Local variables:
  64068. * tab-width: 4
  64069. * c-basic-offset: 4
  64070. * indent-tabs-mode: nil
  64071. * mode: php
  64072. * End:
  64073. */
  64074. // vim600:syn=php
  64075. ?>
  64076. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/LICENSE��������������������������������������������������������������������������������0000644�0001750�0001750�00000002705�13565304531�013267� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Copyright (c) 1997-2009,
  64077. Stig Bakken <ssb@php.net>,
  64078. Gregory Beaver <cellog@php.net>,
  64079. Helgi Þormar Þorbjörnsson <helgi@php.net>,
  64080. Tomas V.V.Cox <cox@idecnet.com>,
  64081. Martin Jansen <mj@php.net>.
  64082. All rights reserved.
  64083. Redistribution and use in source and binary forms, with or without
  64084. modification, are permitted provided that the following conditions are met:
  64085. * Redistributions of source code must retain the above copyright notice,
  64086. this list of conditions and the following disclaimer.
  64087. * Redistributions in binary form must reproduce the above copyright
  64088. notice, this list of conditions and the following disclaimer in the
  64089. documentation and/or other materials provided with the distribution.
  64090. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  64091. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  64092. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  64093. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  64094. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  64095. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  64096. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  64097. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  64098. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  64099. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  64100. �����������������������������������������������������������PEAR-1.10.10/INSTALL��������������������������������������������������������������������������������0000644�0001750�0001750�00000004170�13565304531�013311� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR - The PEAR Installer
  64101. =========================
  64102. Installing the PEAR Installer.
  64103. You should install PEAR on a local development machine first. Installing
  64104. PEAR on a remote production machine should only be done after you are
  64105. familiar with PEAR and have tested code using PEAR on your development
  64106. machine.
  64107. There are two methods of installing PEAR
  64108. - PEAR bundled in PHP
  64109. - go-pear
  64110. We will first examine how to install PEAR that is bundled with PHP.
  64111. Microsoft Windows
  64112. =================
  64113. If you are running PHP 5.2.0 or newer, simply download and
  64114. run the windows installer (.msi) and PEAR can be automatically
  64115. installed.
  64116. Otherwise, for older PHP versions, download the .zip of windows,
  64117. there is a script included with your PHP distribution that is called
  64118. "go-pear". You must open a command box in order to run it. Click
  64119. "start" then click "Run..." and type "cmd.exe" to open a command box.
  64120. Use "cd" to change directory to the location of PHP where you unzipped it,
  64121. and run the go-pear command.
  64122. Unix
  64123. ====
  64124. When compiling PHP from source, you simply need to include the
  64125. --with-pear directive on the "./configure" command. This is "on"
  64126. by default in most PHP versions, but it doesn't hurt to list it
  64127. explicitly. You should also consider enabling the zlib extension via
  64128. --enable-zlib, so that the PEAR installer will be able to handle gzipped
  64129. files (i.e. smaller package files for faster downloads). Later, when you
  64130. run "make install" to install PHP itself, part of the process will be
  64131. prompts that ask you where you want PEAR to be installed.
  64132. go-pear
  64133. =======
  64134. For users who cannot perform the above steps, or who wish to obtain the
  64135. latest PEAR with a slightly higher risk of failure, use go-pear. go-pear
  64136. is obtained by downloading http://pear.php.net/go-pear and saving it as go-pear.php.
  64137. After downloading, simply run "php go-pear.php" or open it in a web browser
  64138. (windows only) to download and install PEAR.
  64139. You can always ask general installation questions on pear-general@lists.php.net,
  64140. a public mailing list devoted to support for PEAR packages and installation-
  64141. related issues.
  64142. Happy PHPing, we hope PEAR will be a great tool for your development work!
  64143. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/package.dtd����������������������������������������������������������������������������0000644�0001750�0001750�00000006477�13565304531�014364� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!--
  64144. $Id: package.dtd,v 1.38 2005-11-12 02:23:07 cellog Exp $
  64145. This is the PEAR package description, version 1.0.
  64146. It should be used with the informal public identifier:
  64147. "-//PHP Group//DTD PEAR Package 1.0//EN//XML"
  64148. Copyright (c) 1997-2005 The PHP Group
  64149. This source file is subject to version 3.00 of the PHP license,
  64150. that is bundled with this package in the file LICENSE, and is
  64151. available at through the world-wide-web at
  64152. http://www.php.net/license/3_0.txt.
  64153. If you did not receive a copy of the PHP license and are unable to
  64154. obtain it through the world-wide-web, please send a note to
  64155. license@php.net so we can mail you a copy immediately.
  64156. Authors:
  64157. Stig S. Bakken <ssb@fast.no>
  64158. Gregory Beaver <cellog@php.net>
  64159. -->
  64160. <!ENTITY % NUMBER "CDATA">
  64161. <!ELEMENT package (name,summary,description,license?,maintainers,release,changelog?)>
  64162. <!ATTLIST package type (source|binary|empty) "empty"
  64163. version CDATA #REQUIRED
  64164. packagerversion CDATA #IMPLIED>
  64165. <!ELEMENT name (#PCDATA)>
  64166. <!ELEMENT summary (#PCDATA)>
  64167. <!ELEMENT license (#PCDATA)>
  64168. <!ELEMENT description (#PCDATA)>
  64169. <!ELEMENT maintainers (maintainer)+>
  64170. <!ELEMENT maintainer (user|role|name|email)+>
  64171. <!ELEMENT user (#PCDATA)>
  64172. <!ELEMENT role (#PCDATA)>
  64173. <!ELEMENT email (#PCDATA)>
  64174. <!ELEMENT changelog (release)+>
  64175. <!ELEMENT release (version,date,license,state,notes,warnings?,provides*,deps?,configureoptions?,filelist?)>
  64176. <!ELEMENT version (#PCDATA)>
  64177. <!ELEMENT date (#PCDATA)>
  64178. <!ELEMENT state (#PCDATA)>
  64179. <!ELEMENT notes (#PCDATA)>
  64180. <!ELEMENT warnings (#PCDATA)>
  64181. <!ELEMENT deps (dep*)>
  64182. <!ELEMENT dep (#PCDATA)>
  64183. <!ATTLIST dep type (pkg|ext|php) #REQUIRED
  64184. rel (has|eq|lt|le|gt|ge) #IMPLIED
  64185. version CDATA #IMPLIED
  64186. optional (yes|no) 'no'>
  64187. <!ELEMENT configureoptions (configureoption)+>
  64188. <!ELEMENT configureoption EMPTY>
  64189. <!ATTLIST configureoption name CDATA #REQUIRED
  64190. default CDATA #IMPLIED
  64191. prompt CDATA #REQUIRED>
  64192. <!ELEMENT provides EMPTY>
  64193. <!ATTLIST provides type (ext|prog|class|function|feature|api) #REQUIRED
  64194. name CDATA #REQUIRED
  64195. extends CDATA #IMPLIED>
  64196. <!ELEMENT filelist (dir|file)+>
  64197. <!ELEMENT dir (dir|file)+>
  64198. <!ATTLIST dir name CDATA #REQUIRED
  64199. role (php|ext|src|test|doc|data|script) 'php'
  64200. baseinstalldir CDATA #IMPLIED>
  64201. <!ELEMENT file (replace*)>
  64202. <!ATTLIST file role (php|ext|src|test|doc|data|script) 'php'
  64203. debug (na|on|off) 'na'
  64204. format CDATA #IMPLIED
  64205. baseinstalldir CDATA #IMPLIED
  64206. platform CDATA #IMPLIED
  64207. md5sum CDATA #IMPLIED
  64208. name CDATA #REQUIRED
  64209. install-as CDATA #IMPLIED>
  64210. <!ELEMENT replace EMPTY>
  64211. <!ATTLIST replace type (php-const|pear-config|package-info) #REQUIRED
  64212. from CDATA #REQUIRED
  64213. to CDATA #REQUIRED>
  64214. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/PEAR.php�������������������������������������������������������������������������������0000644�0001750�0001750�00000106513�13565304531�013524� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  64215. /**
  64216. * PEAR, the PHP Extension and Application Repository
  64217. *
  64218. * PEAR class and PEAR_Error class
  64219. *
  64220. * PHP versions 4 and 5
  64221. *
  64222. * @category pear
  64223. * @package PEAR
  64224. * @author Sterling Hughes <sterling@php.net>
  64225. * @author Stig Bakken <ssb@php.net>
  64226. * @author Tomas V.V.Cox <cox@idecnet.com>
  64227. * @author Greg Beaver <cellog@php.net>
  64228. * @copyright 1997-2010 The Authors
  64229. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  64230. * @link http://pear.php.net/package/PEAR
  64231. * @since File available since Release 0.1
  64232. */
  64233. /**#@+
  64234. * ERROR constants
  64235. */
  64236. define('PEAR_ERROR_RETURN', 1);
  64237. define('PEAR_ERROR_PRINT', 2);
  64238. define('PEAR_ERROR_TRIGGER', 4);
  64239. define('PEAR_ERROR_DIE', 8);
  64240. define('PEAR_ERROR_CALLBACK', 16);
  64241. /**
  64242. * WARNING: obsolete
  64243. * @deprecated
  64244. */
  64245. define('PEAR_ERROR_EXCEPTION', 32);
  64246. /**#@-*/
  64247. if (substr(PHP_OS, 0, 3) == 'WIN') {
  64248. define('OS_WINDOWS', true);
  64249. define('OS_UNIX', false);
  64250. define('PEAR_OS', 'Windows');
  64251. } else {
  64252. define('OS_WINDOWS', false);
  64253. define('OS_UNIX', true);
  64254. define('PEAR_OS', 'Unix'); // blatant assumption
  64255. }
  64256. $GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
  64257. $GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
  64258. $GLOBALS['_PEAR_destructor_object_list'] = array();
  64259. $GLOBALS['_PEAR_shutdown_funcs'] = array();
  64260. $GLOBALS['_PEAR_error_handler_stack'] = array();
  64261. @ini_set('track_errors', true);
  64262. /**
  64263. * Base class for other PEAR classes. Provides rudimentary
  64264. * emulation of destructors.
  64265. *
  64266. * If you want a destructor in your class, inherit PEAR and make a
  64267. * destructor method called _yourclassname (same name as the
  64268. * constructor, but with a "_" prefix). Also, in your constructor you
  64269. * have to call the PEAR constructor: $this->PEAR();.
  64270. * The destructor method will be called without parameters. Note that
  64271. * at in some SAPI implementations (such as Apache), any output during
  64272. * the request shutdown (in which destructors are called) seems to be
  64273. * discarded. If you need to get any debug information from your
  64274. * destructor, use error_log(), syslog() or something similar.
  64275. *
  64276. * IMPORTANT! To use the emulated destructors you need to create the
  64277. * objects by reference: $obj =& new PEAR_child;
  64278. *
  64279. * @category pear
  64280. * @package PEAR
  64281. * @author Stig Bakken <ssb@php.net>
  64282. * @author Tomas V.V. Cox <cox@idecnet.com>
  64283. * @author Greg Beaver <cellog@php.net>
  64284. * @copyright 1997-2006 The PHP Group
  64285. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  64286. * @version Release: 1.10.10
  64287. * @link http://pear.php.net/package/PEAR
  64288. * @see PEAR_Error
  64289. * @since Class available since PHP 4.0.2
  64290. * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear
  64291. */
  64292. class PEAR
  64293. {
  64294. /**
  64295. * Whether to enable internal debug messages.
  64296. *
  64297. * @var bool
  64298. * @access private
  64299. */
  64300. var $_debug = false;
  64301. /**
  64302. * Default error mode for this object.
  64303. *
  64304. * @var int
  64305. * @access private
  64306. */
  64307. var $_default_error_mode = null;
  64308. /**
  64309. * Default error options used for this object when error mode
  64310. * is PEAR_ERROR_TRIGGER.
  64311. *
  64312. * @var int
  64313. * @access private
  64314. */
  64315. var $_default_error_options = null;
  64316. /**
  64317. * Default error handler (callback) for this object, if error mode is
  64318. * PEAR_ERROR_CALLBACK.
  64319. *
  64320. * @var string
  64321. * @access private
  64322. */
  64323. var $_default_error_handler = '';
  64324. /**
  64325. * Which class to use for error objects.
  64326. *
  64327. * @var string
  64328. * @access private
  64329. */
  64330. var $_error_class = 'PEAR_Error';
  64331. /**
  64332. * An array of expected errors.
  64333. *
  64334. * @var array
  64335. * @access private
  64336. */
  64337. var $_expected_errors = array();
  64338. /**
  64339. * List of methods that can be called both statically and non-statically.
  64340. * @var array
  64341. */
  64342. protected static $bivalentMethods = array(
  64343. 'setErrorHandling' => true,
  64344. 'raiseError' => true,
  64345. 'throwError' => true,
  64346. 'pushErrorHandling' => true,
  64347. 'popErrorHandling' => true,
  64348. );
  64349. /**
  64350. * Constructor. Registers this object in
  64351. * $_PEAR_destructor_object_list for destructor emulation if a
  64352. * destructor object exists.
  64353. *
  64354. * @param string $error_class (optional) which class to use for
  64355. * error objects, defaults to PEAR_Error.
  64356. * @access public
  64357. * @return void
  64358. */
  64359. function __construct($error_class = null)
  64360. {
  64361. $classname = strtolower(get_class($this));
  64362. if ($this->_debug) {
  64363. print "PEAR constructor called, class=$classname\n";
  64364. }
  64365. if ($error_class !== null) {
  64366. $this->_error_class = $error_class;
  64367. }
  64368. while ($classname && strcasecmp($classname, "pear")) {
  64369. $destructor = "_$classname";
  64370. if (method_exists($this, $destructor)) {
  64371. global $_PEAR_destructor_object_list;
  64372. $_PEAR_destructor_object_list[] = $this;
  64373. if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  64374. register_shutdown_function("_PEAR_call_destructors");
  64375. $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  64376. }
  64377. break;
  64378. } else {
  64379. $classname = get_parent_class($classname);
  64380. }
  64381. }
  64382. }
  64383. /**
  64384. * Only here for backwards compatibility.
  64385. * E.g. Archive_Tar calls $this->PEAR() in its constructor.
  64386. *
  64387. * @param string $error_class Which class to use for error objects,
  64388. * defaults to PEAR_Error.
  64389. */
  64390. public function PEAR($error_class = null)
  64391. {
  64392. self::__construct($error_class);
  64393. }
  64394. /**
  64395. * Destructor (the emulated type of...). Does nothing right now,
  64396. * but is included for forward compatibility, so subclass
  64397. * destructors should always call it.
  64398. *
  64399. * See the note in the class desciption about output from
  64400. * destructors.
  64401. *
  64402. * @access public
  64403. * @return void
  64404. */
  64405. function _PEAR() {
  64406. if ($this->_debug) {
  64407. printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
  64408. }
  64409. }
  64410. public function __call($method, $arguments)
  64411. {
  64412. if (!isset(self::$bivalentMethods[$method])) {
  64413. trigger_error(
  64414. 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
  64415. );
  64416. }
  64417. return call_user_func_array(
  64418. array(get_class(), '_' . $method),
  64419. array_merge(array($this), $arguments)
  64420. );
  64421. }
  64422. public static function __callStatic($method, $arguments)
  64423. {
  64424. if (!isset(self::$bivalentMethods[$method])) {
  64425. trigger_error(
  64426. 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
  64427. );
  64428. }
  64429. return call_user_func_array(
  64430. array(get_class(), '_' . $method),
  64431. array_merge(array(null), $arguments)
  64432. );
  64433. }
  64434. /**
  64435. * If you have a class that's mostly/entirely static, and you need static
  64436. * properties, you can use this method to simulate them. Eg. in your method(s)
  64437. * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
  64438. * You MUST use a reference, or they will not persist!
  64439. *
  64440. * @param string $class The calling classname, to prevent clashes
  64441. * @param string $var The variable to retrieve.
  64442. * @return mixed A reference to the variable. If not set it will be
  64443. * auto initialised to NULL.
  64444. */
  64445. public static function &getStaticProperty($class, $var)
  64446. {
  64447. static $properties;
  64448. if (!isset($properties[$class])) {
  64449. $properties[$class] = array();
  64450. }
  64451. if (!array_key_exists($var, $properties[$class])) {
  64452. $properties[$class][$var] = null;
  64453. }
  64454. return $properties[$class][$var];
  64455. }
  64456. /**
  64457. * Use this function to register a shutdown method for static
  64458. * classes.
  64459. *
  64460. * @param mixed $func The function name (or array of class/method) to call
  64461. * @param mixed $args The arguments to pass to the function
  64462. *
  64463. * @return void
  64464. */
  64465. public static function registerShutdownFunc($func, $args = array())
  64466. {
  64467. // if we are called statically, there is a potential
  64468. // that no shutdown func is registered. Bug #6445
  64469. if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  64470. register_shutdown_function("_PEAR_call_destructors");
  64471. $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  64472. }
  64473. $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
  64474. }
  64475. /**
  64476. * Tell whether a value is a PEAR error.
  64477. *
  64478. * @param mixed $data the value to test
  64479. * @param int $code if $data is an error object, return true
  64480. * only if $code is a string and
  64481. * $obj->getMessage() == $code or
  64482. * $code is an integer and $obj->getCode() == $code
  64483. *
  64484. * @return bool true if parameter is an error
  64485. */
  64486. public static function isError($data, $code = null)
  64487. {
  64488. if (!is_a($data, 'PEAR_Error')) {
  64489. return false;
  64490. }
  64491. if (is_null($code)) {
  64492. return true;
  64493. } elseif (is_string($code)) {
  64494. return $data->getMessage() == $code;
  64495. }
  64496. return $data->getCode() == $code;
  64497. }
  64498. /**
  64499. * Sets how errors generated by this object should be handled.
  64500. * Can be invoked both in objects and statically. If called
  64501. * statically, setErrorHandling sets the default behaviour for all
  64502. * PEAR objects. If called in an object, setErrorHandling sets
  64503. * the default behaviour for that object.
  64504. *
  64505. * @param object $object
  64506. * Object the method was called on (non-static mode)
  64507. *
  64508. * @param int $mode
  64509. * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  64510. * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  64511. * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
  64512. *
  64513. * @param mixed $options
  64514. * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
  64515. * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  64516. *
  64517. * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
  64518. * to be the callback function or method. A callback
  64519. * function is a string with the name of the function, a
  64520. * callback method is an array of two elements: the element
  64521. * at index 0 is the object, and the element at index 1 is
  64522. * the name of the method to call in the object.
  64523. *
  64524. * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
  64525. * a printf format string used when printing the error
  64526. * message.
  64527. *
  64528. * @access public
  64529. * @return void
  64530. * @see PEAR_ERROR_RETURN
  64531. * @see PEAR_ERROR_PRINT
  64532. * @see PEAR_ERROR_TRIGGER
  64533. * @see PEAR_ERROR_DIE
  64534. * @see PEAR_ERROR_CALLBACK
  64535. * @see PEAR_ERROR_EXCEPTION
  64536. *
  64537. * @since PHP 4.0.5
  64538. */
  64539. protected static function _setErrorHandling(
  64540. $object, $mode = null, $options = null
  64541. ) {
  64542. if ($object !== null) {
  64543. $setmode = &$object->_default_error_mode;
  64544. $setoptions = &$object->_default_error_options;
  64545. } else {
  64546. $setmode = &$GLOBALS['_PEAR_default_error_mode'];
  64547. $setoptions = &$GLOBALS['_PEAR_default_error_options'];
  64548. }
  64549. switch ($mode) {
  64550. case PEAR_ERROR_EXCEPTION:
  64551. case PEAR_ERROR_RETURN:
  64552. case PEAR_ERROR_PRINT:
  64553. case PEAR_ERROR_TRIGGER:
  64554. case PEAR_ERROR_DIE:
  64555. case null:
  64556. $setmode = $mode;
  64557. $setoptions = $options;
  64558. break;
  64559. case PEAR_ERROR_CALLBACK:
  64560. $setmode = $mode;
  64561. // class/object method callback
  64562. if (is_callable($options)) {
  64563. $setoptions = $options;
  64564. } else {
  64565. trigger_error("invalid error callback", E_USER_WARNING);
  64566. }
  64567. break;
  64568. default:
  64569. trigger_error("invalid error mode", E_USER_WARNING);
  64570. break;
  64571. }
  64572. }
  64573. /**
  64574. * This method is used to tell which errors you expect to get.
  64575. * Expected errors are always returned with error mode
  64576. * PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
  64577. * and this method pushes a new element onto it. The list of
  64578. * expected errors are in effect until they are popped off the
  64579. * stack with the popExpect() method.
  64580. *
  64581. * Note that this method can not be called statically
  64582. *
  64583. * @param mixed $code a single error code or an array of error codes to expect
  64584. *
  64585. * @return int the new depth of the "expected errors" stack
  64586. * @access public
  64587. */
  64588. function expectError($code = '*')
  64589. {
  64590. if (is_array($code)) {
  64591. array_push($this->_expected_errors, $code);
  64592. } else {
  64593. array_push($this->_expected_errors, array($code));
  64594. }
  64595. return count($this->_expected_errors);
  64596. }
  64597. /**
  64598. * This method pops one element off the expected error codes
  64599. * stack.
  64600. *
  64601. * @return array the list of error codes that were popped
  64602. */
  64603. function popExpect()
  64604. {
  64605. return array_pop($this->_expected_errors);
  64606. }
  64607. /**
  64608. * This method checks unsets an error code if available
  64609. *
  64610. * @param mixed error code
  64611. * @return bool true if the error code was unset, false otherwise
  64612. * @access private
  64613. * @since PHP 4.3.0
  64614. */
  64615. function _checkDelExpect($error_code)
  64616. {
  64617. $deleted = false;
  64618. foreach ($this->_expected_errors as $key => $error_array) {
  64619. if (in_array($error_code, $error_array)) {
  64620. unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
  64621. $deleted = true;
  64622. }
  64623. // clean up empty arrays
  64624. if (0 == count($this->_expected_errors[$key])) {
  64625. unset($this->_expected_errors[$key]);
  64626. }
  64627. }
  64628. return $deleted;
  64629. }
  64630. /**
  64631. * This method deletes all occurrences of the specified element from
  64632. * the expected error codes stack.
  64633. *
  64634. * @param mixed $error_code error code that should be deleted
  64635. * @return mixed list of error codes that were deleted or error
  64636. * @access public
  64637. * @since PHP 4.3.0
  64638. */
  64639. function delExpect($error_code)
  64640. {
  64641. $deleted = false;
  64642. if ((is_array($error_code) && (0 != count($error_code)))) {
  64643. // $error_code is a non-empty array here; we walk through it trying
  64644. // to unset all values
  64645. foreach ($error_code as $key => $error) {
  64646. $deleted = $this->_checkDelExpect($error) ? true : false;
  64647. }
  64648. return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  64649. } elseif (!empty($error_code)) {
  64650. // $error_code comes alone, trying to unset it
  64651. if ($this->_checkDelExpect($error_code)) {
  64652. return true;
  64653. }
  64654. return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  64655. }
  64656. // $error_code is empty
  64657. return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
  64658. }
  64659. /**
  64660. * This method is a wrapper that returns an instance of the
  64661. * configured error class with this object's default error
  64662. * handling applied. If the $mode and $options parameters are not
  64663. * specified, the object's defaults are used.
  64664. *
  64665. * @param mixed $message a text error message or a PEAR error object
  64666. *
  64667. * @param int $code a numeric error code (it is up to your class
  64668. * to define these if you want to use codes)
  64669. *
  64670. * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  64671. * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  64672. * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
  64673. *
  64674. * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
  64675. * specifies the PHP-internal error level (one of
  64676. * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  64677. * If $mode is PEAR_ERROR_CALLBACK, this
  64678. * parameter specifies the callback function or
  64679. * method. In other error modes this parameter
  64680. * is ignored.
  64681. *
  64682. * @param string $userinfo If you need to pass along for example debug
  64683. * information, this parameter is meant for that.
  64684. *
  64685. * @param string $error_class The returned error object will be
  64686. * instantiated from this class, if specified.
  64687. *
  64688. * @param bool $skipmsg If true, raiseError will only pass error codes,
  64689. * the error message parameter will be dropped.
  64690. *
  64691. * @return object a PEAR error object
  64692. * @see PEAR::setErrorHandling
  64693. * @since PHP 4.0.5
  64694. */
  64695. protected static function _raiseError($object,
  64696. $message = null,
  64697. $code = null,
  64698. $mode = null,
  64699. $options = null,
  64700. $userinfo = null,
  64701. $error_class = null,
  64702. $skipmsg = false)
  64703. {
  64704. // The error is yet a PEAR error object
  64705. if (is_object($message)) {
  64706. $code = $message->getCode();
  64707. $userinfo = $message->getUserInfo();
  64708. $error_class = $message->getType();
  64709. $message->error_message_prefix = '';
  64710. $message = $message->getMessage();
  64711. }
  64712. if (
  64713. $object !== null &&
  64714. isset($object->_expected_errors) &&
  64715. count($object->_expected_errors) > 0 &&
  64716. count($exp = end($object->_expected_errors))
  64717. ) {
  64718. if ($exp[0] === "*" ||
  64719. (is_int(reset($exp)) && in_array($code, $exp)) ||
  64720. (is_string(reset($exp)) && in_array($message, $exp))
  64721. ) {
  64722. $mode = PEAR_ERROR_RETURN;
  64723. }
  64724. }
  64725. // No mode given, try global ones
  64726. if ($mode === null) {
  64727. // Class error handler
  64728. if ($object !== null && isset($object->_default_error_mode)) {
  64729. $mode = $object->_default_error_mode;
  64730. $options = $object->_default_error_options;
  64731. // Global error handler
  64732. } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
  64733. $mode = $GLOBALS['_PEAR_default_error_mode'];
  64734. $options = $GLOBALS['_PEAR_default_error_options'];
  64735. }
  64736. }
  64737. if ($error_class !== null) {
  64738. $ec = $error_class;
  64739. } elseif ($object !== null && isset($object->_error_class)) {
  64740. $ec = $object->_error_class;
  64741. } else {
  64742. $ec = 'PEAR_Error';
  64743. }
  64744. if ($skipmsg) {
  64745. $a = new $ec($code, $mode, $options, $userinfo);
  64746. } else {
  64747. $a = new $ec($message, $code, $mode, $options, $userinfo);
  64748. }
  64749. return $a;
  64750. }
  64751. /**
  64752. * Simpler form of raiseError with fewer options. In most cases
  64753. * message, code and userinfo are enough.
  64754. *
  64755. * @param mixed $message a text error message or a PEAR error object
  64756. *
  64757. * @param int $code a numeric error code (it is up to your class
  64758. * to define these if you want to use codes)
  64759. *
  64760. * @param string $userinfo If you need to pass along for example debug
  64761. * information, this parameter is meant for that.
  64762. *
  64763. * @return object a PEAR error object
  64764. * @see PEAR::raiseError
  64765. */
  64766. protected static function _throwError($object, $message = null, $code = null, $userinfo = null)
  64767. {
  64768. if ($object !== null) {
  64769. $a = $object->raiseError($message, $code, null, null, $userinfo);
  64770. return $a;
  64771. }
  64772. $a = PEAR::raiseError($message, $code, null, null, $userinfo);
  64773. return $a;
  64774. }
  64775. public static function staticPushErrorHandling($mode, $options = null)
  64776. {
  64777. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  64778. $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
  64779. $def_options = &$GLOBALS['_PEAR_default_error_options'];
  64780. $stack[] = array($def_mode, $def_options);
  64781. switch ($mode) {
  64782. case PEAR_ERROR_EXCEPTION:
  64783. case PEAR_ERROR_RETURN:
  64784. case PEAR_ERROR_PRINT:
  64785. case PEAR_ERROR_TRIGGER:
  64786. case PEAR_ERROR_DIE:
  64787. case null:
  64788. $def_mode = $mode;
  64789. $def_options = $options;
  64790. break;
  64791. case PEAR_ERROR_CALLBACK:
  64792. $def_mode = $mode;
  64793. // class/object method callback
  64794. if (is_callable($options)) {
  64795. $def_options = $options;
  64796. } else {
  64797. trigger_error("invalid error callback", E_USER_WARNING);
  64798. }
  64799. break;
  64800. default:
  64801. trigger_error("invalid error mode", E_USER_WARNING);
  64802. break;
  64803. }
  64804. $stack[] = array($mode, $options);
  64805. return true;
  64806. }
  64807. public static function staticPopErrorHandling()
  64808. {
  64809. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  64810. $setmode = &$GLOBALS['_PEAR_default_error_mode'];
  64811. $setoptions = &$GLOBALS['_PEAR_default_error_options'];
  64812. array_pop($stack);
  64813. list($mode, $options) = $stack[sizeof($stack) - 1];
  64814. array_pop($stack);
  64815. switch ($mode) {
  64816. case PEAR_ERROR_EXCEPTION:
  64817. case PEAR_ERROR_RETURN:
  64818. case PEAR_ERROR_PRINT:
  64819. case PEAR_ERROR_TRIGGER:
  64820. case PEAR_ERROR_DIE:
  64821. case null:
  64822. $setmode = $mode;
  64823. $setoptions = $options;
  64824. break;
  64825. case PEAR_ERROR_CALLBACK:
  64826. $setmode = $mode;
  64827. // class/object method callback
  64828. if (is_callable($options)) {
  64829. $setoptions = $options;
  64830. } else {
  64831. trigger_error("invalid error callback", E_USER_WARNING);
  64832. }
  64833. break;
  64834. default:
  64835. trigger_error("invalid error mode", E_USER_WARNING);
  64836. break;
  64837. }
  64838. return true;
  64839. }
  64840. /**
  64841. * Push a new error handler on top of the error handler options stack. With this
  64842. * you can easily override the actual error handler for some code and restore
  64843. * it later with popErrorHandling.
  64844. *
  64845. * @param mixed $mode (same as setErrorHandling)
  64846. * @param mixed $options (same as setErrorHandling)
  64847. *
  64848. * @return bool Always true
  64849. *
  64850. * @see PEAR::setErrorHandling
  64851. */
  64852. protected static function _pushErrorHandling($object, $mode, $options = null)
  64853. {
  64854. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  64855. if ($object !== null) {
  64856. $def_mode = &$object->_default_error_mode;
  64857. $def_options = &$object->_default_error_options;
  64858. } else {
  64859. $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
  64860. $def_options = &$GLOBALS['_PEAR_default_error_options'];
  64861. }
  64862. $stack[] = array($def_mode, $def_options);
  64863. if ($object !== null) {
  64864. $object->setErrorHandling($mode, $options);
  64865. } else {
  64866. PEAR::setErrorHandling($mode, $options);
  64867. }
  64868. $stack[] = array($mode, $options);
  64869. return true;
  64870. }
  64871. /**
  64872. * Pop the last error handler used
  64873. *
  64874. * @return bool Always true
  64875. *
  64876. * @see PEAR::pushErrorHandling
  64877. */
  64878. protected static function _popErrorHandling($object)
  64879. {
  64880. $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  64881. array_pop($stack);
  64882. list($mode, $options) = $stack[sizeof($stack) - 1];
  64883. array_pop($stack);
  64884. if ($object !== null) {
  64885. $object->setErrorHandling($mode, $options);
  64886. } else {
  64887. PEAR::setErrorHandling($mode, $options);
  64888. }
  64889. return true;
  64890. }
  64891. /**
  64892. * OS independent PHP extension load. Remember to take care
  64893. * on the correct extension name for case sensitive OSes.
  64894. *
  64895. * @param string $ext The extension name
  64896. * @return bool Success or not on the dl() call
  64897. */
  64898. public static function loadExtension($ext)
  64899. {
  64900. if (extension_loaded($ext)) {
  64901. return true;
  64902. }
  64903. // if either returns true dl() will produce a FATAL error, stop that
  64904. if (
  64905. function_exists('dl') === false ||
  64906. ini_get('enable_dl') != 1
  64907. ) {
  64908. return false;
  64909. }
  64910. if (OS_WINDOWS) {
  64911. $suffix = '.dll';
  64912. } elseif (PHP_OS == 'HP-UX') {
  64913. $suffix = '.sl';
  64914. } elseif (PHP_OS == 'AIX') {
  64915. $suffix = '.a';
  64916. } elseif (PHP_OS == 'OSX') {
  64917. $suffix = '.bundle';
  64918. } else {
  64919. $suffix = '.so';
  64920. }
  64921. return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
  64922. }
  64923. /**
  64924. * Get SOURCE_DATE_EPOCH environment variable
  64925. * See https://reproducible-builds.org/specs/source-date-epoch/
  64926. *
  64927. * @return int
  64928. * @access public
  64929. */
  64930. static function getSourceDateEpoch()
  64931. {
  64932. if ($source_date_epoch = getenv('SOURCE_DATE_EPOCH')) {
  64933. if (preg_match('/^\d+$/', $source_date_epoch)) {
  64934. return (int) $source_date_epoch;
  64935. } else {
  64936. // "If the value is malformed, the build process SHOULD exit with a non-zero error code."
  64937. self::raiseError("Invalid SOURCE_DATE_EPOCH: $source_date_epoch");
  64938. exit(1);
  64939. }
  64940. } else {
  64941. return time();
  64942. }
  64943. }
  64944. }
  64945. function _PEAR_call_destructors()
  64946. {
  64947. global $_PEAR_destructor_object_list;
  64948. if (is_array($_PEAR_destructor_object_list) &&
  64949. sizeof($_PEAR_destructor_object_list))
  64950. {
  64951. reset($_PEAR_destructor_object_list);
  64952. $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
  64953. if ($destructLifoExists) {
  64954. $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
  64955. }
  64956. foreach ($_PEAR_destructor_object_list as $k => $objref) {
  64957. $classname = get_class($objref);
  64958. while ($classname) {
  64959. $destructor = "_$classname";
  64960. if (method_exists($objref, $destructor)) {
  64961. $objref->$destructor();
  64962. break;
  64963. } else {
  64964. $classname = get_parent_class($classname);
  64965. }
  64966. }
  64967. }
  64968. // Empty the object list to ensure that destructors are
  64969. // not called more than once.
  64970. $_PEAR_destructor_object_list = array();
  64971. }
  64972. // Now call the shutdown functions
  64973. if (
  64974. isset($GLOBALS['_PEAR_shutdown_funcs']) &&
  64975. is_array($GLOBALS['_PEAR_shutdown_funcs']) &&
  64976. !empty($GLOBALS['_PEAR_shutdown_funcs'])
  64977. ) {
  64978. foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
  64979. call_user_func_array($value[0], $value[1]);
  64980. }
  64981. }
  64982. }
  64983. /**
  64984. * Standard PEAR error class for PHP 4
  64985. *
  64986. * This class is supserseded by {@link PEAR_Exception} in PHP 5
  64987. *
  64988. * @category pear
  64989. * @package PEAR
  64990. * @author Stig Bakken <ssb@php.net>
  64991. * @author Tomas V.V. Cox <cox@idecnet.com>
  64992. * @author Gregory Beaver <cellog@php.net>
  64993. * @copyright 1997-2006 The PHP Group
  64994. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  64995. * @version Release: 1.10.10
  64996. * @link http://pear.php.net/manual/en/core.pear.pear-error.php
  64997. * @see PEAR::raiseError(), PEAR::throwError()
  64998. * @since Class available since PHP 4.0.2
  64999. */
  65000. class PEAR_Error
  65001. {
  65002. var $error_message_prefix = '';
  65003. var $mode = PEAR_ERROR_RETURN;
  65004. var $level = E_USER_NOTICE;
  65005. var $code = -1;
  65006. var $message = '';
  65007. var $userinfo = '';
  65008. var $backtrace = null;
  65009. /**
  65010. * PEAR_Error constructor
  65011. *
  65012. * @param string $message message
  65013. *
  65014. * @param int $code (optional) error code
  65015. *
  65016. * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
  65017. * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
  65018. * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
  65019. *
  65020. * @param mixed $options (optional) error level, _OR_ in the case of
  65021. * PEAR_ERROR_CALLBACK, the callback function or object/method
  65022. * tuple.
  65023. *
  65024. * @param string $userinfo (optional) additional user/debug info
  65025. *
  65026. * @access public
  65027. *
  65028. */
  65029. function __construct($message = 'unknown error', $code = null,
  65030. $mode = null, $options = null, $userinfo = null)
  65031. {
  65032. if ($mode === null) {
  65033. $mode = PEAR_ERROR_RETURN;
  65034. }
  65035. $this->message = $message;
  65036. $this->code = $code;
  65037. $this->mode = $mode;
  65038. $this->userinfo = $userinfo;
  65039. $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
  65040. if (!$skiptrace) {
  65041. $this->backtrace = debug_backtrace();
  65042. if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
  65043. unset($this->backtrace[0]['object']);
  65044. }
  65045. }
  65046. if ($mode & PEAR_ERROR_CALLBACK) {
  65047. $this->level = E_USER_NOTICE;
  65048. $this->callback = $options;
  65049. } else {
  65050. if ($options === null) {
  65051. $options = E_USER_NOTICE;
  65052. }
  65053. $this->level = $options;
  65054. $this->callback = null;
  65055. }
  65056. if ($this->mode & PEAR_ERROR_PRINT) {
  65057. if (is_null($options) || is_int($options)) {
  65058. $format = "%s";
  65059. } else {
  65060. $format = $options;
  65061. }
  65062. printf($format, $this->getMessage());
  65063. }
  65064. if ($this->mode & PEAR_ERROR_TRIGGER) {
  65065. trigger_error($this->getMessage(), $this->level);
  65066. }
  65067. if ($this->mode & PEAR_ERROR_DIE) {
  65068. $msg = $this->getMessage();
  65069. if (is_null($options) || is_int($options)) {
  65070. $format = "%s";
  65071. if (substr($msg, -1) != "\n") {
  65072. $msg .= "\n";
  65073. }
  65074. } else {
  65075. $format = $options;
  65076. }
  65077. printf($format, $msg);
  65078. exit($code);
  65079. }
  65080. if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
  65081. call_user_func($this->callback, $this);
  65082. }
  65083. if ($this->mode & PEAR_ERROR_EXCEPTION) {
  65084. trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
  65085. eval('$e = new Exception($this->message, $this->code);throw($e);');
  65086. }
  65087. }
  65088. /**
  65089. * Only here for backwards compatibility.
  65090. *
  65091. * Class "Cache_Error" still uses it, among others.
  65092. *
  65093. * @param string $message Message
  65094. * @param int $code Error code
  65095. * @param int $mode Error mode
  65096. * @param mixed $options See __construct()
  65097. * @param string $userinfo Additional user/debug info
  65098. */
  65099. public function PEAR_Error(
  65100. $message = 'unknown error', $code = null, $mode = null,
  65101. $options = null, $userinfo = null
  65102. ) {
  65103. self::__construct($message, $code, $mode, $options, $userinfo);
  65104. }
  65105. /**
  65106. * Get the error mode from an error object.
  65107. *
  65108. * @return int error mode
  65109. * @access public
  65110. */
  65111. function getMode()
  65112. {
  65113. return $this->mode;
  65114. }
  65115. /**
  65116. * Get the callback function/method from an error object.
  65117. *
  65118. * @return mixed callback function or object/method array
  65119. * @access public
  65120. */
  65121. function getCallback()
  65122. {
  65123. return $this->callback;
  65124. }
  65125. /**
  65126. * Get the error message from an error object.
  65127. *
  65128. * @return string full error message
  65129. * @access public
  65130. */
  65131. function getMessage()
  65132. {
  65133. return ($this->error_message_prefix . $this->message);
  65134. }
  65135. /**
  65136. * Get error code from an error object
  65137. *
  65138. * @return int error code
  65139. * @access public
  65140. */
  65141. function getCode()
  65142. {
  65143. return $this->code;
  65144. }
  65145. /**
  65146. * Get the name of this error/exception.
  65147. *
  65148. * @return string error/exception name (type)
  65149. * @access public
  65150. */
  65151. function getType()
  65152. {
  65153. return get_class($this);
  65154. }
  65155. /**
  65156. * Get additional user-supplied information.
  65157. *
  65158. * @return string user-supplied information
  65159. * @access public
  65160. */
  65161. function getUserInfo()
  65162. {
  65163. return $this->userinfo;
  65164. }
  65165. /**
  65166. * Get additional debug information supplied by the application.
  65167. *
  65168. * @return string debug information
  65169. * @access public
  65170. */
  65171. function getDebugInfo()
  65172. {
  65173. return $this->getUserInfo();
  65174. }
  65175. /**
  65176. * Get the call backtrace from where the error was generated.
  65177. * Supported with PHP 4.3.0 or newer.
  65178. *
  65179. * @param int $frame (optional) what frame to fetch
  65180. * @return array Backtrace, or NULL if not available.
  65181. * @access public
  65182. */
  65183. function getBacktrace($frame = null)
  65184. {
  65185. if (defined('PEAR_IGNORE_BACKTRACE')) {
  65186. return null;
  65187. }
  65188. if ($frame === null) {
  65189. return $this->backtrace;
  65190. }
  65191. return $this->backtrace[$frame];
  65192. }
  65193. function addUserInfo($info)
  65194. {
  65195. if (empty($this->userinfo)) {
  65196. $this->userinfo = $info;
  65197. } else {
  65198. $this->userinfo .= " ** $info";
  65199. }
  65200. }
  65201. function __toString()
  65202. {
  65203. return $this->getMessage();
  65204. }
  65205. /**
  65206. * Make a string representation of this object.
  65207. *
  65208. * @return string a string with an object summary
  65209. * @access public
  65210. */
  65211. function toString()
  65212. {
  65213. $modes = array();
  65214. $levels = array(E_USER_NOTICE => 'notice',
  65215. E_USER_WARNING => 'warning',
  65216. E_USER_ERROR => 'error');
  65217. if ($this->mode & PEAR_ERROR_CALLBACK) {
  65218. if (is_array($this->callback)) {
  65219. $callback = (is_object($this->callback[0]) ?
  65220. strtolower(get_class($this->callback[0])) :
  65221. $this->callback[0]) . '::' .
  65222. $this->callback[1];
  65223. } else {
  65224. $callback = $this->callback;
  65225. }
  65226. return sprintf('[%s: message="%s" code=%d mode=callback '.
  65227. 'callback=%s prefix="%s" info="%s"]',
  65228. strtolower(get_class($this)), $this->message, $this->code,
  65229. $callback, $this->error_message_prefix,
  65230. $this->userinfo);
  65231. }
  65232. if ($this->mode & PEAR_ERROR_PRINT) {
  65233. $modes[] = 'print';
  65234. }
  65235. if ($this->mode & PEAR_ERROR_TRIGGER) {
  65236. $modes[] = 'trigger';
  65237. }
  65238. if ($this->mode & PEAR_ERROR_DIE) {
  65239. $modes[] = 'die';
  65240. }
  65241. if ($this->mode & PEAR_ERROR_RETURN) {
  65242. $modes[] = 'return';
  65243. }
  65244. return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
  65245. 'prefix="%s" info="%s"]',
  65246. strtolower(get_class($this)), $this->message, $this->code,
  65247. implode("|", $modes), $levels[$this->level],
  65248. $this->error_message_prefix,
  65249. $this->userinfo);
  65250. }
  65251. }
  65252. /*
  65253. * Local Variables:
  65254. * mode: php
  65255. * tab-width: 4
  65256. * c-basic-offset: 4
  65257. * End:
  65258. */
  65259. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/README.rst�����������������������������������������������������������������������������0000644�0001750�0001750�00000005207�13565304531�013751� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������*************************
  65260. PEAR - The PEAR Installer
  65261. *************************
  65262. .. image:: https://travis-ci.org/pear/pear-core.svg?branch=stable
  65263. :target: https://travis-ci.org/pear/pear-core
  65264. =========================================
  65265. What is the PEAR Installer? What is PEAR?
  65266. =========================================
  65267. PEAR is the PHP Extension and Application Repository, found at
  65268. http://pear.php.net.
  65269. The **PEAR Installer** is this software, which contains executable
  65270. files and PHP code that is used to **download and install** PEAR code
  65271. from pear.php.net.
  65272. PEAR contains useful **software libraries and applications** such as
  65273. MDB2 (database abstraction), HTML_QuickForm (HTML forms management),
  65274. PhpDocumentor (auto-documentation generator), DB_DataObject
  65275. (Data Access Abstraction), and many hundreds more.
  65276. Browse all available packages at http://pear.php.net, the list is
  65277. constantly growing and updating to reflect improvements in the PHP language.
  65278. .. warning::
  65279. Do not run PEAR without installing it - if you downloaded this
  65280. tarball manually, you MUST install it. Read the instructions in INSTALL
  65281. prior to use.
  65282. =============
  65283. Documentation
  65284. =============
  65285. Documentation for PEAR can be found at http://pear.php.net/manual/.
  65286. Installation documentation can be found in the INSTALL file included
  65287. in this tarball.
  65288. =====
  65289. Tests
  65290. =====
  65291. Run the tests without installation as follows::
  65292. $ ./scripts/pear.sh run-tests -r tests
  65293. You should have the ``Text_Diff`` package installed to get nicer error output.
  65294. To run the tests with another PHP version, modify ``php_bin`` and set the
  65295. ``PHP_PEAR_PHP_BIN`` environment variable::
  65296. $ pear config-set php_bin /usr/local/bin/php7
  65297. $ PHP_PEAR_PHP_BIN=/usr/local/bin/php7 ./scripts/pear.sh run-tests -r tests
  65298. Happy PHPing, we hope PEAR will be a great tool for your development work!
  65299. Test dependencies
  65300. =================
  65301. * ``zlib``
  65302. =========
  65303. Releasing
  65304. =========
  65305. Create a PEAR package as well as phars for pear-less installation::
  65306. $ rm -f PEAR-*.tgz
  65307. $ pear package package2.xml
  65308. $ cd go-pear-tarballs
  65309. $ rm -f PEAR-*
  65310. $ cp ../PEAR-*.tgz .
  65311. $ gunzip PEAR-*.tgz
  65312. $ pear download -Z Archive_Tar Console_Getopt Structures_Graph XML_Util
  65313. $ mkdir src && cd src
  65314. $ for i in ../*.tar; do tar xvf $i; done
  65315. $ mv *\/* .
  65316. $ cd ../../
  65317. $ php make-gopear-phar.php
  65318. $ php make-installpear-nozlib-phar.php
  65319. (Or simply run ``build-release.sh``).
  65320. ``go-pear.phar`` is contains the PEAR installer installer that asks questions
  65321. where to install it.
  65322. It is available from http://pear.php.net/go-pear.phar.
  65323. ``install-pear-nozlib.phar`` installs PEAR automatically without asking
  65324. anything.
  65325. It is shipped with PHP itself.
  65326. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/System.php�����������������������������������������������������������������������������0000644�0001750�0001750�00000050216�13565304531�014257� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  65327. /**
  65328. * File/Directory manipulation
  65329. *
  65330. * PHP versions 4 and 5
  65331. *
  65332. * @category pear
  65333. * @package System
  65334. * @author Tomas V.V.Cox <cox@idecnet.com>
  65335. * @copyright 1997-2009 The Authors
  65336. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  65337. * @link http://pear.php.net/package/PEAR
  65338. * @since File available since Release 0.1
  65339. */
  65340. /**
  65341. * base class
  65342. */
  65343. require_once 'PEAR.php';
  65344. require_once 'Console/Getopt.php';
  65345. $GLOBALS['_System_temp_files'] = array();
  65346. /**
  65347. * System offers cross platform compatible system functions
  65348. *
  65349. * Static functions for different operations. Should work under
  65350. * Unix and Windows. The names and usage has been taken from its respectively
  65351. * GNU commands. The functions will return (bool) false on error and will
  65352. * trigger the error with the PHP trigger_error() function (you can silence
  65353. * the error by prefixing a '@' sign after the function call, but this
  65354. * is not recommended practice. Instead use an error handler with
  65355. * {@link set_error_handler()}).
  65356. *
  65357. * Documentation on this class you can find in:
  65358. * http://pear.php.net/manual/
  65359. *
  65360. * Example usage:
  65361. * if (!@System::rm('-r file1 dir1')) {
  65362. * print "could not delete file1 or dir1";
  65363. * }
  65364. *
  65365. * In case you need to to pass file names with spaces,
  65366. * pass the params as an array:
  65367. *
  65368. * System::rm(array('-r', $file1, $dir1));
  65369. *
  65370. * @category pear
  65371. * @package System
  65372. * @author Tomas V.V. Cox <cox@idecnet.com>
  65373. * @copyright 1997-2006 The PHP Group
  65374. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  65375. * @version Release: 1.10.10
  65376. * @link http://pear.php.net/package/PEAR
  65377. * @since Class available since Release 0.1
  65378. * @static
  65379. */
  65380. class System
  65381. {
  65382. /**
  65383. * returns the commandline arguments of a function
  65384. *
  65385. * @param string $argv the commandline
  65386. * @param string $short_options the allowed option short-tags
  65387. * @param string $long_options the allowed option long-tags
  65388. * @return array the given options and there values
  65389. */
  65390. public static function _parseArgs($argv, $short_options, $long_options = null)
  65391. {
  65392. if (!is_array($argv) && $argv !== null) {
  65393. /*
  65394. // Quote all items that are a short option
  65395. $av = preg_split('/(\A| )--?[a-z0-9]+[ =]?((?<!\\\\)((,\s*)|((?<!,)\s+))?)/i', $argv, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
  65396. $offset = 0;
  65397. foreach ($av as $a) {
  65398. $b = trim($a[0]);
  65399. if ($b[0] == '"' || $b[0] == "'") {
  65400. continue;
  65401. }
  65402. $escape = escapeshellarg($b);
  65403. $pos = $a[1] + $offset;
  65404. $argv = substr_replace($argv, $escape, $pos, strlen($b));
  65405. $offset += 2;
  65406. }
  65407. */
  65408. // Find all items, quoted or otherwise
  65409. preg_match_all("/(?:[\"'])(.*?)(?:['\"])|([^\s]+)/", $argv, $av);
  65410. $argv = $av[1];
  65411. foreach ($av[2] as $k => $a) {
  65412. if (empty($a)) {
  65413. continue;
  65414. }
  65415. $argv[$k] = trim($a) ;
  65416. }
  65417. }
  65418. return Console_Getopt::getopt2($argv, $short_options, $long_options);
  65419. }
  65420. /**
  65421. * Output errors with PHP trigger_error(). You can silence the errors
  65422. * with prefixing a "@" sign to the function call: @System::mkdir(..);
  65423. *
  65424. * @param mixed $error a PEAR error or a string with the error message
  65425. * @return bool false
  65426. */
  65427. protected static function raiseError($error)
  65428. {
  65429. if (PEAR::isError($error)) {
  65430. $error = $error->getMessage();
  65431. }
  65432. trigger_error($error, E_USER_WARNING);
  65433. return false;
  65434. }
  65435. /**
  65436. * Creates a nested array representing the structure of a directory
  65437. *
  65438. * System::_dirToStruct('dir1', 0) =>
  65439. * Array
  65440. * (
  65441. * [dirs] => Array
  65442. * (
  65443. * [0] => dir1
  65444. * )
  65445. *
  65446. * [files] => Array
  65447. * (
  65448. * [0] => dir1/file2
  65449. * [1] => dir1/file3
  65450. * )
  65451. * )
  65452. * @param string $sPath Name of the directory
  65453. * @param integer $maxinst max. deep of the lookup
  65454. * @param integer $aktinst starting deep of the lookup
  65455. * @param bool $silent if true, do not emit errors.
  65456. * @return array the structure of the dir
  65457. */
  65458. protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
  65459. {
  65460. $struct = array('dirs' => array(), 'files' => array());
  65461. if (($dir = @opendir($sPath)) === false) {
  65462. if (!$silent) {
  65463. System::raiseError("Could not open dir $sPath");
  65464. }
  65465. return $struct; // XXX could not open error
  65466. }
  65467. $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
  65468. $list = array();
  65469. while (false !== ($file = readdir($dir))) {
  65470. if ($file != '.' && $file != '..') {
  65471. $list[] = $file;
  65472. }
  65473. }
  65474. closedir($dir);
  65475. natsort($list);
  65476. if ($aktinst < $maxinst || $maxinst == 0) {
  65477. foreach ($list as $val) {
  65478. $path = $sPath . DIRECTORY_SEPARATOR . $val;
  65479. if (is_dir($path) && !is_link($path)) {
  65480. $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
  65481. $struct = array_merge_recursive($struct, $tmp);
  65482. } else {
  65483. $struct['files'][] = $path;
  65484. }
  65485. }
  65486. }
  65487. return $struct;
  65488. }
  65489. /**
  65490. * Creates a nested array representing the structure of a directory and files
  65491. *
  65492. * @param array $files Array listing files and dirs
  65493. * @return array
  65494. * @static
  65495. * @see System::_dirToStruct()
  65496. */
  65497. protected static function _multipleToStruct($files)
  65498. {
  65499. $struct = array('dirs' => array(), 'files' => array());
  65500. settype($files, 'array');
  65501. foreach ($files as $file) {
  65502. if (is_dir($file) && !is_link($file)) {
  65503. $tmp = System::_dirToStruct($file, 0);
  65504. $struct = array_merge_recursive($tmp, $struct);
  65505. } else {
  65506. if (!in_array($file, $struct['files'])) {
  65507. $struct['files'][] = $file;
  65508. }
  65509. }
  65510. }
  65511. return $struct;
  65512. }
  65513. /**
  65514. * The rm command for removing files.
  65515. * Supports multiple files and dirs and also recursive deletes
  65516. *
  65517. * @param string $args the arguments for rm
  65518. * @return mixed PEAR_Error or true for success
  65519. * @static
  65520. * @access public
  65521. */
  65522. public static function rm($args)
  65523. {
  65524. $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
  65525. if (PEAR::isError($opts)) {
  65526. return System::raiseError($opts);
  65527. }
  65528. foreach ($opts[0] as $opt) {
  65529. if ($opt[0] == 'r') {
  65530. $do_recursive = true;
  65531. }
  65532. }
  65533. $ret = true;
  65534. if (isset($do_recursive)) {
  65535. $struct = System::_multipleToStruct($opts[1]);
  65536. foreach ($struct['files'] as $file) {
  65537. if (!@unlink($file)) {
  65538. $ret = false;
  65539. }
  65540. }
  65541. rsort($struct['dirs']);
  65542. foreach ($struct['dirs'] as $dir) {
  65543. if (!@rmdir($dir)) {
  65544. $ret = false;
  65545. }
  65546. }
  65547. } else {
  65548. foreach ($opts[1] as $file) {
  65549. $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
  65550. if (!@$delete($file)) {
  65551. $ret = false;
  65552. }
  65553. }
  65554. }
  65555. return $ret;
  65556. }
  65557. /**
  65558. * Make directories.
  65559. *
  65560. * The -p option will create parent directories
  65561. * @param string $args the name of the director(y|ies) to create
  65562. * @return bool True for success
  65563. */
  65564. public static function mkDir($args)
  65565. {
  65566. $opts = System::_parseArgs($args, 'pm:');
  65567. if (PEAR::isError($opts)) {
  65568. return System::raiseError($opts);
  65569. }
  65570. $mode = 0777; // default mode
  65571. foreach ($opts[0] as $opt) {
  65572. if ($opt[0] == 'p') {
  65573. $create_parents = true;
  65574. } elseif ($opt[0] == 'm') {
  65575. // if the mode is clearly an octal number (starts with 0)
  65576. // convert it to decimal
  65577. if (strlen($opt[1]) && $opt[1][0] == '0') {
  65578. $opt[1] = octdec($opt[1]);
  65579. } else {
  65580. // convert to int
  65581. $opt[1] += 0;
  65582. }
  65583. $mode = $opt[1];
  65584. }
  65585. }
  65586. $ret = true;
  65587. if (isset($create_parents)) {
  65588. foreach ($opts[1] as $dir) {
  65589. $dirstack = array();
  65590. while ((!file_exists($dir) || !is_dir($dir)) &&
  65591. $dir != DIRECTORY_SEPARATOR) {
  65592. array_unshift($dirstack, $dir);
  65593. $dir = dirname($dir);
  65594. }
  65595. while ($newdir = array_shift($dirstack)) {
  65596. if (!is_writeable(dirname($newdir))) {
  65597. $ret = false;
  65598. break;
  65599. }
  65600. if (!mkdir($newdir, $mode)) {
  65601. $ret = false;
  65602. }
  65603. }
  65604. }
  65605. } else {
  65606. foreach($opts[1] as $dir) {
  65607. if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
  65608. $ret = false;
  65609. }
  65610. }
  65611. }
  65612. return $ret;
  65613. }
  65614. /**
  65615. * Concatenate files
  65616. *
  65617. * Usage:
  65618. * 1) $var = System::cat('sample.txt test.txt');
  65619. * 2) System::cat('sample.txt test.txt > final.txt');
  65620. * 3) System::cat('sample.txt test.txt >> final.txt');
  65621. *
  65622. * Note: as the class use fopen, urls should work also
  65623. *
  65624. * @param string $args the arguments
  65625. * @return boolean true on success
  65626. */
  65627. public static function &cat($args)
  65628. {
  65629. $ret = null;
  65630. $files = array();
  65631. if (!is_array($args)) {
  65632. $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
  65633. }
  65634. $count_args = count($args);
  65635. for ($i = 0; $i < $count_args; $i++) {
  65636. if ($args[$i] == '>') {
  65637. $mode = 'wb';
  65638. $outputfile = $args[$i+1];
  65639. break;
  65640. } elseif ($args[$i] == '>>') {
  65641. $mode = 'ab+';
  65642. $outputfile = $args[$i+1];
  65643. break;
  65644. } else {
  65645. $files[] = $args[$i];
  65646. }
  65647. }
  65648. $outputfd = false;
  65649. if (isset($mode)) {
  65650. if (!$outputfd = fopen($outputfile, $mode)) {
  65651. $err = System::raiseError("Could not open $outputfile");
  65652. return $err;
  65653. }
  65654. $ret = true;
  65655. }
  65656. foreach ($files as $file) {
  65657. if (!$fd = fopen($file, 'r')) {
  65658. System::raiseError("Could not open $file");
  65659. continue;
  65660. }
  65661. while ($cont = fread($fd, 2048)) {
  65662. if (is_resource($outputfd)) {
  65663. fwrite($outputfd, $cont);
  65664. } else {
  65665. $ret .= $cont;
  65666. }
  65667. }
  65668. fclose($fd);
  65669. }
  65670. if (is_resource($outputfd)) {
  65671. fclose($outputfd);
  65672. }
  65673. return $ret;
  65674. }
  65675. /**
  65676. * Creates temporary files or directories. This function will remove
  65677. * the created files when the scripts finish its execution.
  65678. *
  65679. * Usage:
  65680. * 1) $tempfile = System::mktemp("prefix");
  65681. * 2) $tempdir = System::mktemp("-d prefix");
  65682. * 3) $tempfile = System::mktemp();
  65683. * 4) $tempfile = System::mktemp("-t /var/tmp prefix");
  65684. *
  65685. * prefix -> The string that will be prepended to the temp name
  65686. * (defaults to "tmp").
  65687. * -d -> A temporary dir will be created instead of a file.
  65688. * -t -> The target dir where the temporary (file|dir) will be created. If
  65689. * this param is missing by default the env vars TMP on Windows or
  65690. * TMPDIR in Unix will be used. If these vars are also missing
  65691. * c:\windows\temp or /tmp will be used.
  65692. *
  65693. * @param string $args The arguments
  65694. * @return mixed the full path of the created (file|dir) or false
  65695. * @see System::tmpdir()
  65696. */
  65697. public static function mktemp($args = null)
  65698. {
  65699. static $first_time = true;
  65700. $opts = System::_parseArgs($args, 't:d');
  65701. if (PEAR::isError($opts)) {
  65702. return System::raiseError($opts);
  65703. }
  65704. foreach ($opts[0] as $opt) {
  65705. if ($opt[0] == 'd') {
  65706. $tmp_is_dir = true;
  65707. } elseif ($opt[0] == 't') {
  65708. $tmpdir = $opt[1];
  65709. }
  65710. }
  65711. $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
  65712. if (!isset($tmpdir)) {
  65713. $tmpdir = System::tmpdir();
  65714. }
  65715. if (!System::mkDir(array('-p', $tmpdir))) {
  65716. return false;
  65717. }
  65718. $tmp = tempnam($tmpdir, $prefix);
  65719. if (isset($tmp_is_dir)) {
  65720. unlink($tmp); // be careful possible race condition here
  65721. if (!mkdir($tmp, 0700)) {
  65722. return System::raiseError("Unable to create temporary directory $tmpdir");
  65723. }
  65724. }
  65725. $GLOBALS['_System_temp_files'][] = $tmp;
  65726. if (isset($tmp_is_dir)) {
  65727. //$GLOBALS['_System_temp_files'][] = dirname($tmp);
  65728. }
  65729. if ($first_time) {
  65730. PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
  65731. $first_time = false;
  65732. }
  65733. return $tmp;
  65734. }
  65735. /**
  65736. * Remove temporary files created my mkTemp. This function is executed
  65737. * at script shutdown time
  65738. */
  65739. public static function _removeTmpFiles()
  65740. {
  65741. if (count($GLOBALS['_System_temp_files'])) {
  65742. $delete = $GLOBALS['_System_temp_files'];
  65743. array_unshift($delete, '-r');
  65744. System::rm($delete);
  65745. $GLOBALS['_System_temp_files'] = array();
  65746. }
  65747. }
  65748. /**
  65749. * Get the path of the temporal directory set in the system
  65750. * by looking in its environments variables.
  65751. * Note: php.ini-recommended removes the "E" from the variables_order setting,
  65752. * making unavaible the $_ENV array, that s why we do tests with _ENV
  65753. *
  65754. * @return string The temporary directory on the system
  65755. */
  65756. public static function tmpdir()
  65757. {
  65758. if (OS_WINDOWS) {
  65759. if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
  65760. return $var;
  65761. }
  65762. if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
  65763. return $var;
  65764. }
  65765. if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
  65766. return $var;
  65767. }
  65768. if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
  65769. return $var;
  65770. }
  65771. return getenv('SystemRoot') . '\temp';
  65772. }
  65773. if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
  65774. return $var;
  65775. }
  65776. return realpath(function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '/tmp');
  65777. }
  65778. /**
  65779. * The "which" command (show the full path of a command)
  65780. *
  65781. * @param string $program The command to search for
  65782. * @param mixed $fallback Value to return if $program is not found
  65783. *
  65784. * @return mixed A string with the full path or false if not found
  65785. * @author Stig Bakken <ssb@php.net>
  65786. */
  65787. public static function which($program, $fallback = false)
  65788. {
  65789. // enforce API
  65790. if (!is_string($program) || '' == $program) {
  65791. return $fallback;
  65792. }
  65793. // full path given
  65794. if (basename($program) != $program) {
  65795. $path_elements[] = dirname($program);
  65796. $program = basename($program);
  65797. } else {
  65798. $path = getenv('PATH');
  65799. if (!$path) {
  65800. $path = getenv('Path'); // some OSes are just stupid enough to do this
  65801. }
  65802. $path_elements = explode(PATH_SEPARATOR, $path);
  65803. }
  65804. if (OS_WINDOWS) {
  65805. $exe_suffixes = getenv('PATHEXT')
  65806. ? explode(PATH_SEPARATOR, getenv('PATHEXT'))
  65807. : array('.exe','.bat','.cmd','.com');
  65808. // allow passing a command.exe param
  65809. if (strpos($program, '.') !== false) {
  65810. array_unshift($exe_suffixes, '');
  65811. }
  65812. } else {
  65813. $exe_suffixes = array('');
  65814. }
  65815. foreach ($exe_suffixes as $suff) {
  65816. foreach ($path_elements as $dir) {
  65817. $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
  65818. // It's possible to run a .bat on Windows that is_executable
  65819. // would return false for. The is_executable check is meaningless...
  65820. if (OS_WINDOWS) {
  65821. return $file;
  65822. } else {
  65823. if (is_executable($file)) {
  65824. return $file;
  65825. }
  65826. }
  65827. }
  65828. }
  65829. return $fallback;
  65830. }
  65831. /**
  65832. * The "find" command
  65833. *
  65834. * Usage:
  65835. *
  65836. * System::find($dir);
  65837. * System::find("$dir -type d");
  65838. * System::find("$dir -type f");
  65839. * System::find("$dir -name *.php");
  65840. * System::find("$dir -name *.php -name *.htm*");
  65841. * System::find("$dir -maxdepth 1");
  65842. *
  65843. * Params implemented:
  65844. * $dir -> Start the search at this directory
  65845. * -type d -> return only directories
  65846. * -type f -> return only files
  65847. * -maxdepth <n> -> max depth of recursion
  65848. * -name <pattern> -> search pattern (bash style). Multiple -name param allowed
  65849. *
  65850. * @param mixed Either array or string with the command line
  65851. * @return array Array of found files
  65852. */
  65853. public static function find($args)
  65854. {
  65855. if (!is_array($args)) {
  65856. $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
  65857. }
  65858. $dir = realpath(array_shift($args));
  65859. if (!$dir) {
  65860. return array();
  65861. }
  65862. $patterns = array();
  65863. $depth = 0;
  65864. $do_files = $do_dirs = true;
  65865. $args_count = count($args);
  65866. for ($i = 0; $i < $args_count; $i++) {
  65867. switch ($args[$i]) {
  65868. case '-type':
  65869. if (in_array($args[$i+1], array('d', 'f'))) {
  65870. if ($args[$i+1] == 'd') {
  65871. $do_files = false;
  65872. } else {
  65873. $do_dirs = false;
  65874. }
  65875. }
  65876. $i++;
  65877. break;
  65878. case '-name':
  65879. $name = preg_quote($args[$i+1], '#');
  65880. // our magic characters ? and * have just been escaped,
  65881. // so now we change the escaped versions to PCRE operators
  65882. $name = strtr($name, array('\?' => '.', '\*' => '.*'));
  65883. $patterns[] = '('.$name.')';
  65884. $i++;
  65885. break;
  65886. case '-maxdepth':
  65887. $depth = $args[$i+1];
  65888. break;
  65889. }
  65890. }
  65891. $path = System::_dirToStruct($dir, $depth, 0, true);
  65892. if ($do_files && $do_dirs) {
  65893. $files = array_merge($path['files'], $path['dirs']);
  65894. } elseif ($do_dirs) {
  65895. $files = $path['dirs'];
  65896. } else {
  65897. $files = $path['files'];
  65898. }
  65899. if (count($patterns)) {
  65900. $dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
  65901. $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#';
  65902. $ret = array();
  65903. $files_count = count($files);
  65904. for ($i = 0; $i < $files_count; $i++) {
  65905. // only search in the part of the file below the current directory
  65906. $filepart = basename($files[$i]);
  65907. if (preg_match($pattern, $filepart)) {
  65908. $ret[] = $files[$i];
  65909. }
  65910. }
  65911. return $ret;
  65912. }
  65913. return $files;
  65914. }
  65915. }
  65916. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PEAR-1.10.10/template.spec��������������������������������������������������������������������������0000644�0001750�0001750�00000003725�13565304531�014754� 0����������������������������������������������������������������������������������������������������ustar �ashnazg�������������������������ashnazg����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Summary: PEAR: @summary@
  65917. Name: @rpm_package@
  65918. Version: @version@
  65919. Release: 1
  65920. License: @release_license@
  65921. Group: Development/Libraries
  65922. Source: http://@master_server@/get/@package@-%{version}.tgz
  65923. BuildRoot: %{_tmppath}/%{name}-root
  65924. URL: http://@master_server@/package/@package@
  65925. Prefix: %{_prefix}
  65926. BuildArchitectures: @arch@
  65927. @extra_headers@
  65928. %description
  65929. @description@
  65930. %prep
  65931. rm -rf %{buildroot}/*
  65932. %setup -c -T
  65933. # XXX Source files location is missing here in pear cmd
  65934. pear -v -c %{buildroot}/pearrc \
  65935. -d php_dir=%{_libdir}/php/pear \
  65936. -d doc_dir=/docs \
  65937. -d bin_dir=%{_bindir} \
  65938. -d data_dir=%{_libdir}/php/pear/data \
  65939. -d test_dir=%{_libdir}/php/pear/tests \
  65940. -d ext_dir=%{_libdir} \@extra_config@
  65941. -s
  65942. %build
  65943. echo BuildRoot=%{buildroot}
  65944. %postun
  65945. # if refcount = 0 then package has been removed (not upgraded)
  65946. if [ "$1" -eq "0" ]; then
  65947. pear uninstall --nodeps -r @possible_channel@@package@
  65948. rm @rpm_xml_dir@/@package@.xml
  65949. fi
  65950. %post
  65951. # if refcount = 2 then package has been upgraded
  65952. if [ "$1" -ge "2" ]; then
  65953. pear upgrade --nodeps -r @rpm_xml_dir@/@package@.xml
  65954. else
  65955. pear install --nodeps -r @rpm_xml_dir@/@package@.xml
  65956. fi
  65957. %install
  65958. pear -c %{buildroot}/pearrc install --nodeps -R %{buildroot} \
  65959. $RPM_SOURCE_DIR/@package@-%{version}.tgz
  65960. rm %{buildroot}/pearrc
  65961. rm %{buildroot}/%{_libdir}/php/pear/.filemap
  65962. rm %{buildroot}/%{_libdir}/php/pear/.lock
  65963. rm -rf %{buildroot}/%{_libdir}/php/pear/.registry
  65964. if [ "@doc_files@" != "" ]; then
  65965. mv %{buildroot}/docs/@package@/* .
  65966. rm -rf %{buildroot}/docs
  65967. fi
  65968. mkdir -p %{buildroot}@rpm_xml_dir@
  65969. tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package@package2xml@.xml
  65970. cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml
  65971. #rm -rf %{buildroot}/*
  65972. #pear -q install -R %{buildroot} -n package@package2xml@.xml
  65973. #mkdir -p %{buildroot}@rpm_xml_dir@
  65974. #cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml
  65975. %files
  65976. %defattr(-,root,root)
  65977. %doc @doc_files@
  65978. /
  65979. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������package.xml�����������������������������������������������������������������������������������������0000644�0001750�0000144�00000012470�12553252061�012551 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?>
  65980. <package packagerversion="1.9.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  65981. <name>Structures_Graph</name>
  65982. <channel>pear.php.net</channel>
  65983. <summary>Graph datastructure manipulation library</summary>
  65984. <description>Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed
  65985. and undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing
  65986. as well as for characteristic extraction from the graph topology.</description>
  65987. <lead>
  65988. <name>Sérgio Carvalho</name>
  65989. <user>sergiosgc</user>
  65990. <email>sergio.carvalho@portugalmail.com</email>
  65991. <active>yes</active>
  65992. </lead>
  65993. <helper>
  65994. <name>Brett Bieber</name>
  65995. <user>saltybeagle</user>
  65996. <email>brett.bieber@gmail.com</email>
  65997. <active>yes</active>
  65998. </helper>
  65999. <date>2015-07-20</date>
  66000. <time>20:04:01</time>
  66001. <version>
  66002. <release>1.1.1</release>
  66003. <api>1.1.0</api>
  66004. </version>
  66005. <stability>
  66006. <release>stable</release>
  66007. <api>stable</api>
  66008. </stability>
  66009. <license>LGPL-3.0+</license>
  66010. <notes>
  66011. * Fix deprecated constructor warning on PHP 7 [cweiske]
  66012. </notes>
  66013. <contents>
  66014. <dir baseinstalldir="/" name="/">
  66015. <file baseinstalldir="/" md5sum="628eb6532a8047bf5962fe24c1c245df" name="docs/tutorials/Structures_Graph/Structures_Graph.pkg" role="doc" />
  66016. <file baseinstalldir="/" md5sum="4b26eecd30f8695fc3739b1a5b59518e" name="Structures/Graph/Manipulator/AcyclicTest.php" role="php" />
  66017. <file baseinstalldir="/" md5sum="1f857de1fbbaace54b857ed9712f399f" name="Structures/Graph/Manipulator/TopologicalSorter.php" role="php" />
  66018. <file baseinstalldir="/" md5sum="f8e969f0b45d3859408901c8350bb701" name="Structures/Graph/Node.php" role="php" />
  66019. <file baseinstalldir="/" md5sum="88ae1ad8bcd74d4b74ad845f55611cdd" name="Structures/Graph.php" role="php" />
  66020. <file baseinstalldir="/" md5sum="65e4e85e573833516f5cc1d7a81db9c5" name="tests/AllTests.php" role="test" />
  66021. <file baseinstalldir="/" md5sum="68ba309e2ac6713527f0fd31456457a1" name="tests/BasicGraphTest.php" role="test" />
  66022. <file baseinstalldir="/" md5sum="190fc4634be55cd98608b72bc9d0a27f" name="tests/TopologicalSorterTest.php" role="test" />
  66023. <file baseinstalldir="/" md5sum="4dc0c43f054732ec0f2fc78458ebadde" name="tests/AcyclicTestTest.php" role="test" />
  66024. <file baseinstalldir="/" md5sum="68ba309e2ac6713527f0fd31456457a1" name="tests/BasicGraphTest.php" role="test" />
  66025. <file baseinstalldir="/" md5sum="c891580ee21a7aa863ac32566c979fc5" name="tests/helper.inc" role="test">
  66026. <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  66027. </file>
  66028. <file baseinstalldir="/" md5sum="b52f2d57d10c4f7ee67a7eb9615d5d24" name="LICENSE" role="doc" />
  66029. </dir>
  66030. </contents>
  66031. <compatible>
  66032. <name>PEAR</name>
  66033. <channel>pear.php.net</channel>
  66034. <min>1.5.0RC3</min>
  66035. <max>1.9.1</max>
  66036. </compatible>
  66037. <dependencies>
  66038. <required>
  66039. <php>
  66040. <min>5.3.0</min>
  66041. </php>
  66042. <pearinstaller>
  66043. <min>1.4.3</min>
  66044. </pearinstaller>
  66045. </required>
  66046. </dependencies>
  66047. <phprelease />
  66048. <changelog>
  66049. <release>
  66050. <version>
  66051. <release>1.0.2</release>
  66052. <api>1.0.0</api>
  66053. </version>
  66054. <stability>
  66055. <release>stable</release>
  66056. <api>stable</api>
  66057. </stability>
  66058. <date>2007-01-07</date>
  66059. <license uri="http://opensource.org/licenses/lgpl-license.php">LGPL</license>
  66060. <notes>
  66061. - Bug #9682 only variables can be returned by reference
  66062. - fix Bug #9661 notice in Structures_Graph_Manipulator_Topological::sort()
  66063. </notes>
  66064. </release>
  66065. <release>
  66066. <version>
  66067. <release>1.0.3</release>
  66068. <api>1.0.3</api>
  66069. </version>
  66070. <stability>
  66071. <release>stable</release>
  66072. <api>stable</api>
  66073. </stability>
  66074. <date>2009-10-11</date>
  66075. <license>LGPL License</license>
  66076. <notes>
  66077. Bugfix Release:
  66078. Version 1.0.3 is functionally equivalent to 1.0.2 but with an updated package.xml file.
  66079. * Correct invalid md5 sum preventing installation with pyrus [saltybeagle]
  66080. * Add compatible tag for PEAR 1.5.0RC3-1.9.0 [saltybeagle]
  66081. * Update package.xml
  66082. </notes>
  66083. </release>
  66084. <release>
  66085. <version>
  66086. <release>1.0.4</release>
  66087. <api>1.0.3</api>
  66088. </version>
  66089. <stability>
  66090. <release>stable</release>
  66091. <api>stable</api>
  66092. </stability>
  66093. <date>2010-10-25</date>
  66094. <license>LGPL License</license>
  66095. <notes>
  66096. Bugfix Release:
  66097. * Bug #17108 BasicGraph::test_directed_degree fails on PHP 5 [clockwerx]
  66098. </notes>
  66099. </release>
  66100. <release>
  66101. <version>
  66102. <release>1.1.0</release>
  66103. <api>1.1.0</api>
  66104. </version>
  66105. <stability>
  66106. <release>stable</release>
  66107. <api>stable</api>
  66108. </stability>
  66109. <date>2015-02-26</date>
  66110. <license>LGPL-3.0+</license>
  66111. <notes>
  66112. * Set minimum PHP version to 5.3
  66113. * Fix bug #19367: Incorrect FSF address in LICENSE
  66114. * Change license from LGPL-2.1+ to LGPL-3.0+
  66115. </notes>
  66116. </release>
  66117. <release>
  66118. <version>
  66119. <release>1.1.1</release>
  66120. <api>1.1.0</api>
  66121. </version>
  66122. <stability>
  66123. <release>stable</release>
  66124. <api>stable</api>
  66125. </stability>
  66126. <date>2015-07-20</date>
  66127. <license>LGPL-3.0+</license>
  66128. <notes>
  66129. * Fix deprecated constructor warning on PHP 7 [cweiske]
  66130. </notes>
  66131. </release>
  66132. </changelog>
  66133. </package>
  66134. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/docs/tutorials/Structures_Graph/Structures_Graph.pkg�������������������������0000644�0001750�0000144�00000007714�12553252061�026672 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<refentry id="{@id package.database.structures_graph.tutorial}">
  66135. <refnamediv>
  66136. <refname><classname>Structures_Graph</classname> Tutorial</refname>
  66137. <refpurpose>A first tour of graph datastructure manipulation</refpurpose>
  66138. </refnamediv>
  66139. <refsect1 id="{@id package.database.structures_graph.tutorial.intro}">
  66140. <title>Introduction</title>
  66141. <para>
  66142. Structures_Graph is a package for creating and manipulating graph datastructures. A graph is a set of objects, called nodes, connected by arcs. When used as a datastructure, usually nodes contain data, and arcs represent relationships between nodes. When arcs have a direction, and can be travelled only one way, graphs are said to be directed. When arcs have no direction, and can always be travelled both ways, graphs are said to be non directed.
  66143. </para>
  66144. <para>
  66145. Structures_Graph provides an object oriented API to create and directly query a graph, as well as a set of Manipulator classes to extract information from the graph.
  66146. </para>
  66147. </refsect1>
  66148. <refsect1 id="{@id package.database.structures_graph.tutorial.creation}">
  66149. <title>Creating a Graph</title>
  66150. <para>
  66151. Creating a graph is done using the simple constructor:
  66152. <programlisting>
  66153. <![CDATA[
  66154. require_once 'Structures/Graph.php';
  66155. $directedGraph =& new Structures_Graph(true);
  66156. $nonDirectedGraph =& new Structures_Graph(false);
  66157. ]]>
  66158. </programlisting>
  66159. and passing the constructor a flag telling it whether the graph should be directed. A directed graph will always be directed during its lifetime. It's a permanent characteristic.
  66160. </para>
  66161. <para>
  66162. To fill out the graph, we'll need to create some nodes, and then call Graph::addNode.
  66163. <programlisting>
  66164. <![CDATA[
  66165. require_once 'Structures/Graph/Node.php';
  66166. $nodeOne =& new Structures_Graph_Node();
  66167. $nodeTwo =& new Structures_Graph_Node();
  66168. $nodeThree =& new Structures_Graph_Node();
  66169. $directedGraph->addNode(&$nodeOne);
  66170. $directedGraph->addNode(&$nodeTwo);
  66171. $directedGraph->addNode(&$nodeThree);
  66172. ]]>
  66173. </programlisting>
  66174. and then setup the arcs:
  66175. <programlisting>
  66176. <![CDATA[
  66177. $nodeOne->connectTo($nodeTwo);
  66178. $nodeOne->connectTo($nodeThree);
  66179. ]]>
  66180. </programlisting>
  66181. Note that arcs can only be created after the nodes have been inserted into the graph.
  66182. </para>
  66183. </refsect1>
  66184. <refsect1 id="{@id package.database.structures_graph.tutorial.nodesanddata}">
  66185. <title>Associating Data</title>
  66186. <para>
  66187. Graphs are only useful as datastructures if they can hold data. Structure_Graph stores data in nodes. Each node contains a setter and a getter for its data.
  66188. <programlisting>
  66189. <![CDATA[
  66190. $nodeOne->setData("Node One's Data is a String");
  66191. $nodeTwo->setData(1976);
  66192. $nodeThree->setData('Some other string');
  66193. print("NodeTwo's Data is an integer: " . $nodeTwo->getData());
  66194. ]]>
  66195. </programlisting>
  66196. </para>
  66197. <para>
  66198. Structure_Graph nodes can also store metadata, alongside with the main data. Metadata differs from regular data just because it is stored under a key, making it possible to store more than one data reference per node. The metadata getter and setter need the key to perform the operation:
  66199. <programlisting>
  66200. <![CDATA[
  66201. $nodeOne->setMetadata('example key', "Node One's Sample Metadata");
  66202. print("Metadata stored under key 'example key' in node one: " . $nodeOne->getMetadata('example key'));
  66203. $nodeOne->unsetMetadata('example key');
  66204. ]]>
  66205. </programlisting>
  66206. </para>
  66207. </refsect1>
  66208. <refsect1 id="{@id package.database.structures_graph.tutorial.querying}">
  66209. <title>Querying a Graph</title>
  66210. <para>
  66211. Structures_Graph provides for basic querying of the graph:
  66212. <programlisting>
  66213. <![CDATA[
  66214. // Nodes are able to calculate their indegree and outdegree
  66215. print("NodeOne's inDegree: " . $nodeOne->inDegree());
  66216. print("NodeOne's outDegree: " . $nodeOne->outDegree());
  66217. // and naturally, nodes can report on their arcs
  66218. $arcs = $nodeOne->getNeighbours();
  66219. for ($i=0;$i<sizeof($arcs);$i++) {
  66220. print("NodeOne has an arc to " . $arcs[$i]->getData());
  66221. }
  66222. ]]>
  66223. </programlisting>
  66224. </para>
  66225. </refsect1>
  66226. </refentry>
  66227. ����������������������������������������������������Structures_Graph-1.1.1/Structures/Graph/Manipulator/AcyclicTest.php���������������������������������0000644�0001750�0000144�00000013201�12553252061�025024 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  66228. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  66229. // +-----------------------------------------------------------------------------+
  66230. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  66231. // +-----------------------------------------------------------------------------+
  66232. // | This file is part of Structures_Graph. |
  66233. // | |
  66234. // | Structures_Graph is free software; you can redistribute it and/or modify |
  66235. // | it under the terms of the GNU Lesser General Public License as published by |
  66236. // | the Free Software Foundation; either version 2.1 of the License, or |
  66237. // | (at your option) any later version. |
  66238. // | |
  66239. // | Structures_Graph is distributed in the hope that it will be useful, |
  66240. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  66241. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  66242. // | GNU Lesser General Public License for more details. |
  66243. // | |
  66244. // | You should have received a copy of the GNU Lesser General Public License |
  66245. // | along with Structures_Graph; if not, write to the Free Software |
  66246. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  66247. // | 02111-1307 USA |
  66248. // +-----------------------------------------------------------------------------+
  66249. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  66250. // +-----------------------------------------------------------------------------+
  66251. //
  66252. /**
  66253. * This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator.
  66254. *
  66255. * @see Structures_Graph_Manipulator_AcyclicTest
  66256. * @package Structures_Graph
  66257. */
  66258. /* dependencies {{{ */
  66259. /** */
  66260. require_once 'PEAR.php';
  66261. /** */
  66262. require_once 'Structures/Graph.php';
  66263. /** */
  66264. require_once 'Structures/Graph/Node.php';
  66265. /* }}} */
  66266. /* class Structures_Graph_Manipulator_AcyclicTest {{{ */
  66267. /**
  66268. * The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator
  66269. * which tests whether a graph contains a cycle.
  66270. *
  66271. * The definition of an acyclic graph used in this manipulator is that of a
  66272. * DAG. The graph must be directed, or else it is considered cyclic, even when
  66273. * there are no arcs.
  66274. *
  66275. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  66276. * @copyright (c) 2004 by Sérgio Carvalho
  66277. * @package Structures_Graph
  66278. */
  66279. class Structures_Graph_Manipulator_AcyclicTest {
  66280. /* _nonVisitedInDegree {{{ */
  66281. /**
  66282. *
  66283. * This is a variant of Structures_Graph::inDegree which does
  66284. * not count nodes marked as visited.
  66285. *
  66286. * @return integer Number of non-visited nodes that link to this one
  66287. */
  66288. protected static function _nonVisitedInDegree(&$node) {
  66289. $result = 0;
  66290. $graphNodes =& $node->_graph->getNodes();
  66291. foreach (array_keys($graphNodes) as $key) {
  66292. if ((!$graphNodes[$key]->getMetadata('acyclic-test-visited')) && $graphNodes[$key]->connectsTo($node)) $result++;
  66293. }
  66294. return $result;
  66295. }
  66296. /* }}} */
  66297. /* _isAcyclic {{{ */
  66298. /**
  66299. * Check if the graph is acyclic
  66300. */
  66301. protected static function _isAcyclic(&$graph) {
  66302. // Mark every node as not visited
  66303. $nodes =& $graph->getNodes();
  66304. $nodeKeys = array_keys($nodes);
  66305. $refGenerator = array();
  66306. foreach($nodeKeys as $key) {
  66307. $refGenerator[] = false;
  66308. $nodes[$key]->setMetadata('acyclic-test-visited', $refGenerator[sizeof($refGenerator) - 1]);
  66309. }
  66310. // Iteratively peel off leaf nodes
  66311. do {
  66312. // Find out which nodes are leafs (excluding visited nodes)
  66313. $leafNodes = array();
  66314. foreach($nodeKeys as $key) {
  66315. if ((!$nodes[$key]->getMetadata('acyclic-test-visited')) && Structures_Graph_Manipulator_AcyclicTest::_nonVisitedInDegree($nodes[$key]) == 0) {
  66316. $leafNodes[] =& $nodes[$key];
  66317. }
  66318. }
  66319. // Mark leafs as visited
  66320. for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) {
  66321. $visited =& $leafNodes[$i]->getMetadata('acyclic-test-visited');
  66322. $visited = true;
  66323. $leafNodes[$i]->setMetadata('acyclic-test-visited', $visited);
  66324. }
  66325. } while (sizeof($leafNodes) > 0);
  66326. // If graph is a DAG, there should be no non-visited nodes. Let's try to prove otherwise
  66327. $result = true;
  66328. foreach($nodeKeys as $key) if (!$nodes[$key]->getMetadata('acyclic-test-visited')) $result = false;
  66329. // Cleanup visited marks
  66330. foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('acyclic-test-visited');
  66331. return $result;
  66332. }
  66333. /* }}} */
  66334. /* isAcyclic {{{ */
  66335. /**
  66336. *
  66337. * isAcyclic returns true if a graph contains no cycles, false otherwise.
  66338. *
  66339. * @return boolean true iff graph is acyclic
  66340. */
  66341. public static function isAcyclic(&$graph) {
  66342. // We only test graphs
  66343. if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_AcyclicTest::isAcyclic received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  66344. if (!$graph->isDirected()) return false; // Only directed graphs may be acyclic
  66345. return Structures_Graph_Manipulator_AcyclicTest::_isAcyclic($graph);
  66346. }
  66347. /* }}} */
  66348. }
  66349. /* }}} */
  66350. ?>
  66351. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/Structures/Graph/Manipulator/TopologicalSorter.php���������������������������0000644�0001750�0000144�00000015564�12553252061�026306 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  66352. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  66353. // +-----------------------------------------------------------------------------+
  66354. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  66355. // +-----------------------------------------------------------------------------+
  66356. // | This file is part of Structures_Graph. |
  66357. // | |
  66358. // | Structures_Graph is free software; you can redistribute it and/or modify |
  66359. // | it under the terms of the GNU Lesser General Public License as published by |
  66360. // | the Free Software Foundation; either version 2.1 of the License, or |
  66361. // | (at your option) any later version. |
  66362. // | |
  66363. // | Structures_Graph is distributed in the hope that it will be useful, |
  66364. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  66365. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  66366. // | GNU Lesser General Public License for more details. |
  66367. // | |
  66368. // | You should have received a copy of the GNU Lesser General Public License |
  66369. // | along with Structures_Graph; if not, write to the Free Software |
  66370. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  66371. // | 02111-1307 USA |
  66372. // +-----------------------------------------------------------------------------+
  66373. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  66374. // +-----------------------------------------------------------------------------+
  66375. //
  66376. /**
  66377. * This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class.
  66378. *
  66379. * @package Structures_Graph
  66380. */
  66381. require_once 'PEAR.php';
  66382. require_once 'Structures/Graph.php';
  66383. require_once 'Structures/Graph/Node.php';
  66384. require_once 'Structures/Graph/Manipulator/AcyclicTest.php';
  66385. /**
  66386. * The Structures_Graph_Manipulator_TopologicalSorter is a manipulator
  66387. * which is able to return the set of nodes in a graph, sorted by topological
  66388. * order.
  66389. *
  66390. * A graph may only be sorted topologically iff it's a DAG. You can test it
  66391. * with the Structures_Graph_Manipulator_AcyclicTest.
  66392. *
  66393. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  66394. * @copyright (c) 2004 by Sérgio Carvalho
  66395. * @see Structures_Graph_Manipulator_AcyclicTest
  66396. * @package Structures_Graph
  66397. */
  66398. class Structures_Graph_Manipulator_TopologicalSorter
  66399. {
  66400. /**
  66401. * This is a variant of Structures_Graph::inDegree which does
  66402. * not count nodes marked as visited.
  66403. *
  66404. * @param object $node Node to check
  66405. *
  66406. * @return integer Number of non-visited nodes that link to this one
  66407. */
  66408. protected static function _nonVisitedInDegree(&$node)
  66409. {
  66410. $result = 0;
  66411. $graphNodes =& $node->_graph->getNodes();
  66412. foreach (array_keys($graphNodes) as $key) {
  66413. if ((!$graphNodes[$key]->getMetadata('topological-sort-visited'))
  66414. && $graphNodes[$key]->connectsTo($node)
  66415. ) {
  66416. $result++;
  66417. }
  66418. }
  66419. return $result;
  66420. }
  66421. /**
  66422. * Sort implementation
  66423. *
  66424. * @param object $graph Graph to sort
  66425. *
  66426. * @return void
  66427. */
  66428. protected static function _sort(&$graph)
  66429. {
  66430. // Mark every node as not visited
  66431. $nodes =& $graph->getNodes();
  66432. $nodeKeys = array_keys($nodes);
  66433. $refGenerator = array();
  66434. foreach ($nodeKeys as $key) {
  66435. $refGenerator[] = false;
  66436. $nodes[$key]->setMetadata(
  66437. 'topological-sort-visited',
  66438. $refGenerator[sizeof($refGenerator) - 1]
  66439. );
  66440. }
  66441. // Iteratively peel off leaf nodes
  66442. $topologicalLevel = 0;
  66443. do {
  66444. // Find out which nodes are leafs (excluding visited nodes)
  66445. $leafNodes = array();
  66446. foreach ($nodeKeys as $key) {
  66447. if ((!$nodes[$key]->getMetadata('topological-sort-visited'))
  66448. && static::_nonVisitedInDegree($nodes[$key]) == 0
  66449. ) {
  66450. $leafNodes[] =& $nodes[$key];
  66451. }
  66452. }
  66453. // Mark leafs as visited
  66454. $refGenerator[] = $topologicalLevel;
  66455. for ($i = sizeof($leafNodes) - 1; $i>=0; $i--) {
  66456. $visited =& $leafNodes[$i]->getMetadata('topological-sort-visited');
  66457. $visited = true;
  66458. $leafNodes[$i]->setMetadata('topological-sort-visited', $visited);
  66459. $leafNodes[$i]->setMetadata(
  66460. 'topological-sort-level',
  66461. $refGenerator[sizeof($refGenerator) - 1]
  66462. );
  66463. }
  66464. $topologicalLevel++;
  66465. } while (sizeof($leafNodes) > 0);
  66466. // Cleanup visited marks
  66467. foreach ($nodeKeys as $key) {
  66468. $nodes[$key]->unsetMetadata('topological-sort-visited');
  66469. }
  66470. }
  66471. /**
  66472. * Sort returns the graph's nodes, sorted by topological order.
  66473. *
  66474. * The result is an array with as many entries as topological levels.
  66475. * Each entry in this array is an array of nodes within
  66476. * the given topological level.
  66477. *
  66478. * @param object $graph Graph to sort
  66479. *
  66480. * @return array The graph's nodes, sorted by topological order.
  66481. */
  66482. public static function sort(&$graph)
  66483. {
  66484. // We only sort graphs
  66485. if (!is_a($graph, 'Structures_Graph')) {
  66486. return Pear::raiseError(
  66487. 'Structures_Graph_Manipulator_TopologicalSorter::sort received'
  66488. . ' an object that is not a Structures_Graph',
  66489. STRUCTURES_GRAPH_ERROR_GENERIC
  66490. );
  66491. }
  66492. if (!Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph)) {
  66493. return Pear::raiseError(
  66494. 'Structures_Graph_Manipulator_TopologicalSorter::sort'
  66495. . ' received an graph that has cycles',
  66496. STRUCTURES_GRAPH_ERROR_GENERIC
  66497. );
  66498. }
  66499. Structures_Graph_Manipulator_TopologicalSorter::_sort($graph);
  66500. $result = array();
  66501. // Fill out result array
  66502. $nodes =& $graph->getNodes();
  66503. $nodeKeys = array_keys($nodes);
  66504. foreach ($nodeKeys as $key) {
  66505. if (!array_key_exists($nodes[$key]->getMetadata('topological-sort-level'), $result)) {
  66506. $result[$nodes[$key]->getMetadata('topological-sort-level')]
  66507. = array();
  66508. }
  66509. $result[$nodes[$key]->getMetadata('topological-sort-level')][]
  66510. =& $nodes[$key];
  66511. $nodes[$key]->unsetMetadata('topological-sort-level');
  66512. }
  66513. return $result;
  66514. }
  66515. }
  66516. ?>
  66517. ��������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/Structures/Graph/Node.php����������������������������������������������������0000644�0001750�0000144�00000025440�12553252061�021217 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  66518. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  66519. // +-----------------------------------------------------------------------------+
  66520. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  66521. // +-----------------------------------------------------------------------------+
  66522. // | This file is part of Structures_Graph. |
  66523. // | |
  66524. // | Structures_Graph is free software; you can redistribute it and/or modify |
  66525. // | it under the terms of the GNU Lesser General Public License as published by |
  66526. // | the Free Software Foundation; either version 2.1 of the License, or |
  66527. // | (at your option) any later version. |
  66528. // | |
  66529. // | Structures_Graph is distributed in the hope that it will be useful, |
  66530. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  66531. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  66532. // | GNU Lesser General Public License for more details. |
  66533. // | |
  66534. // | You should have received a copy of the GNU Lesser General Public License |
  66535. // | along with Structures_Graph; if not, write to the Free Software |
  66536. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  66537. // | 02111-1307 USA |
  66538. // +-----------------------------------------------------------------------------+
  66539. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  66540. // +-----------------------------------------------------------------------------+
  66541. //
  66542. /**
  66543. * This file contains the definition of the Structures_Graph_Node class
  66544. *
  66545. * @see Structures_Graph_Node
  66546. * @package Structures_Graph
  66547. */
  66548. /* dependencies {{{ */
  66549. /** */
  66550. require_once 'PEAR.php';
  66551. /** */
  66552. require_once 'Structures/Graph.php';
  66553. /* }}} */
  66554. /* class Structures_Graph_Node {{{ */
  66555. /**
  66556. * The Structures_Graph_Node class represents a Node that can be member of a
  66557. * graph node set.
  66558. *
  66559. * A graph node can contain data. Under this API, the node contains default data,
  66560. * and key index data. It behaves, thus, both as a regular data node, and as a
  66561. * dictionary (or associative array) node.
  66562. *
  66563. * Regular data is accessed via getData and setData. Key indexed data is accessed
  66564. * via getMetadata and setMetadata.
  66565. *
  66566. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  66567. * @copyright (c) 2004 by Sérgio Carvalho
  66568. * @package Structures_Graph
  66569. */
  66570. /* }}} */
  66571. class Structures_Graph_Node {
  66572. /* fields {{{ */
  66573. /**
  66574. * @access private
  66575. */
  66576. var $_data = null;
  66577. /** @access private */
  66578. var $_metadata = array();
  66579. /** @access private */
  66580. var $_arcs = array();
  66581. /** @access private */
  66582. var $_graph = null;
  66583. /* }}} */
  66584. /* Constructor {{{ */
  66585. /**
  66586. *
  66587. * Constructor
  66588. *
  66589. * @access public
  66590. */
  66591. function __construct() {
  66592. }
  66593. /* }}} */
  66594. /* getGraph {{{ */
  66595. /**
  66596. *
  66597. * Node graph getter
  66598. *
  66599. * @return Structures_Graph Graph where node is stored
  66600. * @access public
  66601. */
  66602. function &getGraph() {
  66603. return $this->_graph;
  66604. }
  66605. /* }}} */
  66606. /* setGraph {{{ */
  66607. /**
  66608. *
  66609. * Node graph setter. This method should not be called directly. Use Graph::addNode instead.
  66610. *
  66611. * @param Structures_Graph Set the graph for this node.
  66612. * @see Structures_Graph::addNode()
  66613. * @access public
  66614. */
  66615. function setGraph(&$graph) {
  66616. $this->_graph =& $graph;
  66617. }
  66618. /* }}} */
  66619. /* getData {{{ */
  66620. /**
  66621. *
  66622. * Node data getter.
  66623. *
  66624. * Each graph node can contain a reference to one variable. This is the getter for that reference.
  66625. *
  66626. * @return mixed Data stored in node
  66627. * @access public
  66628. */
  66629. function &getData() {
  66630. return $this->_data;
  66631. }
  66632. /* }}} */
  66633. /* setData {{{ */
  66634. /**
  66635. *
  66636. * Node data setter
  66637. *
  66638. * Each graph node can contain a reference to one variable. This is the setter for that reference.
  66639. *
  66640. * @return mixed Data to store in node
  66641. * @access public
  66642. */
  66643. function setData(&$data) {
  66644. $this->_data =& $data;
  66645. }
  66646. /* }}} */
  66647. /* metadataKeyExists {{{ */
  66648. /**
  66649. *
  66650. * Test for existence of metadata under a given key.
  66651. *
  66652. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  66653. * associative array or in a dictionary. This method tests whether a given metadata key exists for this node.
  66654. *
  66655. * @param string Key to test
  66656. * @return boolean
  66657. * @access public
  66658. */
  66659. function metadataKeyExists($key) {
  66660. return array_key_exists($key, $this->_metadata);
  66661. }
  66662. /* }}} */
  66663. /* getMetadata {{{ */
  66664. /**
  66665. *
  66666. * Node metadata getter
  66667. *
  66668. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  66669. * associative array or in a dictionary. This method gets the data under the given key. If the key does
  66670. * not exist, an error will be thrown, so testing using metadataKeyExists might be needed.
  66671. *
  66672. * @param string Key
  66673. * @param boolean nullIfNonexistent (defaults to false).
  66674. * @return mixed Metadata Data stored in node under given key
  66675. * @see metadataKeyExists
  66676. * @access public
  66677. */
  66678. function &getMetadata($key, $nullIfNonexistent = false) {
  66679. if (array_key_exists($key, $this->_metadata)) {
  66680. return $this->_metadata[$key];
  66681. } else {
  66682. if ($nullIfNonexistent) {
  66683. $a = null;
  66684. return $a;
  66685. } else {
  66686. $a = Pear::raiseError('Structures_Graph_Node::getMetadata: Requested key does not exist', STRUCTURES_GRAPH_ERROR_GENERIC);
  66687. return $a;
  66688. }
  66689. }
  66690. }
  66691. /* }}} */
  66692. /* unsetMetadata {{{ */
  66693. /**
  66694. *
  66695. * Delete metadata by key
  66696. *
  66697. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  66698. * associative array or in a dictionary. This method removes any data that might be stored under the provided key.
  66699. * If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence.
  66700. *
  66701. * @param string Key
  66702. * @access public
  66703. */
  66704. function unsetMetadata($key) {
  66705. if (array_key_exists($key, $this->_metadata)) unset($this->_metadata[$key]);
  66706. }
  66707. /* }}} */
  66708. /* setMetadata {{{ */
  66709. /**
  66710. *
  66711. * Node metadata setter
  66712. *
  66713. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  66714. * associative array or in a dictionary. This method stores data under the given key. If the key already exists,
  66715. * previously stored data is discarded.
  66716. *
  66717. * @param string Key
  66718. * @param mixed Data
  66719. * @access public
  66720. */
  66721. function setMetadata($key, &$data) {
  66722. $this->_metadata[$key] =& $data;
  66723. }
  66724. /* }}} */
  66725. /* _connectTo {{{ */
  66726. /** @access private */
  66727. function _connectTo(&$destinationNode) {
  66728. $this->_arcs[] =& $destinationNode;
  66729. }
  66730. /* }}} */
  66731. /* connectTo {{{ */
  66732. /**
  66733. *
  66734. * Connect this node to another one.
  66735. *
  66736. * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.
  66737. *
  66738. * @param Structures_Graph_Node Node to connect to
  66739. * @access public
  66740. */
  66741. function connectTo(&$destinationNode) {
  66742. // We only connect to nodes
  66743. if (!is_a($destinationNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph_Node::connectTo received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC);
  66744. // Nodes must already be in graphs to be connected
  66745. if ($this->_graph == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  66746. if ($destinationNode->getGraph() == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect to a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  66747. // Connect here
  66748. $this->_connectTo($destinationNode);
  66749. // If graph is undirected, connect back
  66750. if (!$this->_graph->isDirected()) {
  66751. $destinationNode->_connectTo($this);
  66752. }
  66753. }
  66754. /* }}} */
  66755. /* getNeighbours {{{ */
  66756. /**
  66757. *
  66758. * Return nodes connected to this one.
  66759. *
  66760. * @return array Array of nodes
  66761. * @access public
  66762. */
  66763. function getNeighbours() {
  66764. return $this->_arcs;
  66765. }
  66766. /* }}} */
  66767. /* connectsTo {{{ */
  66768. /**
  66769. *
  66770. * Test wether this node has an arc to the target node
  66771. *
  66772. * @return boolean True if the two nodes are connected
  66773. * @access public
  66774. */
  66775. function connectsTo(&$target) {
  66776. if (version_compare(PHP_VERSION, '5.0.0') >= 0) {
  66777. return in_array($target, $this->getNeighbours(), true);
  66778. }
  66779. $copy = $target;
  66780. $arcKeys = array_keys($this->_arcs);
  66781. foreach($arcKeys as $key) {
  66782. /* ZE1 chokes on this expression:
  66783. if ($target === $arc) return true;
  66784. so, we'll use more convoluted stuff
  66785. */
  66786. $arc =& $this->_arcs[$key];
  66787. $target = true;
  66788. if ($arc === true) {
  66789. $target = false;
  66790. if ($arc === false) {
  66791. $target = $copy;
  66792. return true;
  66793. }
  66794. }
  66795. }
  66796. $target = $copy;
  66797. return false;
  66798. }
  66799. /* }}} */
  66800. /* inDegree {{{ */
  66801. /**
  66802. *
  66803. * Calculate the in degree of the node.
  66804. *
  66805. * The indegree for a node is the number of arcs entering the node. For non directed graphs,
  66806. * the indegree is equal to the outdegree.
  66807. *
  66808. * @return integer In degree of the node
  66809. * @access public
  66810. */
  66811. function inDegree() {
  66812. if ($this->_graph == null) return 0;
  66813. if (!$this->_graph->isDirected()) return $this->outDegree();
  66814. $result = 0;
  66815. $graphNodes =& $this->_graph->getNodes();
  66816. foreach (array_keys($graphNodes) as $key) {
  66817. if ($graphNodes[$key]->connectsTo($this)) $result++;
  66818. }
  66819. return $result;
  66820. }
  66821. /* }}} */
  66822. /* outDegree {{{ */
  66823. /**
  66824. *
  66825. * Calculate the out degree of the node.
  66826. *
  66827. * The outdegree for a node is the number of arcs exiting the node. For non directed graphs,
  66828. * the outdegree is always equal to the indegree.
  66829. *
  66830. * @return integer Out degree of the node
  66831. * @access public
  66832. */
  66833. function outDegree() {
  66834. if ($this->_graph == null) return 0;
  66835. return sizeof($this->_arcs);
  66836. }
  66837. /* }}} */
  66838. }
  66839. ?>
  66840. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/Structures/Graph.php���������������������������������������������������������0000644�0001750�0000144�00000014037�12553252061�020332 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  66841. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  66842. // +-----------------------------------------------------------------------------+
  66843. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  66844. // +-----------------------------------------------------------------------------+
  66845. // | This file is part of Structures_Graph. |
  66846. // | |
  66847. // | Structures_Graph is free software; you can redistribute it and/or modify |
  66848. // | it under the terms of the GNU Lesser General Public License as published by |
  66849. // | the Free Software Foundation; either version 2.1 of the License, or |
  66850. // | (at your option) any later version. |
  66851. // | |
  66852. // | Structures_Graph is distributed in the hope that it will be useful, |
  66853. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  66854. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  66855. // | GNU Lesser General Public License for more details. |
  66856. // | |
  66857. // | You should have received a copy of the GNU Lesser General Public License |
  66858. // | along with Structures_Graph; if not, write to the Free Software |
  66859. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  66860. // | 02111-1307 USA |
  66861. // +-----------------------------------------------------------------------------+
  66862. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  66863. // +-----------------------------------------------------------------------------+
  66864. //
  66865. /**
  66866. * The Graph.php file contains the definition of the Structures_Graph class
  66867. *
  66868. * @package Structures_Graph
  66869. */
  66870. /* dependencies {{{ */
  66871. require_once 'PEAR.php';
  66872. require_once 'Structures/Graph/Node.php';
  66873. /* }}} */
  66874. define('STRUCTURES_GRAPH_ERROR_GENERIC', 100);
  66875. /* class Structures_Graph {{{ */
  66876. /**
  66877. * The Structures_Graph class represents a graph data structure.
  66878. *
  66879. * A Graph is a data structure composed by a set of nodes, connected by arcs.
  66880. * Graphs may either be directed or undirected. In a directed graph, arcs are
  66881. * directional, and can be traveled only one way. In an undirected graph, arcs
  66882. * are bidirectional, and can be traveled both ways.
  66883. *
  66884. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  66885. * @copyright (c) 2004 by Sérgio Carvalho
  66886. * @package Structures_Graph
  66887. */
  66888. /* }}} */
  66889. class Structures_Graph
  66890. {
  66891. /**
  66892. * List of node objects in this graph
  66893. * @access private
  66894. */
  66895. var $_nodes = array();
  66896. /**
  66897. * If the graph is directed or not
  66898. * @access private
  66899. */
  66900. var $_directed = false;
  66901. /**
  66902. * Constructor
  66903. *
  66904. * @param boolean $directed Set to true if the graph is directed.
  66905. * Set to false if it is not directed.
  66906. */
  66907. public function __construct($directed = true)
  66908. {
  66909. $this->_directed = $directed;
  66910. }
  66911. /**
  66912. * Old constructor (PHP4-style; kept for BC with extending classes)
  66913. *
  66914. * @param boolean $directed Set to true if the graph is directed.
  66915. * Set to false if it is not directed.
  66916. *
  66917. * @return void
  66918. */
  66919. public function Structures_Graph($directed = true)
  66920. {
  66921. $this->__construct($directed);
  66922. }
  66923. /**
  66924. * Return true if a graph is directed
  66925. *
  66926. * @return boolean true if the graph is directed
  66927. */
  66928. public function isDirected()
  66929. {
  66930. return (boolean) $this->_directed;
  66931. }
  66932. /**
  66933. * Add a Node to the Graph
  66934. *
  66935. * @param Structures_Graph_Node $newNode The node to be added.
  66936. *
  66937. * @return void
  66938. */
  66939. public function addNode(&$newNode)
  66940. {
  66941. // We only add nodes
  66942. if (!is_a($newNode, 'Structures_Graph_Node')) {
  66943. return Pear::raiseError(
  66944. 'Structures_Graph::addNode received an object that is not'
  66945. . ' a Structures_Graph_Node',
  66946. STRUCTURES_GRAPH_ERROR_GENERIC
  66947. );
  66948. }
  66949. //Graphs are node *sets*, so duplicates are forbidden.
  66950. // We allow nodes that are exactly equal, but disallow equal references.
  66951. foreach ($this->_nodes as $key => $node) {
  66952. /*
  66953. ZE1 equality operators choke on the recursive cycle introduced
  66954. by the _graph field in the Node object.
  66955. So, we'll check references the hard way
  66956. (change $this->_nodes[$key] and check if the change reflects in
  66957. $node)
  66958. */
  66959. $savedData = $this->_nodes[$key];
  66960. $referenceIsEqualFlag = false;
  66961. $this->_nodes[$key] = true;
  66962. if ($node === true) {
  66963. $this->_nodes[$key] = false;
  66964. if ($node === false) {
  66965. $referenceIsEqualFlag = true;
  66966. }
  66967. }
  66968. $this->_nodes[$key] = $savedData;
  66969. if ($referenceIsEqualFlag) {
  66970. return Pear::raiseError(
  66971. 'Structures_Graph::addNode received an object that is'
  66972. . ' a duplicate for this dataset',
  66973. STRUCTURES_GRAPH_ERROR_GENERIC
  66974. );
  66975. }
  66976. }
  66977. $this->_nodes[] =& $newNode;
  66978. $newNode->setGraph($this);
  66979. }
  66980. /**
  66981. * Remove a Node from the Graph
  66982. *
  66983. * @param Structures_Graph_Node $node The node to be removed from the graph
  66984. *
  66985. * @return void
  66986. * @todo This is unimplemented
  66987. */
  66988. public function removeNode(&$node)
  66989. {
  66990. }
  66991. /**
  66992. * Return the node set, in no particular order.
  66993. * For ordered node sets, use a Graph Manipulator insted.
  66994. *
  66995. * @return array The set of nodes in this graph
  66996. * @see Structures_Graph_Manipulator_TopologicalSorter
  66997. */
  66998. public function &getNodes()
  66999. {
  67000. return $this->_nodes;
  67001. }
  67002. }
  67003. ?>
  67004. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/tests/AllTests.php�����������������������������������������������������������0000644�0001750�0000144�00000000674�12553252061�020005 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  67005. require_once dirname(__FILE__) . '/helper.inc';
  67006. class Structures_Graph_AllTests
  67007. {
  67008. public static function main()
  67009. {
  67010. PHPUnit_TextUI_TestRunner::run(self::suite());
  67011. }
  67012. public static function suite()
  67013. {
  67014. $suite = new PHPUnit_Framework_TestSuite('Structures_Graph Tests');
  67015. $dir = new GlobIterator(dirname(__FILE__) . '/*Test.php');
  67016. $suite->addTestFiles($dir);
  67017. return $suite;
  67018. }
  67019. }
  67020. ��������������������������������������������������������������������Structures_Graph-1.1.1/tests/BasicGraphTest.php�����������������������������������������������������0000644�0001750�0000144�00000021552�12553252061�021113 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  67021. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  67022. // +-----------------------------------------------------------------------------+
  67023. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  67024. // +-----------------------------------------------------------------------------+
  67025. // | This file is part of Structures_Graph. |
  67026. // | |
  67027. // | Structures_Graph is free software; you can redistribute it and/or modify |
  67028. // | it under the terms of the GNU Lesser General Public License as published by |
  67029. // | the Free Software Foundation; either version 2.1 of the License, or |
  67030. // | (at your option) any later version. |
  67031. // | |
  67032. // | Structures_Graph is distributed in the hope that it will be useful, |
  67033. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  67034. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  67035. // | GNU Lesser General Public License for more details. |
  67036. // | |
  67037. // | You should have received a copy of the GNU Lesser General Public License |
  67038. // | along with Structures_Graph; if not, write to the Free Software |
  67039. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  67040. // | 02111-1307 USA |
  67041. // +-----------------------------------------------------------------------------+
  67042. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  67043. // +-----------------------------------------------------------------------------+
  67044. //
  67045. require_once dirname(__FILE__) . '/helper.inc';
  67046. /**
  67047. * @access private
  67048. */
  67049. class BasicGraph extends PHPUnit_Framework_TestCase
  67050. {
  67051. var $_graph = null;
  67052. function test_create_graph() {
  67053. $this->_graph = new Structures_Graph();
  67054. $this->assertTrue(is_a($this->_graph, 'Structures_Graph'));
  67055. }
  67056. function test_add_node() {
  67057. $this->_graph = new Structures_Graph();
  67058. $data = 1;
  67059. $node = new Structures_Graph_Node($data);
  67060. $this->_graph->addNode($node);
  67061. $node = new Structures_Graph_Node($data);
  67062. $this->_graph->addNode($node);
  67063. $node = new Structures_Graph_Node($data);
  67064. $this->_graph->addNode($node);
  67065. }
  67066. function test_connect_node() {
  67067. $this->_graph = new Structures_Graph();
  67068. $data = 1;
  67069. $node1 = new Structures_Graph_Node($data);
  67070. $node2 = new Structures_Graph_Node($data);
  67071. $this->_graph->addNode($node1);
  67072. $this->_graph->addNode($node2);
  67073. $node1->connectTo($node2);
  67074. $node =& $this->_graph->getNodes();
  67075. $node =& $node[0];
  67076. $node = $node->getNeighbours();
  67077. $node =& $node[0];
  67078. /*
  67079. ZE1 == and === operators fail on $node,$node2 because of the recursion introduced
  67080. by the _graph field in the Node object. So, we'll use the stupid method for reference
  67081. testing
  67082. */
  67083. $node = true;
  67084. $this->assertTrue($node2);
  67085. $node = false;
  67086. $this->assertFalse($node2);
  67087. }
  67088. function test_data_references() {
  67089. $this->_graph = new Structures_Graph();
  67090. $data = 1;
  67091. $node = new Structures_Graph_Node();
  67092. $node->setData($data);
  67093. $this->_graph->addNode($node);
  67094. $data = 2;
  67095. $dataInNode =& $this->_graph->getNodes();
  67096. $dataInNode =& $dataInNode[0];
  67097. $dataInNode =& $dataInNode->getData();
  67098. $this->assertEquals($data, $dataInNode);
  67099. }
  67100. function test_metadata_references() {
  67101. $this->_graph = new Structures_Graph();
  67102. $data = 1;
  67103. $node = new Structures_Graph_Node();
  67104. $node->setMetadata('5', $data);
  67105. $data = 2;
  67106. $dataInNode =& $node->getMetadata('5');
  67107. $this->assertEquals($data, $dataInNode);
  67108. }
  67109. function test_metadata_key_exists() {
  67110. $this->_graph = new Structures_Graph();
  67111. $data = 1;
  67112. $node = new Structures_Graph_Node();
  67113. $node->setMetadata('5', $data);
  67114. $this->assertTrue($node->metadataKeyExists('5'));
  67115. $this->assertFalse($node->metadataKeyExists('1'));
  67116. }
  67117. function test_directed_degree() {
  67118. $this->_graph = new Structures_Graph(true);
  67119. $node = array();
  67120. $node[] = new Structures_Graph_Node();
  67121. $node[] = new Structures_Graph_Node();
  67122. $node[] = new Structures_Graph_Node();
  67123. $this->_graph->addNode($node[0]);
  67124. $this->_graph->addNode($node[1]);
  67125. $this->_graph->addNode($node[2]);
  67126. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 0 arcs');
  67127. $this->assertEquals(0, $node[1]->inDegree(), 'inDegree test failed for node 1 with 0 arcs');
  67128. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 0 arcs');
  67129. $this->assertEquals(0, $node[0]->outDegree(), 'outDegree test failed for node 0 with 0 arcs');
  67130. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 0 arcs');
  67131. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 0 arcs');
  67132. $node[0]->connectTo($node[1]);
  67133. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 1 arc');
  67134. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 1 arc');
  67135. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 1 arc');
  67136. $this->assertEquals(1, $node[0]->outDegree(), 'outDegree test failed for node 0 with 1 arc');
  67137. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 1 arc');
  67138. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 1 arc');
  67139. $node[0]->connectTo($node[2]);
  67140. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 2 arcs');
  67141. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 2 arcs');
  67142. $this->assertEquals(1, $node[2]->inDegree(), 'inDegree test failed for node 2 with 2 arcs');
  67143. $this->assertEquals(2, $node[0]->outDegree(), 'outDegree test failed for node 0 with 2 arcs');
  67144. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 2 arcs');
  67145. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 2 arcs');
  67146. }
  67147. function test_undirected_degree() {
  67148. $this->_graph = new Structures_Graph(false);
  67149. $node = array();
  67150. $node[] = new Structures_Graph_Node();
  67151. $node[] = new Structures_Graph_Node();
  67152. $node[] = new Structures_Graph_Node();
  67153. $this->_graph->addNode($node[0]);
  67154. $this->_graph->addNode($node[1]);
  67155. $this->_graph->addNode($node[2]);
  67156. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 0 arcs');
  67157. $this->assertEquals(0, $node[1]->inDegree(), 'inDegree test failed for node 1 with 0 arcs');
  67158. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 0 arcs');
  67159. $this->assertEquals(0, $node[0]->outDegree(), 'outDegree test failed for node 0 with 0 arcs');
  67160. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 0 arcs');
  67161. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 0 arcs');
  67162. $node[0]->connectTo($node[1]);
  67163. $this->assertEquals(1, $node[0]->inDegree(), 'inDegree test failed for node 0 with 1 arc');
  67164. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 1 arc');
  67165. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 1 arc');
  67166. $this->assertEquals(1, $node[0]->outDegree(), 'outDegree test failed for node 0 with 1 arc');
  67167. $this->assertEquals(1, $node[1]->outDegree(), 'outDegree test failed for node 1 with 1 arc');
  67168. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 1 arc');
  67169. $node[0]->connectTo($node[2]);
  67170. $this->assertEquals(2, $node[0]->inDegree(), 'inDegree test failed for node 0 with 2 arcs');
  67171. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 2 arcs');
  67172. $this->assertEquals(1, $node[2]->inDegree(), 'inDegree test failed for node 2 with 2 arcs');
  67173. $this->assertEquals(2, $node[0]->outDegree(), 'outDegree test failed for node 0 with 2 arcs');
  67174. $this->assertEquals(1, $node[1]->outDegree(), 'outDegree test failed for node 1 with 2 arcs');
  67175. $this->assertEquals(1, $node[2]->outDegree(), 'outDegree test failed for node 2 with 2 arcs');
  67176. }
  67177. }
  67178. ?>
  67179. ������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/tests/TopologicalSorterTest.php����������������������������������������������0000644�0001750�0000144�00000003525�12553252061�022563 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  67180. require_once dirname(__FILE__) . '/helper.inc';
  67181. require_once 'Structures/Graph/Manipulator/TopologicalSorter.php';
  67182. class TopologicalSorterTest extends PHPUnit_Framework_TestCase
  67183. {
  67184. public function testSort()
  67185. {
  67186. $graph = new Structures_Graph();
  67187. $name1 = 'node1';
  67188. $node1 = new Structures_Graph_Node();
  67189. $node1->setData($name1);
  67190. $graph->addNode($node1);
  67191. $name11 = 'node11';
  67192. $node11 = new Structures_Graph_Node();
  67193. $node11->setData($name11);
  67194. $graph->addNode($node11);
  67195. $node1->connectTo($node11);
  67196. $name12 = 'node12';
  67197. $node12 = new Structures_Graph_Node();
  67198. $node12->setData($name12);
  67199. $graph->addNode($node12);
  67200. $node1->connectTo($node12);
  67201. $name121 = 'node121';
  67202. $node121 = new Structures_Graph_Node();
  67203. $node121->setData($name121);
  67204. $graph->addNode($node121);
  67205. $node12->connectTo($node121);
  67206. $name2 = 'node2';
  67207. $node2 = new Structures_Graph_Node();
  67208. $node2->setData($name2);
  67209. $graph->addNode($node2);
  67210. $name21 = 'node21';
  67211. $node21 = new Structures_Graph_Node();
  67212. $node21->setData($name21);
  67213. $graph->addNode($node21);
  67214. $node2->connectTo($node21);
  67215. $nodes = Structures_Graph_Manipulator_TopologicalSorter::sort($graph);
  67216. $this->assertCount(2, $nodes[0]);
  67217. $this->assertEquals('node1', $nodes[0][0]->getData());
  67218. $this->assertEquals('node2', $nodes[0][1]->getData());
  67219. $this->assertCount(3, $nodes[1]);
  67220. $this->assertEquals('node11', $nodes[1][0]->getData());
  67221. $this->assertEquals('node12', $nodes[1][1]->getData());
  67222. $this->assertEquals('node21', $nodes[1][2]->getData());
  67223. $this->assertCount(1, $nodes[2]);
  67224. $this->assertEquals('node121', $nodes[2][0]->getData());
  67225. }
  67226. }
  67227. ?>
  67228. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/tests/AcyclicTestTest.php����������������������������������������������������0000644�0001750�0000144�00000002434�12553252061�021315 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  67229. require_once dirname(__FILE__) . '/helper.inc';
  67230. require_once 'Structures/Graph/Manipulator/AcyclicTest.php';
  67231. class AcyclicTestTest extends PHPUnit_Framework_TestCase
  67232. {
  67233. public function testIsAcyclicFalse()
  67234. {
  67235. $graph = new Structures_Graph();
  67236. $node1 = new Structures_Graph_Node();
  67237. $graph->addNode($node1);
  67238. $node2 = new Structures_Graph_Node();
  67239. $graph->addNode($node2);
  67240. $node1->connectTo($node2);
  67241. $node3 = new Structures_Graph_Node();
  67242. $graph->addNode($node3);
  67243. $node2->connectTo($node3);
  67244. $node3->connectTo($node1);
  67245. $this->assertFalse(
  67246. Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph),
  67247. 'Graph is cyclic'
  67248. );
  67249. }
  67250. public function testIsAcyclicTrue()
  67251. {
  67252. $graph = new Structures_Graph();
  67253. $node1 = new Structures_Graph_Node();
  67254. $graph->addNode($node1);
  67255. $node2 = new Structures_Graph_Node();
  67256. $graph->addNode($node2);
  67257. $node1->connectTo($node2);
  67258. $node3 = new Structures_Graph_Node();
  67259. $graph->addNode($node3);
  67260. $node2->connectTo($node3);
  67261. $this->assertTrue(
  67262. Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph),
  67263. 'Graph is acyclic'
  67264. );
  67265. }
  67266. }
  67267. ?>
  67268. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/tests/BasicGraphTest.php�����������������������������������������������������0000644�0001750�0000144�00000021552�12553252061�021113 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  67269. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  67270. // +-----------------------------------------------------------------------------+
  67271. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  67272. // +-----------------------------------------------------------------------------+
  67273. // | This file is part of Structures_Graph. |
  67274. // | |
  67275. // | Structures_Graph is free software; you can redistribute it and/or modify |
  67276. // | it under the terms of the GNU Lesser General Public License as published by |
  67277. // | the Free Software Foundation; either version 2.1 of the License, or |
  67278. // | (at your option) any later version. |
  67279. // | |
  67280. // | Structures_Graph is distributed in the hope that it will be useful, |
  67281. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  67282. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  67283. // | GNU Lesser General Public License for more details. |
  67284. // | |
  67285. // | You should have received a copy of the GNU Lesser General Public License |
  67286. // | along with Structures_Graph; if not, write to the Free Software |
  67287. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  67288. // | 02111-1307 USA |
  67289. // +-----------------------------------------------------------------------------+
  67290. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  67291. // +-----------------------------------------------------------------------------+
  67292. //
  67293. require_once dirname(__FILE__) . '/helper.inc';
  67294. /**
  67295. * @access private
  67296. */
  67297. class BasicGraph extends PHPUnit_Framework_TestCase
  67298. {
  67299. var $_graph = null;
  67300. function test_create_graph() {
  67301. $this->_graph = new Structures_Graph();
  67302. $this->assertTrue(is_a($this->_graph, 'Structures_Graph'));
  67303. }
  67304. function test_add_node() {
  67305. $this->_graph = new Structures_Graph();
  67306. $data = 1;
  67307. $node = new Structures_Graph_Node($data);
  67308. $this->_graph->addNode($node);
  67309. $node = new Structures_Graph_Node($data);
  67310. $this->_graph->addNode($node);
  67311. $node = new Structures_Graph_Node($data);
  67312. $this->_graph->addNode($node);
  67313. }
  67314. function test_connect_node() {
  67315. $this->_graph = new Structures_Graph();
  67316. $data = 1;
  67317. $node1 = new Structures_Graph_Node($data);
  67318. $node2 = new Structures_Graph_Node($data);
  67319. $this->_graph->addNode($node1);
  67320. $this->_graph->addNode($node2);
  67321. $node1->connectTo($node2);
  67322. $node =& $this->_graph->getNodes();
  67323. $node =& $node[0];
  67324. $node = $node->getNeighbours();
  67325. $node =& $node[0];
  67326. /*
  67327. ZE1 == and === operators fail on $node,$node2 because of the recursion introduced
  67328. by the _graph field in the Node object. So, we'll use the stupid method for reference
  67329. testing
  67330. */
  67331. $node = true;
  67332. $this->assertTrue($node2);
  67333. $node = false;
  67334. $this->assertFalse($node2);
  67335. }
  67336. function test_data_references() {
  67337. $this->_graph = new Structures_Graph();
  67338. $data = 1;
  67339. $node = new Structures_Graph_Node();
  67340. $node->setData($data);
  67341. $this->_graph->addNode($node);
  67342. $data = 2;
  67343. $dataInNode =& $this->_graph->getNodes();
  67344. $dataInNode =& $dataInNode[0];
  67345. $dataInNode =& $dataInNode->getData();
  67346. $this->assertEquals($data, $dataInNode);
  67347. }
  67348. function test_metadata_references() {
  67349. $this->_graph = new Structures_Graph();
  67350. $data = 1;
  67351. $node = new Structures_Graph_Node();
  67352. $node->setMetadata('5', $data);
  67353. $data = 2;
  67354. $dataInNode =& $node->getMetadata('5');
  67355. $this->assertEquals($data, $dataInNode);
  67356. }
  67357. function test_metadata_key_exists() {
  67358. $this->_graph = new Structures_Graph();
  67359. $data = 1;
  67360. $node = new Structures_Graph_Node();
  67361. $node->setMetadata('5', $data);
  67362. $this->assertTrue($node->metadataKeyExists('5'));
  67363. $this->assertFalse($node->metadataKeyExists('1'));
  67364. }
  67365. function test_directed_degree() {
  67366. $this->_graph = new Structures_Graph(true);
  67367. $node = array();
  67368. $node[] = new Structures_Graph_Node();
  67369. $node[] = new Structures_Graph_Node();
  67370. $node[] = new Structures_Graph_Node();
  67371. $this->_graph->addNode($node[0]);
  67372. $this->_graph->addNode($node[1]);
  67373. $this->_graph->addNode($node[2]);
  67374. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 0 arcs');
  67375. $this->assertEquals(0, $node[1]->inDegree(), 'inDegree test failed for node 1 with 0 arcs');
  67376. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 0 arcs');
  67377. $this->assertEquals(0, $node[0]->outDegree(), 'outDegree test failed for node 0 with 0 arcs');
  67378. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 0 arcs');
  67379. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 0 arcs');
  67380. $node[0]->connectTo($node[1]);
  67381. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 1 arc');
  67382. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 1 arc');
  67383. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 1 arc');
  67384. $this->assertEquals(1, $node[0]->outDegree(), 'outDegree test failed for node 0 with 1 arc');
  67385. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 1 arc');
  67386. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 1 arc');
  67387. $node[0]->connectTo($node[2]);
  67388. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 2 arcs');
  67389. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 2 arcs');
  67390. $this->assertEquals(1, $node[2]->inDegree(), 'inDegree test failed for node 2 with 2 arcs');
  67391. $this->assertEquals(2, $node[0]->outDegree(), 'outDegree test failed for node 0 with 2 arcs');
  67392. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 2 arcs');
  67393. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 2 arcs');
  67394. }
  67395. function test_undirected_degree() {
  67396. $this->_graph = new Structures_Graph(false);
  67397. $node = array();
  67398. $node[] = new Structures_Graph_Node();
  67399. $node[] = new Structures_Graph_Node();
  67400. $node[] = new Structures_Graph_Node();
  67401. $this->_graph->addNode($node[0]);
  67402. $this->_graph->addNode($node[1]);
  67403. $this->_graph->addNode($node[2]);
  67404. $this->assertEquals(0, $node[0]->inDegree(), 'inDegree test failed for node 0 with 0 arcs');
  67405. $this->assertEquals(0, $node[1]->inDegree(), 'inDegree test failed for node 1 with 0 arcs');
  67406. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 0 arcs');
  67407. $this->assertEquals(0, $node[0]->outDegree(), 'outDegree test failed for node 0 with 0 arcs');
  67408. $this->assertEquals(0, $node[1]->outDegree(), 'outDegree test failed for node 1 with 0 arcs');
  67409. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 0 arcs');
  67410. $node[0]->connectTo($node[1]);
  67411. $this->assertEquals(1, $node[0]->inDegree(), 'inDegree test failed for node 0 with 1 arc');
  67412. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 1 arc');
  67413. $this->assertEquals(0, $node[2]->inDegree(), 'inDegree test failed for node 2 with 1 arc');
  67414. $this->assertEquals(1, $node[0]->outDegree(), 'outDegree test failed for node 0 with 1 arc');
  67415. $this->assertEquals(1, $node[1]->outDegree(), 'outDegree test failed for node 1 with 1 arc');
  67416. $this->assertEquals(0, $node[2]->outDegree(), 'outDegree test failed for node 2 with 1 arc');
  67417. $node[0]->connectTo($node[2]);
  67418. $this->assertEquals(2, $node[0]->inDegree(), 'inDegree test failed for node 0 with 2 arcs');
  67419. $this->assertEquals(1, $node[1]->inDegree(), 'inDegree test failed for node 1 with 2 arcs');
  67420. $this->assertEquals(1, $node[2]->inDegree(), 'inDegree test failed for node 2 with 2 arcs');
  67421. $this->assertEquals(2, $node[0]->outDegree(), 'outDegree test failed for node 0 with 2 arcs');
  67422. $this->assertEquals(1, $node[1]->outDegree(), 'outDegree test failed for node 1 with 2 arcs');
  67423. $this->assertEquals(1, $node[2]->outDegree(), 'outDegree test failed for node 2 with 2 arcs');
  67424. }
  67425. }
  67426. ?>
  67427. ������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/tests/helper.inc�������������������������������������������������������������0000644�0001750�0000144�00000000525�12553252061�017506 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  67428. if ('@php_dir@' == '@'.'php_dir'.'@') {
  67429. // This package hasn't been installed.
  67430. // Adjust path to ensure includes find files in working directory.
  67431. set_include_path(dirname(dirname(__FILE__))
  67432. . PATH_SEPARATOR . dirname(__FILE__)
  67433. . PATH_SEPARATOR . get_include_path());
  67434. }
  67435. require_once 'Structures/Graph.php';
  67436. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������Structures_Graph-1.1.1/LICENSE����������������������������������������������������������������������0000644�0001750�0000144�00000016725�12553252061�015410 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ GNU LESSER GENERAL PUBLIC LICENSE
  67437. Version 3, 29 June 2007
  67438. Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
  67439. Everyone is permitted to copy and distribute verbatim copies
  67440. of this license document, but changing it is not allowed.
  67441. This version of the GNU Lesser General Public License incorporates
  67442. the terms and conditions of version 3 of the GNU General Public
  67443. License, supplemented by the additional permissions listed below.
  67444. 0. Additional Definitions.
  67445. As used herein, "this License" refers to version 3 of the GNU Lesser
  67446. General Public License, and the "GNU GPL" refers to version 3 of the GNU
  67447. General Public License.
  67448. "The Library" refers to a covered work governed by this License,
  67449. other than an Application or a Combined Work as defined below.
  67450. An "Application" is any work that makes use of an interface provided
  67451. by the Library, but which is not otherwise based on the Library.
  67452. Defining a subclass of a class defined by the Library is deemed a mode
  67453. of using an interface provided by the Library.
  67454. A "Combined Work" is a work produced by combining or linking an
  67455. Application with the Library. The particular version of the Library
  67456. with which the Combined Work was made is also called the "Linked
  67457. Version".
  67458. The "Minimal Corresponding Source" for a Combined Work means the
  67459. Corresponding Source for the Combined Work, excluding any source code
  67460. for portions of the Combined Work that, considered in isolation, are
  67461. based on the Application, and not on the Linked Version.
  67462. The "Corresponding Application Code" for a Combined Work means the
  67463. object code and/or source code for the Application, including any data
  67464. and utility programs needed for reproducing the Combined Work from the
  67465. Application, but excluding the System Libraries of the Combined Work.
  67466. 1. Exception to Section 3 of the GNU GPL.
  67467. You may convey a covered work under sections 3 and 4 of this License
  67468. without being bound by section 3 of the GNU GPL.
  67469. 2. Conveying Modified Versions.
  67470. If you modify a copy of the Library, and, in your modifications, a
  67471. facility refers to a function or data to be supplied by an Application
  67472. that uses the facility (other than as an argument passed when the
  67473. facility is invoked), then you may convey a copy of the modified
  67474. version:
  67475. a) under this License, provided that you make a good faith effort to
  67476. ensure that, in the event an Application does not supply the
  67477. function or data, the facility still operates, and performs
  67478. whatever part of its purpose remains meaningful, or
  67479. b) under the GNU GPL, with none of the additional permissions of
  67480. this License applicable to that copy.
  67481. 3. Object Code Incorporating Material from Library Header Files.
  67482. The object code form of an Application may incorporate material from
  67483. a header file that is part of the Library. You may convey such object
  67484. code under terms of your choice, provided that, if the incorporated
  67485. material is not limited to numerical parameters, data structure
  67486. layouts and accessors, or small macros, inline functions and templates
  67487. (ten or fewer lines in length), you do both of the following:
  67488. a) Give prominent notice with each copy of the object code that the
  67489. Library is used in it and that the Library and its use are
  67490. covered by this License.
  67491. b) Accompany the object code with a copy of the GNU GPL and this license
  67492. document.
  67493. 4. Combined Works.
  67494. You may convey a Combined Work under terms of your choice that,
  67495. taken together, effectively do not restrict modification of the
  67496. portions of the Library contained in the Combined Work and reverse
  67497. engineering for debugging such modifications, if you also do each of
  67498. the following:
  67499. a) Give prominent notice with each copy of the Combined Work that
  67500. the Library is used in it and that the Library and its use are
  67501. covered by this License.
  67502. b) Accompany the Combined Work with a copy of the GNU GPL and this license
  67503. document.
  67504. c) For a Combined Work that displays copyright notices during
  67505. execution, include the copyright notice for the Library among
  67506. these notices, as well as a reference directing the user to the
  67507. copies of the GNU GPL and this license document.
  67508. d) Do one of the following:
  67509. 0) Convey the Minimal Corresponding Source under the terms of this
  67510. License, and the Corresponding Application Code in a form
  67511. suitable for, and under terms that permit, the user to
  67512. recombine or relink the Application with a modified version of
  67513. the Linked Version to produce a modified Combined Work, in the
  67514. manner specified by section 6 of the GNU GPL for conveying
  67515. Corresponding Source.
  67516. 1) Use a suitable shared library mechanism for linking with the
  67517. Library. A suitable mechanism is one that (a) uses at run time
  67518. a copy of the Library already present on the user's computer
  67519. system, and (b) will operate properly with a modified version
  67520. of the Library that is interface-compatible with the Linked
  67521. Version.
  67522. e) Provide Installation Information, but only if you would otherwise
  67523. be required to provide such information under section 6 of the
  67524. GNU GPL, and only to the extent that such information is
  67525. necessary to install and execute a modified version of the
  67526. Combined Work produced by recombining or relinking the
  67527. Application with a modified version of the Linked Version. (If
  67528. you use option 4d0, the Installation Information must accompany
  67529. the Minimal Corresponding Source and Corresponding Application
  67530. Code. If you use option 4d1, you must provide the Installation
  67531. Information in the manner specified by section 6 of the GNU GPL
  67532. for conveying Corresponding Source.)
  67533. 5. Combined Libraries.
  67534. You may place library facilities that are a work based on the
  67535. Library side by side in a single library together with other library
  67536. facilities that are not Applications and are not covered by this
  67537. License, and convey such a combined library under terms of your
  67538. choice, if you do both of the following:
  67539. a) Accompany the combined library with a copy of the same work based
  67540. on the Library, uncombined with any other library facilities,
  67541. conveyed under the terms of this License.
  67542. b) Give prominent notice with the combined library that part of it
  67543. is a work based on the Library, and explaining where to find the
  67544. accompanying uncombined form of the same work.
  67545. 6. Revised Versions of the GNU Lesser General Public License.
  67546. The Free Software Foundation may publish revised and/or new versions
  67547. of the GNU Lesser General Public License from time to time. Such new
  67548. versions will be similar in spirit to the present version, but may
  67549. differ in detail to address new problems or concerns.
  67550. Each version is given a distinguishing version number. If the
  67551. Library as you received it specifies that a certain numbered version
  67552. of the GNU Lesser General Public License "or any later version"
  67553. applies to it, you have the option of following the terms and
  67554. conditions either of that published version or of any later version
  67555. published by the Free Software Foundation. If the Library as you
  67556. received it does not specify a version number of the GNU Lesser
  67557. General Public License, you may choose any version of the GNU Lesser
  67558. General Public License ever published by the Free Software Foundation.
  67559. If the Library as you received it specifies that a proxy can decide
  67560. whether future versions of the GNU Lesser General Public License shall
  67561. apply, that proxy's public statement of acceptance of any version is
  67562. permanent authorization for you to choose that version for the
  67563. Library.
  67564. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������package.xml�����������������������������������������������������������������������������������������0000644�0001750�0000144�00000044265�13125000640�012546 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?>
  67565. <package packagerversion="1.10.4" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  67566. <name>XML_Util</name>
  67567. <channel>pear.php.net</channel>
  67568. <summary>XML utility class</summary>
  67569. <description>Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more.</description>
  67570. <lead>
  67571. <name>Chuck Burgess</name>
  67572. <user>ashnazg</user>
  67573. <email>ashnazg@php.net</email>
  67574. <active>yes</active>
  67575. </lead>
  67576. <lead>
  67577. <name>Stephan Schmidt</name>
  67578. <user>schst</user>
  67579. <email>schst@php-tools.net</email>
  67580. <active>no</active>
  67581. </lead>
  67582. <helper>
  67583. <name>Davey Shafik</name>
  67584. <user>davey</user>
  67585. <email>davey@php.net</email>
  67586. <active>no</active>
  67587. </helper>
  67588. <date>2017-06-28</date>
  67589. <time>19:21:04</time>
  67590. <version>
  67591. <release>1.4.3</release>
  67592. <api>1.4.0</api>
  67593. </version>
  67594. <stability>
  67595. <release>stable</release>
  67596. <api>stable</api>
  67597. </stability>
  67598. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  67599. <notes>
  67600. * Decrease minimum PEAR version to 1.9.0 to allow PEAR upgrades
  67601. </notes>
  67602. <contents>
  67603. <dir baseinstalldir="/" name="/">
  67604. <file baseinstalldir="/" md5sum="af2746028ae4395f549855a5e444ada7" name="examples/example.php" role="doc" />
  67605. <file baseinstalldir="/" md5sum="b9e52f4aa372c4067c609f49c2285b8f" name="examples/example2.php" role="doc" />
  67606. <file baseinstalldir="/" md5sum="d0af9354df0962e70e9e2215b5611b9c" name="tests/AbstractUnitTests.php" role="test" />
  67607. <file baseinstalldir="/" md5sum="57ce547d64d6e1f2986c313407deffef" name="tests/ApiVersionTests.php" role="test" />
  67608. <file baseinstalldir="/" md5sum="2d0427db94790df7ada24a744547edf5" name="tests/AttributesToStringTests.php" role="test" />
  67609. <file baseinstalldir="/" md5sum="673d1438c4718a70c5da3fe019027db4" name="tests/CollapseEmptyTagsTests.php" role="test" />
  67610. <file baseinstalldir="/" md5sum="46b981f91edd163f1cd021cfef5d1bb1" name="tests/CreateCDataSectionTests.php" role="test" />
  67611. <file baseinstalldir="/" md5sum="6aa925b879572e9b3f1885b7cdbb223b" name="tests/CreateCommentTests.php" role="test" />
  67612. <file baseinstalldir="/" md5sum="dbc083b62a020fa245fde5a7828a4806" name="tests/CreateEndElementTests.php" role="test" />
  67613. <file baseinstalldir="/" md5sum="f58e38343ecf60811c842d4cfc8194ae" name="tests/CreateStartElementTests.php" role="test" />
  67614. <file baseinstalldir="/" md5sum="9385fba272f4ebccf4c95d43d16dcff4" name="tests/CreateTagTests.php" role="test" />
  67615. <file baseinstalldir="/" md5sum="51e7ba1390e6dadc3c0be0c960bf171d" name="tests/CreateTagFromArrayTests.php" role="test" />
  67616. <file baseinstalldir="/" md5sum="6bbb54ef4cf56dc2c0b558b295de5668" name="tests/GetDocTypeDeclarationTests.php" role="test" />
  67617. <file baseinstalldir="/" md5sum="825b440b0ee8abd10b4df017c08bf15f" name="tests/GetXmlDeclarationTests.php" role="test" />
  67618. <file baseinstalldir="/" md5sum="3844dc8d9c4af6d83c3caf28f2fa34fd" name="tests/IsValidNameTests.php" role="test" />
  67619. <file baseinstalldir="/" md5sum="b273525b905ae6d5fc53adcb3ce0b8d9" name="tests/RaiseErrorTests.php" role="test" />
  67620. <file baseinstalldir="/" md5sum="20befbef5e55639539336761a17c64f3" name="tests/ReplaceEntitiesTests.php" role="test" />
  67621. <file baseinstalldir="/" md5sum="a3ceff3302e31f90130be01c312b33b3" name="tests/ReverseEntitiesTests.php" role="test" />
  67622. <file baseinstalldir="/" md5sum="aeb95108896180ef77a7dce3c310a3b8" name="tests/SplitQualifiedNameTests.php" role="test" />
  67623. <file baseinstalldir="/" md5sum="e93010b1eff68f889fefcb006bf20b63" name="tests/Bug4950Tests.php" role="test" />
  67624. <file baseinstalldir="/" md5sum="748ffb640e13e7b960385c7e12413782" name="tests/Bug5392Tests.php" role="test" />
  67625. <file baseinstalldir="/" md5sum="01e68b66e27a6fdb197d572c67ae6bc5" name="tests/Bug18343Tests.php" role="test" />
  67626. <file baseinstalldir="/" md5sum="d945220c38344bc773b18244439bb0cc" name="tests/Bug21177Tests.php" role="test" />
  67627. <file baseinstalldir="/" md5sum="af2672bb90875c2e00f93f563bfafe70" name="tests/Bug21184Tests.php" role="test" />
  67628. <file baseinstalldir="/" md5sum="2e595891598290c522310d06189d2419" name="XML/Util.php" role="php">
  67629. <tasks:replace from="@version@" to="version" type="package-info" />
  67630. </file>
  67631. </dir>
  67632. </contents>
  67633. <dependencies>
  67634. <required>
  67635. <php>
  67636. <min>5.4.0</min>
  67637. </php>
  67638. <pearinstaller>
  67639. <min>1.9.0</min>
  67640. </pearinstaller>
  67641. <extension>
  67642. <name>pcre</name>
  67643. </extension>
  67644. </required>
  67645. </dependencies>
  67646. <phprelease />
  67647. <changelog>
  67648. <release>
  67649. <version>
  67650. <release>0.1</release>
  67651. <api>0.1</api>
  67652. </version>
  67653. <stability>
  67654. <release>stable</release>
  67655. <api>stable</api>
  67656. </stability>
  67657. <date>2003-08-01</date>
  67658. <license uri="http://www.php.net/license">PHP License</license>
  67659. <notes>
  67660. inital release
  67661. </notes>
  67662. </release>
  67663. <release>
  67664. <version>
  67665. <release>0.1.1</release>
  67666. <api>0.1.1</api>
  67667. </version>
  67668. <stability>
  67669. <release>stable</release>
  67670. <api>stable</api>
  67671. </stability>
  67672. <date>2003-08-02</date>
  67673. <license uri="http://www.php.net/license">PHP License</license>
  67674. <notes>
  67675. bugfix: removed bug in createTagFromArray
  67676. </notes>
  67677. </release>
  67678. <release>
  67679. <version>
  67680. <release>0.2</release>
  67681. <api>0.2</api>
  67682. </version>
  67683. <stability>
  67684. <release>stable</release>
  67685. <api>stable</api>
  67686. </stability>
  67687. <date>2003-08-12</date>
  67688. <license uri="http://www.php.net/license">PHP License</license>
  67689. <notes>
  67690. added XML_Util::getDocTypeDeclaration()
  67691. </notes>
  67692. </release>
  67693. <release>
  67694. <version>
  67695. <release>0.2.1</release>
  67696. <api>0.2.1</api>
  67697. </version>
  67698. <stability>
  67699. <release>stable</release>
  67700. <api>stable</api>
  67701. </stability>
  67702. <date>2003-09-05</date>
  67703. <license uri="http://www.php.net/license">PHP License</license>
  67704. <notes>
  67705. fixed bug with zero as tag content in createTagFromArray and createTag
  67706. </notes>
  67707. </release>
  67708. <release>
  67709. <version>
  67710. <release>0.3</release>
  67711. <api>0.3</api>
  67712. </version>
  67713. <stability>
  67714. <release>stable</release>
  67715. <api>stable</api>
  67716. </stability>
  67717. <date>2003-09-12</date>
  67718. <license uri="http://www.php.net/license">PHP License</license>
  67719. <notes>
  67720. added createStartElement() and createEndElement()
  67721. </notes>
  67722. </release>
  67723. <release>
  67724. <version>
  67725. <release>0.4</release>
  67726. <api>0.4</api>
  67727. </version>
  67728. <stability>
  67729. <release>stable</release>
  67730. <api>stable</api>
  67731. </stability>
  67732. <date>2003-09-21</date>
  67733. <license uri="http://www.php.net/license">PHP License</license>
  67734. <notes>
  67735. added createCDataSection(),
  67736. added support for CData sections in createTag* methods,
  67737. fixed bug #23,
  67738. fixed bug in splitQualifiedName()
  67739. </notes>
  67740. </release>
  67741. <release>
  67742. <version>
  67743. <release>0.5</release>
  67744. <api>0.5</api>
  67745. </version>
  67746. <stability>
  67747. <release>stable</release>
  67748. <api>stable</api>
  67749. </stability>
  67750. <date>2003-09-23</date>
  67751. <license uri="http://www.php.net/license">PHP License</license>
  67752. <notes>
  67753. added support for multiline attributes in attributesToString(), createTag*() and createStartElement (requested by Yavor Shahpasov for XML_Serializer),
  67754. added createComment
  67755. </notes>
  67756. </release>
  67757. <release>
  67758. <version>
  67759. <release>0.5.1</release>
  67760. <api>0.5.1</api>
  67761. </version>
  67762. <stability>
  67763. <release>stable</release>
  67764. <api>stable</api>
  67765. </stability>
  67766. <date>2003-09-26</date>
  67767. <license uri="http://www.php.net/license">PHP License</license>
  67768. <notes>
  67769. added default namespace parameter (optional) in splitQualifiedName() (requested by Sebastian Bergmann)
  67770. </notes>
  67771. </release>
  67772. <release>
  67773. <version>
  67774. <release>0.5.2</release>
  67775. <api>0.5.2</api>
  67776. </version>
  67777. <stability>
  67778. <release>stable</release>
  67779. <api>stable</api>
  67780. </stability>
  67781. <date>2003-11-22</date>
  67782. <license uri="http://www.php.net/license">PHP License</license>
  67783. <notes>
  67784. now creates XHTML compliant empty tags (Davey),
  67785. minor whitespace fixes (Davey)
  67786. </notes>
  67787. </release>
  67788. <release>
  67789. <version>
  67790. <release>0.6.0beta1</release>
  67791. <api>0.6.0beta1</api>
  67792. </version>
  67793. <stability>
  67794. <release>beta</release>
  67795. <api>beta</api>
  67796. </stability>
  67797. <date>2004-05-24</date>
  67798. <license uri="http://www.php.net/license">PHP License</license>
  67799. <notes>
  67800. - Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey)
  67801. - added optional parameter to replaceEntities() to define the set of entities to replace
  67802. - added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann)
  67803. - allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter)
  67804. - introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error
  67805. </notes>
  67806. </release>
  67807. <release>
  67808. <version>
  67809. <release>0.6.0</release>
  67810. <api>0.6.0</api>
  67811. </version>
  67812. <stability>
  67813. <release>stable</release>
  67814. <api>stable</api>
  67815. </stability>
  67816. <date>2004-06-07</date>
  67817. <license uri="http://www.php.net/license">PHP License</license>
  67818. <notes>
  67819. - Fixed bug 1438 (namespaces not accepted for isValidName()) (thanks to davey)
  67820. - added optional parameter to replaceEntities() to define the set of entities to replace
  67821. - added optional parameter to attributesToString() to define, whether entities should be replaced (requested by Sebastian Bergmann)
  67822. - allowed second parameter to XML_Util::attributesToString() to be an array containing options (easier to use, if you only need to set the last parameter)
  67823. - introduced XML_Util::raiseError() to avoid the necessity of including PEAR.php, will only be included on error
  67824. </notes>
  67825. </release>
  67826. <release>
  67827. <version>
  67828. <release>0.6.1</release>
  67829. <api>0.6.1</api>
  67830. </version>
  67831. <stability>
  67832. <release>stable</release>
  67833. <api>stable</api>
  67834. </stability>
  67835. <date>2004-10-28</date>
  67836. <license uri="http://www.php.net/license">PHP License</license>
  67837. <notes>
  67838. - Added check for tag name (either as local part or qualified name) in createTagFromArray() (bug #1083)
  67839. </notes>
  67840. </release>
  67841. <release>
  67842. <version>
  67843. <release>1.0.0</release>
  67844. <api>1.0.0</api>
  67845. </version>
  67846. <stability>
  67847. <release>stable</release>
  67848. <api>stable</api>
  67849. </stability>
  67850. <date>2004-10-28</date>
  67851. <license uri="http://www.php.net/license">PHP License</license>
  67852. <notes>
  67853. - Added reverseEntities() (request #2639)
  67854. </notes>
  67855. </release>
  67856. <release>
  67857. <version>
  67858. <release>1.1.0</release>
  67859. <api>1.1.0</api>
  67860. </version>
  67861. <stability>
  67862. <release>stable</release>
  67863. <api>stable</api>
  67864. </stability>
  67865. <date>2004-11-19</date>
  67866. <license uri="http://www.php.net/license">PHP License</license>
  67867. <notes>
  67868. - Added collapseEmptyTags (patch by Sebastian Bergmann and Thomas Duffey)
  67869. </notes>
  67870. </release>
  67871. <release>
  67872. <version>
  67873. <release>1.1.1</release>
  67874. <api>1.1.1</api>
  67875. </version>
  67876. <stability>
  67877. <release>stable</release>
  67878. <api>stable</api>
  67879. </stability>
  67880. <date>2004-12-23</date>
  67881. <license uri="http://www.php.net/license">PHP License</license>
  67882. <notes>
  67883. - fixed bug in replaceEntities() and reverseEntities() in conjunction with XML_UTIL_ENTITIES_HTML
  67884. - createTag() and createTagFromArray() now accept XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML, XML_UTIL_ENTITIES_NONE and XML_UTIL_CDATA_SECTION as $replaceEntities parameter
  67885. </notes>
  67886. </release>
  67887. <release>
  67888. <version>
  67889. <release>1.1.2</release>
  67890. <api>1.1.2</api>
  67891. </version>
  67892. <stability>
  67893. <release>stable</release>
  67894. <api>stable</api>
  67895. </stability>
  67896. <date>2006-12-01</date>
  67897. <license uri="http://www.php.net/license">PHP License</license>
  67898. <notes>
  67899. - fixed bug #5419: isValidName() now checks for character classes
  67900. - implemented request #8196: added optional parameter to influence array sorting to createTag() createTagFromArray() and createStartElement()
  67901. </notes>
  67902. </release>
  67903. <release>
  67904. <version>
  67905. <release>1.1.4</release>
  67906. <api>1.1.4</api>
  67907. </version>
  67908. <stability>
  67909. <release>stable</release>
  67910. <api>stable</api>
  67911. </stability>
  67912. <date>2006-12-16</date>
  67913. <license uri="http://www.php.net/license">PHP License</license>
  67914. <notes>
  67915. - Fixed bug #9561: Not allowing underscores in middle of tags
  67916. </notes>
  67917. </release>
  67918. <release>
  67919. <version>
  67920. <release>1.2.0a1</release>
  67921. <api>1.2.0</api>
  67922. </version>
  67923. <stability>
  67924. <release>alpha</release>
  67925. <api>alpha</api>
  67926. </stability>
  67927. <date>2008-05-04</date>
  67928. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  67929. <notes>
  67930. Changed license to New BSD License (Req #13826 [ashnazg])
  67931. Added a test suite against all API methods [ashnazg]
  67932. Switch to package.xml v2 [ashnazg]
  67933. Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|ja.doma]
  67934. </notes>
  67935. </release>
  67936. <release>
  67937. <version>
  67938. <release>1.2.0a2</release>
  67939. <api>1.2.0</api>
  67940. </version>
  67941. <stability>
  67942. <release>alpha</release>
  67943. <api>alpha</api>
  67944. </stability>
  67945. <date>2008-05-22</date>
  67946. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  67947. <notes>
  67948. Changed license to New BSD License (Req #13826 [ashnazg])
  67949. Added a test suite against all API methods [ashnazg]
  67950. Switch to package.xml v2 [ashnazg]
  67951. Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry]
  67952. Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg]
  67953. Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry]
  67954. -- (this fix differs from the one in v1.2.0a1)
  67955. </notes>
  67956. </release>
  67957. <release>
  67958. <version>
  67959. <release>1.2.0RC1</release>
  67960. <api>1.2.0</api>
  67961. </version>
  67962. <stability>
  67963. <release>beta</release>
  67964. <api>beta</api>
  67965. </stability>
  67966. <date>2008-07-12</date>
  67967. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  67968. <notes>
  67969. Changed license to New BSD License (Req #13826 [ashnazg])
  67970. Added a test suite against all API methods [ashnazg]
  67971. Switch to package.xml v2 [ashnazg]
  67972. Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry]
  67973. Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg]
  67974. Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry]
  67975. -- (this fix differs from the one in v1.2.0a1)
  67976. </notes>
  67977. </release>
  67978. <release>
  67979. <version>
  67980. <release>1.2.0</release>
  67981. <api>1.2.0</api>
  67982. </version>
  67983. <stability>
  67984. <release>stable</release>
  67985. <api>stable</api>
  67986. </stability>
  67987. <date>2008-07-26</date>
  67988. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  67989. <notes>
  67990. Changed license to New BSD License (Req #13826 [ashnazg])
  67991. Added a test suite against all API methods [ashnazg]
  67992. Switch to package.xml v2 [ashnazg]
  67993. Added Req #13839: Missing XHTML empty tags to collapse [ashnazg|drry]
  67994. Fixed Bug #5392: encoding of ISO-8859-1 is the only supported encoding [ashnazg]
  67995. Fixed Bug #4950: Incorrect CDATA serializing [ashnazg|drry]
  67996. -- (this fix differs from the one in v1.2.0a1)
  67997. </notes>
  67998. </release>
  67999. <release>
  68000. <version>
  68001. <release>1.2.1</release>
  68002. <api>1.2.0</api>
  68003. </version>
  68004. <stability>
  68005. <release>stable</release>
  68006. <api>stable</api>
  68007. </stability>
  68008. <date>2011-12-31</date>
  68009. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68010. <notes>
  68011. Fixed Bug #14760: Bug in getDocTypeDeclaration() [ashnazg|fpospisil]
  68012. </notes>
  68013. </release>
  68014. <release>
  68015. <version>
  68016. <release>1.2.2</release>
  68017. <api>1.2.0</api>
  68018. </version>
  68019. <stability>
  68020. <release>stable</release>
  68021. <api>stable</api>
  68022. </stability>
  68023. <date>2014-06-07</date>
  68024. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68025. <notes>
  68026. QA release
  68027. Bug #18343 Entities in file names decoded during packaging
  68028. Bug #19174 upgrade PHPUnit require statements &amp; other fixes (for PEAR QA Team)
  68029. Request #19750 examples/example.php encoding
  68030. </notes>
  68031. </release>
  68032. <release>
  68033. <version>
  68034. <release>1.2.3</release>
  68035. <api>1.2.0</api>
  68036. </version>
  68037. <stability>
  68038. <release>stable</release>
  68039. <api>stable</api>
  68040. </stability>
  68041. <date>2014-06-07</date>
  68042. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68043. <notes>
  68044. Bug #20293 Broken installation for 1.2.2
  68045. </notes>
  68046. </release>
  68047. <release>
  68048. <version>
  68049. <release>1.3.0</release>
  68050. <api>1.3.0</api>
  68051. </version>
  68052. <stability>
  68053. <release>stable</release>
  68054. <api>stable</api>
  68055. </stability>
  68056. <date>2015-02-27</date>
  68057. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68058. <notes>
  68059. * Set minimum PHP version to 5.3.0
  68060. * Mark static methods with static keyword
  68061. </notes>
  68062. </release>
  68063. <release>
  68064. <version>
  68065. <release>1.4.0</release>
  68066. <api>1.4.0</api>
  68067. </version>
  68068. <stability>
  68069. <release>stable</release>
  68070. <api>stable</api>
  68071. </stability>
  68072. <date>2017-02-03</date>
  68073. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68074. <notes>
  68075. * Set minimum PHP version to 5.4.0
  68076. * Set minimum PEAR version to 1.10.1
  68077. * Adds a new XML_UTIL_COLLAPSE_NONE option
  68078. for preventing empty tag collapsing.
  68079. * Request #15467 CDATA sections and blank nodes
  68080. </notes>
  68081. </release>
  68082. <release>
  68083. <version>
  68084. <release>1.4.1</release>
  68085. <api>1.4.0</api>
  68086. </version>
  68087. <stability>
  68088. <release>stable</release>
  68089. <api>stable</api>
  68090. </stability>
  68091. <date>2017-02-07</date>
  68092. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68093. <notes>
  68094. * Bug #21177 XML_Util::collapseEmptyTags() can return NULL
  68095. </notes>
  68096. </release>
  68097. <release>
  68098. <version>
  68099. <release>1.4.2</release>
  68100. <api>1.4.0</api>
  68101. </version>
  68102. <stability>
  68103. <release>stable</release>
  68104. <api>stable</api>
  68105. </stability>
  68106. <date>2017-02-22</date>
  68107. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68108. <notes>
  68109. * Bug #21184 Collapse issue
  68110. </notes>
  68111. </release>
  68112. <release>
  68113. <version>
  68114. <release>1.4.3</release>
  68115. <api>1.4.0</api>
  68116. </version>
  68117. <stability>
  68118. <release>stable</release>
  68119. <api>stable</api>
  68120. </stability>
  68121. <date>2017-06-28</date>
  68122. <license uri="http://opensource.org/licenses/bsd-license">BSD License</license>
  68123. <notes>
  68124. * Decrease minimum PEAR version to 1.9.0 to allow PEAR upgrades
  68125. </notes>
  68126. </release>
  68127. </changelog>
  68128. </package>
  68129. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/examples/example.php�����������������������������������������������������������������0000644�0001750�0000144�00000021710�13125000640�016477 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68130. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  68131. /**
  68132. * Examples (file #1)
  68133. *
  68134. * several examples for the methods of XML_Util
  68135. *
  68136. * PHP versions 4 and 5
  68137. *
  68138. * LICENSE:
  68139. *
  68140. * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
  68141. * All rights reserved.
  68142. *
  68143. * Redistribution and use in source and binary forms, with or without
  68144. * modification, are permitted provided that the following conditions
  68145. * are met:
  68146. *
  68147. * * Redistributions of source code must retain the above copyright
  68148. * notice, this list of conditions and the following disclaimer.
  68149. * * Redistributions in binary form must reproduce the above copyright
  68150. * notice, this list of conditions and the following disclaimer in the
  68151. * documentation and/or other materials provided with the distribution.
  68152. * * The name of the author may not be used to endorse or promote products
  68153. * derived from this software without specific prior written permission.
  68154. *
  68155. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  68156. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  68157. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  68158. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  68159. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  68160. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  68161. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  68162. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  68163. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  68164. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  68165. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  68166. *
  68167. * @category XML
  68168. * @package XML_Util
  68169. * @subpackage Examples
  68170. * @author Stephan Schmidt <schst@php.net>
  68171. * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
  68172. * @license http://opensource.org/licenses/bsd-license New BSD License
  68173. * @version CVS: $Id$
  68174. * @link http://pear.php.net/package/XML_Util
  68175. */
  68176. /**
  68177. * set error level
  68178. */
  68179. error_reporting(E_ALL);
  68180. require_once 'XML/Util.php';
  68181. /**
  68182. * replacing XML entities
  68183. */
  68184. print 'replace XML entities:<br>';
  68185. print XML_Util::replaceEntities('This string contains < & >.');
  68186. print "\n<br><br>\n";
  68187. /**
  68188. * reversing XML entities
  68189. */
  68190. print 'replace XML entities:<br>';
  68191. print XML_Util::reverseEntities('This string contains &lt; &amp; &gt;.');
  68192. print "\n<br><br>\n";
  68193. /**
  68194. * building XML declaration
  68195. */
  68196. print 'building XML declaration:<br>';
  68197. print htmlspecialchars(XML_Util::getXMLDeclaration());
  68198. print "\n<br><br>\n";
  68199. print 'building XML declaration with additional attributes:<br>';
  68200. print htmlspecialchars(XML_Util::getXMLDeclaration('1.0', 'UTF-8', true));
  68201. print "\n<br><br>\n";
  68202. /**
  68203. * building document type declaration
  68204. */
  68205. print 'building DocType declaration:<br>';
  68206. print htmlspecialchars(XML_Util::getDocTypeDeclaration('package',
  68207. 'http://pear.php.net/dtd/package-1.0'));
  68208. print "\n<br><br>\n";
  68209. print 'building DocType declaration with public ID (does not exist):<br>';
  68210. print htmlspecialchars(XML_Util::getDocTypeDeclaration('package',
  68211. array('uri' => 'http://pear.php.net/dtd/package-1.0',
  68212. 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1')));
  68213. print "\n<br><br>\n";
  68214. print 'building DocType declaration with internal DTD:<br>';
  68215. print '<pre>';
  68216. print htmlspecialchars(XML_Util::getDocTypeDeclaration('package',
  68217. 'http://pear.php.net/dtd/package-1.0',
  68218. '<!ELEMENT additionalInfo (#PCDATA)>'));
  68219. print '</pre>';
  68220. print "\n<br><br>\n";
  68221. /**
  68222. * creating an attribute string
  68223. */
  68224. $att = array(
  68225. 'foo' => 'bar',
  68226. 'argh' => 'tomato'
  68227. );
  68228. print 'converting array to string:<br>';
  68229. print XML_Util::attributesToString($att);
  68230. print "\n<br><br>\n";
  68231. /**
  68232. * creating an attribute string with linebreaks
  68233. */
  68234. $att = array(
  68235. 'foo' => 'bar',
  68236. 'argh' => 'tomato'
  68237. );
  68238. print 'converting array to string (including line breaks):<br>';
  68239. print '<pre>';
  68240. print XML_Util::attributesToString($att, true, true);
  68241. print '</pre>';
  68242. print "\n<br><br>\n";
  68243. /**
  68244. * splitting a qualified tag name
  68245. */
  68246. print 'splitting qualified tag name:<br>';
  68247. print '<pre>';
  68248. print_r(XML_Util::splitQualifiedName('xslt:stylesheet'));
  68249. print '</pre>';
  68250. print "\n<br>\n";
  68251. /**
  68252. * splitting a qualified tag name (no namespace)
  68253. */
  68254. print 'splitting qualified tag name (no namespace):<br>';
  68255. print '<pre>';
  68256. print_r(XML_Util::splitQualifiedName('foo'));
  68257. print '</pre>';
  68258. print "\n<br>\n";
  68259. /**
  68260. * splitting a qualified tag name (no namespace, but default namespace specified)
  68261. */
  68262. print 'splitting qualified tag name '
  68263. . '(no namespace, but default namespace specified):<br>';
  68264. print '<pre>';
  68265. print_r(XML_Util::splitQualifiedName('foo', 'bar'));
  68266. print '</pre>';
  68267. print "\n<br>\n";
  68268. /**
  68269. * verifying XML names
  68270. */
  68271. print 'verifying \'My private tag\':<br>';
  68272. print '<pre>';
  68273. print_r(XML_Util::isValidname('My Private Tag'));
  68274. print '</pre>';
  68275. print "\n<br><br>\n";
  68276. print 'verifying \'-MyTag\':<br>';
  68277. print '<pre>';
  68278. print_r(XML_Util::isValidname('-MyTag'));
  68279. print '</pre>';
  68280. print "\n<br><br>\n";
  68281. /**
  68282. * creating an XML tag
  68283. */
  68284. $tag = array(
  68285. 'namespace' => 'foo',
  68286. 'localPart' => 'bar',
  68287. 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  68288. 'content' => 'I\'m inside the tag'
  68289. );
  68290. print 'creating a tag with namespace and local part:<br>';
  68291. print htmlentities(XML_Util::createTagFromArray($tag));
  68292. print "\n<br><br>\n";
  68293. /**
  68294. * creating an XML tag
  68295. */
  68296. $tag = array(
  68297. 'qname' => 'foo:bar',
  68298. 'namespaceUri' => 'http://foo.com',
  68299. 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  68300. 'content' => 'I\'m inside the tag'
  68301. );
  68302. print 'creating a tag with qualified name and namespaceUri:<br>';
  68303. print htmlentities(XML_Util::createTagFromArray($tag));
  68304. print "\n<br><br>\n";
  68305. /**
  68306. * creating an XML tag
  68307. */
  68308. $tag = array(
  68309. 'qname' => 'bar',
  68310. 'namespaceUri' => 'http://foo.com',
  68311. 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable')
  68312. );
  68313. print 'creating an empty tag without namespace but namespace Uri:<br>';
  68314. print htmlentities(XML_Util::createTagFromArray($tag));
  68315. print "\n<br><br>\n";
  68316. /**
  68317. * creating an XML tag with more namespaces
  68318. */
  68319. $tag = array(
  68320. 'namespace' => 'foo',
  68321. 'localPart' => 'bar',
  68322. 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  68323. 'content' => 'I\'m inside the tag',
  68324. 'namespaces' => array(
  68325. 'bar' => 'http://bar.com',
  68326. 'pear' => 'http://pear.php.net',
  68327. )
  68328. );
  68329. print 'creating an XML tag with more namespaces:<br />';
  68330. print htmlentities(XML_Util::createTagFromArray($tag));
  68331. print "\n<br><br>\n";
  68332. /**
  68333. * creating an XML tag with a CData Section
  68334. */
  68335. $tag = array(
  68336. 'qname' => 'foo',
  68337. 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  68338. 'content' => 'I\'m inside the tag'
  68339. );
  68340. print 'creating a tag with CData section:<br>';
  68341. print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_CDATA_SECTION));
  68342. print "\n<br><br>\n";
  68343. /**
  68344. * creating an XML tag with a CData Section
  68345. */
  68346. $tag = array(
  68347. 'qname' => 'foo',
  68348. 'attributes' => array('key' => 'value', 'argh' => 'tütü'),
  68349. 'content' =>
  68350. 'Also XHTML-tags can be created '
  68351. . 'and HTML entities can be replaced Ä ä Ü ö <>.'
  68352. );
  68353. print 'creating a tag with HTML entities:<br>';
  68354. print htmlentities(XML_Util::createTagFromArray($tag, XML_UTIL_ENTITIES_HTML));
  68355. print "\n<br><br>\n";
  68356. /**
  68357. * creating an XML tag with createTag
  68358. */
  68359. print 'creating a tag with createTag:<br>';
  68360. print htmlentities(XML_Util::createTag('myNs:myTag',
  68361. array('foo' => 'bar'),
  68362. 'This is inside the tag',
  68363. 'http://www.w3c.org/myNs#'));
  68364. print "\n<br><br>\n";
  68365. /**
  68366. * trying to create an XML tag with an array as content
  68367. */
  68368. $tag = array(
  68369. 'qname' => 'bar',
  68370. 'content' => array('foo' => 'bar')
  68371. );
  68372. print 'trying to create an XML tag with an array as content:<br>';
  68373. print '<pre>';
  68374. print_r(XML_Util::createTagFromArray($tag));
  68375. print '</pre>';
  68376. print "\n<br><br>\n";
  68377. /**
  68378. * trying to create an XML tag without a name
  68379. */
  68380. $tag = array(
  68381. 'attributes' => array('foo' => 'bar'),
  68382. );
  68383. print 'trying to create an XML tag without a name:<br>';
  68384. print '<pre>';
  68385. print_r(XML_Util::createTagFromArray($tag));
  68386. print '</pre>';
  68387. print "\n<br><br>\n";
  68388. ?>
  68389. ��������������������������������������������������������XML_Util-1.4.3/examples/example2.php����������������������������������������������������������������0000644�0001750�0000144�00000011353�13125000640�016563 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68390. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  68391. /**
  68392. * Examples (file #2)
  68393. *
  68394. * several examples for the methods of XML_Util
  68395. *
  68396. * PHP versions 4 and 5
  68397. *
  68398. * LICENSE:
  68399. *
  68400. * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
  68401. * All rights reserved.
  68402. *
  68403. * Redistribution and use in source and binary forms, with or without
  68404. * modification, are permitted provided that the following conditions
  68405. * are met:
  68406. *
  68407. * * Redistributions of source code must retain the above copyright
  68408. * notice, this list of conditions and the following disclaimer.
  68409. * * Redistributions in binary form must reproduce the above copyright
  68410. * notice, this list of conditions and the following disclaimer in the
  68411. * documentation and/or other materials provided with the distribution.
  68412. * * The name of the author may not be used to endorse or promote products
  68413. * derived from this software without specific prior written permission.
  68414. *
  68415. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  68416. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  68417. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  68418. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  68419. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  68420. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  68421. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  68422. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  68423. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  68424. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  68425. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  68426. *
  68427. * @category XML
  68428. * @package XML_Util
  68429. * @subpackage Examples
  68430. * @author Stephan Schmidt <schst@php.net>
  68431. * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
  68432. * @license http://opensource.org/licenses/bsd-license New BSD License
  68433. * @version CVS: $Id$
  68434. * @link http://pear.php.net/package/XML_Util
  68435. */
  68436. /**
  68437. * set error level
  68438. */
  68439. error_reporting(E_ALL);
  68440. require_once 'XML/Util.php';
  68441. /**
  68442. * creating a start element
  68443. */
  68444. print 'creating a start element:<br>';
  68445. print htmlentities(XML_Util::createStartElement('myNs:myTag',
  68446. array('foo' => 'bar'), 'http://www.w3c.org/myNs#'));
  68447. print "\n<br><br>\n";
  68448. /**
  68449. * creating a start element
  68450. */
  68451. print 'creating a start element:<br>';
  68452. print htmlentities(XML_Util::createStartElement('myTag',
  68453. array(), 'http://www.w3c.org/myNs#'));
  68454. print "\n<br><br>\n";
  68455. /**
  68456. * creating a start element
  68457. */
  68458. print 'creating a start element:<br>';
  68459. print '<pre>';
  68460. print htmlentities(XML_Util::createStartElement('myTag',
  68461. array('foo' => 'bar', 'argh' => 'tomato'),
  68462. 'http://www.w3c.org/myNs#', true));
  68463. print '</pre>';
  68464. print "\n<br><br>\n";
  68465. /**
  68466. * creating an end element
  68467. */
  68468. print 'creating an end element:<br>';
  68469. print htmlentities(XML_Util::createEndElement('myNs:myTag'));
  68470. print "\n<br><br>\n";
  68471. /**
  68472. * creating a CData section
  68473. */
  68474. print 'creating a CData section:<br>';
  68475. print htmlentities(XML_Util::createCDataSection('I am content.'));
  68476. print "\n<br><br>\n";
  68477. /**
  68478. * creating a comment
  68479. */
  68480. print 'creating a comment:<br>';
  68481. print htmlentities(XML_Util::createComment('I am a comment.'));
  68482. print "\n<br><br>\n";
  68483. /**
  68484. * creating an XML tag with multiline mode
  68485. */
  68486. $tag = array(
  68487. 'qname' => 'foo:bar',
  68488. 'namespaceUri' => 'http://foo.com',
  68489. 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  68490. 'content' => 'I\'m inside the tag & contain dangerous chars'
  68491. );
  68492. print 'creating a tag with qualified name and namespaceUri:<br>';
  68493. print '<pre>';
  68494. print htmlentities(XML_Util::createTagFromArray($tag,
  68495. XML_UTIL_REPLACE_ENTITIES, true));
  68496. print '</pre>';
  68497. print "\n<br><br>\n";
  68498. /**
  68499. * create an attribute string without replacing the entities
  68500. */
  68501. $atts = array('series' => 'Starsky &amp; Hutch', 'channel' => 'ABC');
  68502. print 'creating a attribute string, '
  68503. . 'entities in values already had been replaced:<br>';
  68504. print htmlentities(XML_Util::attributesToString($atts,
  68505. true, false, false, false, XML_UTIL_ENTITIES_NONE));
  68506. print "\n<br><br>\n";
  68507. /**
  68508. * using the array-syntax for attributesToString()
  68509. */
  68510. $atts = array('series' => 'Starsky &amp; Hutch', 'channel' => 'ABC');
  68511. print 'using the array-syntax for attributesToString()<br>';
  68512. print htmlentities(XML_Util::attributesToString($atts,
  68513. array('entities' => XML_UTIL_ENTITIES_NONE)));
  68514. print "\n<br><br>\n";
  68515. ?>
  68516. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/AbstractUnitTests.php����������������������������������������������������������0000644�0001750�0000144�00000000650�13125000640�020016 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68517. /*
  68518. * Allow for PHPUnit 4.* while XML_Util is still usable on PHP 5.4
  68519. */
  68520. if (!class_exists('PHPUnit_Framework_TestCase')) {
  68521. class PHPUnit_Framework_TestCase extends \PHPUnit\Framework\TestCase {}
  68522. }
  68523. abstract class AbstractUnitTests extends \PHPUnit_Framework_TestCase
  68524. {
  68525. public function setUp()
  68526. {
  68527. // ensure the class is defined, and thus its constants are declared
  68528. new XML_Util();
  68529. }
  68530. }
  68531. ����������������������������������������������������������������������������������������XML_Util-1.4.3/tests/ApiVersionTests.php������������������������������������������������������������0000644�0001750�0000144�00000000335�13125000640�017472 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68532. class ApiVersionTests extends AbstractUnitTests
  68533. {
  68534. /**
  68535. * @covers XML_Util::apiVersion()
  68536. */
  68537. public function testApiVersion()
  68538. {
  68539. $this->assertEquals('1.4', XML_Util::apiVersion());
  68540. }
  68541. }���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/AttributesToStringTests.php����������������������������������������������������0000644�0001750�0000144�00000017026�13125000640�021240 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68542. class AttributesToStringTests extends AbstractUnitTests
  68543. {
  68544. /**
  68545. * @covers XML_Util::attributesToString()
  68546. */
  68547. public function testAttributesToStringBasicUsage()
  68548. {
  68549. $original = array('foo' => 'bar','boo' => 'baz',);
  68550. $expected = " boo=\"baz\" foo=\"bar\"";
  68551. $this->assertEquals($expected, XML_Util::attributesToString($original));
  68552. }
  68553. /**
  68554. * @covers XML_Util::attributesToString()
  68555. */
  68556. public function testAttributesToStringWithExplicitSortTrue()
  68557. {
  68558. $original = array('foo' => 'bar','boo' => 'baz',);
  68559. $expected = " boo=\"baz\" foo=\"bar\"";
  68560. $sort = true;
  68561. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort));
  68562. }
  68563. /**
  68564. * @covers XML_Util::attributesToString()
  68565. */
  68566. public function testAttributesToStringWithExplicitSortFalse()
  68567. {
  68568. $original = array('foo' => 'bar','boo' => 'baz',);
  68569. $expected = " foo=\"bar\" boo=\"baz\"";
  68570. $sort = false;
  68571. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort));
  68572. }
  68573. /**
  68574. * @covers XML_Util::attributesToString()
  68575. */
  68576. public function testAttributesToStringWithMultilineFalse()
  68577. {
  68578. $original = array('foo' => 'bar','boo' => 'baz',);
  68579. $expected = " boo=\"baz\" foo=\"bar\"";
  68580. $sort = true;
  68581. $multiline = false;
  68582. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline));
  68583. }
  68584. /**
  68585. * @covers XML_Util::attributesToString()
  68586. */
  68587. public function testAttributesToStringWithMultilineTrue()
  68588. {
  68589. $original = array('foo' => 'bar','boo' => 'baz',);
  68590. $expected =
  68591. <<< EOF
  68592. boo="baz"
  68593. foo="bar"
  68594. EOF;
  68595. $sort = true;
  68596. $multiline = true;
  68597. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline));
  68598. }
  68599. /**
  68600. * @covers XML_Util::attributesToString()
  68601. */
  68602. public function testAttributesToStringWithExplicitIndent()
  68603. {
  68604. $original = array('foo' => 'bar','boo' => 'baz',);
  68605. $expected = " boo=\"baz\"\n foo=\"bar\"";
  68606. $sort = true;
  68607. $multiline = true;
  68608. $indent = ' '; // 8 spaces
  68609. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline, $indent));
  68610. }
  68611. /**
  68612. * @covers XML_Util::attributesToString()
  68613. */
  68614. public function testAttributesToStringWithExplicitLinebreak()
  68615. {
  68616. $original = array('foo' => 'bar','boo' => 'baz',);
  68617. $expected = " boo=\"baz\"\n^foo=\"bar\"";
  68618. $sort = true;
  68619. $multiline = true;
  68620. $linebreak = '^'; // some dummy character
  68621. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline, $linebreak));
  68622. }
  68623. /**
  68624. * @covers XML_Util::attributesToString()
  68625. */
  68626. public function testAttributesToStringWithOptionsThatIncludesSort()
  68627. {
  68628. $original = array('foo' => 'bar','boo' => 'baz',);
  68629. $options = array(
  68630. 'multiline' => true,
  68631. 'indent' => '----',
  68632. 'linebreak' => "^",
  68633. 'entities' => XML_UTIL_ENTITIES_XML,
  68634. 'sort' => true,
  68635. );
  68636. $expected = " boo=\"baz\"\n----foo=\"bar\"";
  68637. $this->assertEquals($expected, XML_Util::attributesToString($original, $options));
  68638. }
  68639. /**
  68640. * @covers XML_Util::attributesToString()
  68641. */
  68642. public function testAttributesToStringWithOptionsThatExcludesSort()
  68643. {
  68644. $original = array('foo' => 'bar','boo' => 'baz',);
  68645. $options = array(
  68646. 'multiline' => true,
  68647. 'indent' => '----',
  68648. 'linebreak' => "^",
  68649. 'entities' => XML_UTIL_ENTITIES_XML,
  68650. );
  68651. $expected = " boo=\"baz\"\n----foo=\"bar\"";
  68652. $this->assertEquals($expected, XML_Util::attributesToString($original, $options));
  68653. }
  68654. /**
  68655. * @covers XML_Util::attributesToString()
  68656. */
  68657. public function testAttributesToStringWithEntitiesNone()
  68658. {
  68659. $original = array("foo" => "b@&r", "boo" => "b><z");
  68660. $expected = " boo=\"b><z\" foo=\"b@&r\"";
  68661. $sort = true;
  68662. $multiline = false;
  68663. $linebreak = ' ';
  68664. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline, $linebreak, PHP_EOL, XML_UTIL_ENTITIES_NONE));
  68665. }
  68666. /**
  68667. * @covers XML_Util::attributesToString()
  68668. */
  68669. public function testAttributesToStringWithEntitiesXml()
  68670. {
  68671. $original = array("foo" => "b@&r", "boo" => "b><z");
  68672. $expected = " boo=\"b&gt;&lt;z\" foo=\"b@&amp;r\"";
  68673. $sort = true;
  68674. $multiline = false;
  68675. $linebreak = ' ';
  68676. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline, $linebreak, PHP_EOL, XML_UTIL_ENTITIES_XML));
  68677. }
  68678. /**
  68679. * @covers XML_Util::attributesToString()
  68680. */
  68681. public function testAttributesToStringWithEntitiesXmlRequired()
  68682. {
  68683. $original = array("foo" => "b@&r", "boo" => "b><z");
  68684. $expected = " boo=\"b>&lt;z\" foo=\"b@&amp;r\"";
  68685. $sort = true;
  68686. $multiline = false;
  68687. $linebreak = ' ';
  68688. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline, $linebreak, PHP_EOL, XML_UTIL_ENTITIES_XML_REQUIRED));
  68689. }
  68690. /**
  68691. * @covers XML_Util::attributesToString()
  68692. */
  68693. public function testAttributesToStringWithEntitiesHtml()
  68694. {
  68695. $original = array("foo" => "b@&r", "boo" => "b><z");
  68696. $expected = " boo=\"b&gt;&lt;z\" foo=\"b@&amp;r\"";
  68697. $sort = true;
  68698. $multiline = false;
  68699. $linebreak = ' ';
  68700. $this->assertEquals($expected, XML_Util::attributesToString($original, $sort, $multiline, $linebreak, PHP_EOL, XML_UTIL_ENTITIES_HTML));
  68701. }
  68702. /**
  68703. * Tag attributes should not be treated as CDATA,
  68704. * so the operation will instead quietly use XML_UTIL_ENTITIES_XML.
  68705. *
  68706. * @covers XML_Util::attributesToString()
  68707. */
  68708. public function testAttributesToStringWithCDataSectionForSingleAttribute()
  68709. {
  68710. $original = array('foo' => 'bar'); // need exactly one attribute here
  68711. $options = array(
  68712. 'sort' => true, // doesn't matter for this testcase
  68713. 'multiline' => false, // doesn't matter for this testcase
  68714. 'indent' => null, // doesn't matter for this testcase
  68715. 'linebreak' => null, // doesn't matter for this testcase
  68716. 'entities' => XML_UTIL_CDATA_SECTION, // DOES matter for this testcase
  68717. );
  68718. $expected = " foo=\"bar\"";
  68719. $this->assertEquals($expected, XML_Util::attributesToString($original, $options));
  68720. }
  68721. /**
  68722. * Tag attributes should not be treated as CDATA,
  68723. * so the operation will instead quietly use XML_UTIL_ENTITIES_XML.
  68724. *
  68725. * @covers XML_Util::attributesToString()
  68726. */
  68727. public function testAttributesToStringWithCDataSectionForMultipleAttributesAndMultilineFalse()
  68728. {
  68729. $original = array('foo' => 'bar', 'boo' => 'baz'); // need more than one attribute here
  68730. $options = array(
  68731. 'sort' => true, // doesn't matter for this testcase
  68732. 'multiline' => false, // DOES matter for this testcase, must be false
  68733. 'indent' => null, // doesn't matter for this testcase
  68734. 'linebreak' => null, // doesn't matter for this testcase
  68735. 'entities' => XML_UTIL_CDATA_SECTION, // DOES matter for this testcase
  68736. );
  68737. $expected = " boo=\"baz\" foo=\"bar\"";
  68738. $this->assertEquals($expected, XML_Util::attributesToString($original, $options));
  68739. }
  68740. }
  68741. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CollapseEmptyTagsTests.php�����������������������������������������������������0000644�0001750�0000144�00000010401�13125000640�021006 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68742. class CollapseEmptyTagsTests extends AbstractUnitTests
  68743. {
  68744. /**
  68745. * @covers XML_Util::collapseEmptyTags()
  68746. */
  68747. public function testCollapseEmptyTagsBasicUsage()
  68748. {
  68749. $emptyTag = "<foo></foo>";
  68750. $expected = "<foo />";
  68751. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag));
  68752. }
  68753. /**
  68754. * @covers XML_Util::collapseEmptyTags()
  68755. */
  68756. public function testCollapseEmptyTagsBasicUsageAlongsideNonemptyTag()
  68757. {
  68758. $emptyTag = "<foo></foo>";
  68759. $otherTag = "<bar>baz</bar>";
  68760. $expected = "<foo /><bar>baz</bar>";
  68761. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $otherTag));
  68762. }
  68763. /**
  68764. * @covers XML_Util::collapseEmptyTags()
  68765. */
  68766. public function testCollapseEmptyTagsOnOneEmptyTagWithCollapseAll()
  68767. {
  68768. $emptyTag = "<foo></foo>";
  68769. $expected = "<foo />";
  68770. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag, XML_UTIL_COLLAPSE_ALL));
  68771. }
  68772. /**
  68773. * @covers XML_Util::collapseEmptyTags()
  68774. */
  68775. public function testCollapseEmptyTagsOnOneEmptyTagAlongsideNonemptyTagWithCollapseAll()
  68776. {
  68777. $emptyTag = "<foo></foo>";
  68778. $otherTag = "<bar>baz</bar>";
  68779. $expected = "<foo /><bar>baz</bar>";
  68780. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $otherTag, XML_UTIL_COLLAPSE_ALL));
  68781. }
  68782. /**
  68783. * @covers XML_Util::collapseEmptyTags()
  68784. */
  68785. public function testCollapseEmptyTagsOnOneEmptyTagAlongsideNonemptyTagAlongsideEmptyTagWithCollapseAll()
  68786. {
  68787. $emptyTag = "<foo></foo>";
  68788. $otherTag = "<bar>baz</bar>";
  68789. $expected = "<foo /><bar>baz</bar><foo />";
  68790. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $otherTag . $emptyTag, XML_UTIL_COLLAPSE_ALL));
  68791. }
  68792. /**
  68793. * @covers XML_Util::collapseEmptyTags()
  68794. */
  68795. public function testCollapseEmptyTagsOnOneEmptyPrefixedTagAlongsideNonemptyTagAlongsideEmptyPrefixedTagWithCollapseAll()
  68796. {
  68797. $emptyTag = "<foo:foo2></foo:foo2>";
  68798. $otherTag = "<bar>baz</bar>";
  68799. $expected = "<foo:foo2 /><bar>baz</bar><foo:foo2 />";
  68800. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $otherTag . $emptyTag, XML_UTIL_COLLAPSE_ALL));
  68801. }
  68802. /**
  68803. * @covers XML_Util::collapseEmptyTags()
  68804. */
  68805. public function testCollapseEmptyTagsOnOneEmptyNsPrefixedTagAlongsideNonemptyTagAlongsideEmptyNsPrefixedTagWithCollapseAll()
  68806. {
  68807. $emptyTag = "<http://foo.com:foo2></http://foo.com:foo2>";
  68808. $otherTag = "<bar>baz</bar>";
  68809. $expected = "<http://foo.com:foo2 /><bar>baz</bar><http://foo.com:foo2 />";
  68810. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $otherTag . $emptyTag, XML_UTIL_COLLAPSE_ALL));
  68811. }
  68812. /**
  68813. * @covers XML_Util::collapseEmptyTags()
  68814. */
  68815. public function testCollapseEmptyTagsOnOneEmptyTagWithCollapseXhtml()
  68816. {
  68817. $emptyTag = "<foo></foo>";
  68818. $expected = "<foo></foo>";
  68819. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag, XML_UTIL_COLLAPSE_XHTML_ONLY));
  68820. }
  68821. /**
  68822. * @covers XML_Util::collapseEmptyTags()
  68823. */
  68824. public function testCollapseEmptyTagsOnOneEmptyTagAlongsideNonemptyTagWithCollapseXhtml()
  68825. {
  68826. $emptyTag = "<foo></foo>";
  68827. $otherTag = "<bar>baz</bar>";
  68828. $xhtmlTag = "<br></br>";
  68829. $expected = "<foo></foo><br /><bar>baz</bar>";
  68830. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $xhtmlTag . $otherTag, XML_UTIL_COLLAPSE_XHTML_ONLY));
  68831. }
  68832. /**
  68833. * @covers XML_Util::collapseEmptyTags()
  68834. */
  68835. public function testCollapseEmptyTagsOnOneEmptyTagWithCollapseNone()
  68836. {
  68837. $emptyTag = "<foo></foo>";
  68838. $expected = "<foo></foo>";
  68839. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag, XML_UTIL_COLLAPSE_NONE));
  68840. }
  68841. /**
  68842. * @covers XML_Util::collapseEmptyTags()
  68843. */
  68844. public function testCollapseEmptyTagsOnOneEmptyTagAlongsideNonemptyTagWithCollapseNone()
  68845. {
  68846. $emptyTag = "<foo></foo>";
  68847. $otherTag = "<bar>baz</bar>";
  68848. $expected = "<foo></foo><bar>baz</bar>";
  68849. $this->assertEquals($expected, XML_Util::collapseEmptyTags($emptyTag . $otherTag, XML_UTIL_COLLAPSE_NONE));
  68850. }
  68851. }
  68852. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CreateCDataSectionTests.php����������������������������������������������������0000644�0001750�0000144�00000000552�13125000640�021041 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68853. class CreateCDataSectionTests extends AbstractUnitTests
  68854. {
  68855. /**
  68856. * @covers XML_Util::createCDataSection()
  68857. */
  68858. public function testCreateCDataSectionBasicUsage()
  68859. {
  68860. $original = "I am content.";
  68861. $expected ="<![CDATA[I am content.]]>";
  68862. $this->assertEquals($expected, XML_Util::createCDataSection($original));
  68863. }
  68864. }
  68865. ������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CreateCommentTests.php���������������������������������������������������������0000644�0001750�0000144�00000000524�13125000640�020141 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68866. class CreateCommentTests extends AbstractUnitTests
  68867. {
  68868. /**
  68869. * @covers XML_Util::createComment()
  68870. */
  68871. public function testCreateCommentBasicUsage()
  68872. {
  68873. $original = "I am comment.";
  68874. $expected = "<!-- I am comment. -->";
  68875. $this->assertEquals($expected, XML_Util::createComment($original));
  68876. }
  68877. }
  68878. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CreateEndElementTests.php������������������������������������������������������0000644�0001750�0000144�00000001145�13125000640�020557 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68879. class CreateEndElementTests extends AbstractUnitTests
  68880. {
  68881. /**
  68882. * @covers XML_Util::createEndElement()
  68883. */
  68884. public function testCreateEndElementBasicUsage()
  68885. {
  68886. $original = "myTag";
  68887. $expected = "</myTag>";
  68888. $this->assertEquals($expected, XML_Util::createEndElement($original));
  68889. }
  68890. /**
  68891. * @covers XML_Util::createEndElement()
  68892. */
  68893. public function testCreateEndElementWithNamespacedTag()
  68894. {
  68895. $original = "myNs:myTag";
  68896. $expected = "</myNs:myTag>";
  68897. $this->assertEquals($expected, XML_Util::createEndElement($original));
  68898. }
  68899. }
  68900. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CreateStartElementTests.php����������������������������������������������������0000644�0001750�0000144�00000012442�13125000640�021150 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  68901. class CreateStartElementTests extends AbstractUnitTests
  68902. {
  68903. /**
  68904. * @covers XML_Util::createStartElement()
  68905. */
  68906. public function testCreateStartElementForTagOnly()
  68907. {
  68908. $original = "myNs:myTag";
  68909. $expected = "<myNs:myTag>";
  68910. $this->assertEquals($expected, XML_Util::createStartElement($original));
  68911. }
  68912. /**
  68913. * @covers XML_Util::createStartElement()
  68914. */
  68915. public function testCreateStartElementForTagWithAttributes()
  68916. {
  68917. $originalTag = "myNs:myTag";
  68918. $originalAttributes = array("foo" => "bar");
  68919. $expected = "<myNs:myTag foo=\"bar\">";
  68920. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes));
  68921. }
  68922. /**
  68923. * @covers XML_Util::createStartElement()
  68924. */
  68925. public function testCreateStartElementForTagWithEmptyAttributes()
  68926. {
  68927. $originalTag = "myNs:myTag";
  68928. $originalAttributes = "";
  68929. $expected = "<myNs:myTag>";
  68930. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes));
  68931. }
  68932. /**
  68933. * @covers XML_Util::createStartElement()
  68934. */
  68935. public function testCreateStartElementForTagWithAttributesAndNamespace()
  68936. {
  68937. $originalTag = "myNs:myTag";
  68938. $originalAttributes = array("foo" => "bar");
  68939. $originalNamespace = "http://www.w3c.org/myNs#";
  68940. $expected = "<myNs:myTag foo=\"bar\" xmlns:myNs=\"http://www.w3c.org/myNs#\">";
  68941. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace));
  68942. }
  68943. /**
  68944. * @covers XML_Util::createStartElement()
  68945. */
  68946. public function testCreateStartElementForTagWithEmptyAttributesAndNonUriNamespace()
  68947. {
  68948. $originalTag = "myTag";
  68949. $originalAttributes = "";
  68950. $originalNamespace = "foo";
  68951. $expected = "<myTag xmlns=\"foo\">";
  68952. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace));
  68953. }
  68954. /**
  68955. * @covers XML_Util::createStartElement()
  68956. */
  68957. public function testCreateStartElementForTagWithAttributesAndNamespaceWithMultiline()
  68958. {
  68959. $originalTag = "myNs:myTag";
  68960. $originalAttributes = array("foo" => "bar");
  68961. $originalNamespace = "http://www.w3c.org/myNs#";
  68962. $expected =
  68963. <<< EOF
  68964. <myNs:myTag foo="bar"
  68965. xmlns:myNs="http://www.w3c.org/myNs#">
  68966. EOF;
  68967. $multiline = true;
  68968. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace, $multiline));
  68969. }
  68970. /**
  68971. * @covers XML_Util::createStartElement()
  68972. */
  68973. public function testCreateStartElementForTagWithAttributesAndNamespaceWithMultilineAndIndent()
  68974. {
  68975. $originalTag = "myNs:myTag";
  68976. $originalAttributes = array("foo" => "bar");
  68977. $originalNamespace = "http://www.w3c.org/myNs#";
  68978. $expected =
  68979. <<< EOF
  68980. <myNs:myTag foo="bar"
  68981. xmlns:myNs="http://www.w3c.org/myNs#">
  68982. EOF;
  68983. $multiline = true;
  68984. $indent = " ";
  68985. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace, $multiline, $indent));
  68986. }
  68987. /**
  68988. * @covers XML_Util::createStartElement()
  68989. */
  68990. public function testCreateStartElementForTagWithAttributesAndNamespaceWithMultilineAndIndentAndLinebreak()
  68991. {
  68992. $originalTag = "myNs:myTag";
  68993. $originalAttributes = array("foo" => "bar");
  68994. $originalNamespace = "http://www.w3c.org/myNs#";
  68995. $expected = "<myNs:myTag foo=\"bar\"^ xmlns:myNs=\"http://www.w3c.org/myNs#\">";
  68996. $multiline = true;
  68997. $indent = " ";
  68998. $linebreak = "^";
  68999. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace, $multiline, $indent, $linebreak));
  69000. }
  69001. /**
  69002. * @covers XML_Util::createStartElement()
  69003. */
  69004. public function testCreateStartElementForTagWithAttributesAndNamespaceWithMultilineAndIndentAndLinebreakAndSortAttributesIsTrue()
  69005. {
  69006. $originalTag = "myNs:myTag";
  69007. $originalAttributes = array("foo" => "bar", "boo" => "baz");
  69008. $originalNamespace = "http://www.w3c.org/myNs#";
  69009. $expected = "<myNs:myTag boo=\"baz\"^ foo=\"bar\"^ xmlns:myNs=\"http://www.w3c.org/myNs#\">";
  69010. $multiline = true;
  69011. $indent = " ";
  69012. $linebreak = "^";
  69013. $sortAttributes = true;
  69014. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace, $multiline, $indent, $linebreak, $sortAttributes));
  69015. }
  69016. /**
  69017. * @covers XML_Util::createStartElement()
  69018. */
  69019. public function testCreateStartElementForTagWithAttributesAndNamespaceWithMultilineAndIndentAndLinebreakAndSortAttributesIsFalse()
  69020. {
  69021. $originalTag = "myNs:myTag";
  69022. $originalAttributes = array("foo" => "bar", "boo" => "baz");
  69023. $originalNamespace = "http://www.w3c.org/myNs#";
  69024. $expected = "<myNs:myTag foo=\"bar\"^ boo=\"baz\"^ xmlns:myNs=\"http://www.w3c.org/myNs#\">";
  69025. $multiline = true;
  69026. $indent = " ";
  69027. $linebreak = "^";
  69028. $sortAttributes = false;
  69029. $this->assertEquals($expected, XML_Util::createStartElement($originalTag, $originalAttributes, $originalNamespace, $multiline, $indent, $linebreak, $sortAttributes));
  69030. }
  69031. }
  69032. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CreateTagTests.php�������������������������������������������������������������0000644�0001750�0000144�00000017452�13125000640�017262 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69033. class CreateTagTests extends AbstractUnitTests
  69034. {
  69035. /**
  69036. * @covers XML_Util::createTag()
  69037. */
  69038. public function testCreateTagForTagWithAttributes()
  69039. {
  69040. $originalTag = "myNs:myTag";
  69041. $originalAttributes = array("foo" => "bar");
  69042. $expected = "<myNs:myTag foo=\"bar\" />";
  69043. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes));
  69044. }
  69045. /**
  69046. * @covers XML_Util::createTag()
  69047. */
  69048. public function testCreateTagForTagWithAttributesAndContent()
  69049. {
  69050. $originalTag = "myNs:myTag";
  69051. $originalAttributes = array("foo" => "bar");
  69052. $originalContent = "This is inside the tag";
  69053. $expected = "<myNs:myTag foo=\"bar\">This is inside the tag</myNs:myTag>";
  69054. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent));
  69055. }
  69056. /**
  69057. * @covers XML_Util::createTag()
  69058. */
  69059. public function testCreateTagForTagWithAttributesAndContentAndNamespace()
  69060. {
  69061. $originalTag = "myNs:myTag";
  69062. $originalAttributes = array("foo" => "bar");
  69063. $originalContent = "This is inside the tag";
  69064. $originalNamespace = "http://www.w3c.org/myNs#";
  69065. $expected = "<myNs:myTag foo=\"bar\" xmlns:myNs=\"http://www.w3c.org/myNs#\">This is inside the tag</myNs:myTag>";
  69066. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace));
  69067. }
  69068. /**
  69069. * @covers XML_Util::createTag()
  69070. */
  69071. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithCDataSection()
  69072. {
  69073. $originalTag = "myNs:myTag";
  69074. $originalAttributes = array("foo" => "bar");
  69075. $originalContent = "This is inside the tag and has < & @ > in it";
  69076. $originalNamespace = "http://www.w3c.org/myNs#";
  69077. $expected = "<myNs:myTag foo=\"bar\" xmlns:myNs=\"http://www.w3c.org/myNs#\"><![CDATA[This is inside the tag and has < & @ > in it]]></myNs:myTag>";
  69078. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_CDATA_SECTION));
  69079. }
  69080. /**
  69081. * @covers XML_Util::createTag()
  69082. */
  69083. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntities()
  69084. {
  69085. $originalTag = "myNs:myTag";
  69086. $originalAttributes = array("foo" => "bar");
  69087. $originalContent = "This is inside the tag and has < & @ > in it";
  69088. $originalNamespace = "http://www.w3c.org/myNs#";
  69089. $expected = "<myNs:myTag foo=\"bar\" xmlns:myNs=\"http://www.w3c.org/myNs#\">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>";
  69090. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES));
  69091. }
  69092. /**
  69093. * @covers XML_Util::createTag()
  69094. */
  69095. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntitiesAndMultilineFalse()
  69096. {
  69097. $originalTag = "myNs:myTag";
  69098. $originalAttributes = array("foo" => "bar");
  69099. $originalContent = "This is inside the tag and has < & @ > in it";
  69100. $originalNamespace = "http://www.w3c.org/myNs#";
  69101. $multiline = false;
  69102. $expected = "<myNs:myTag foo=\"bar\" xmlns:myNs=\"http://www.w3c.org/myNs#\">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>";
  69103. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES, $multiline));
  69104. }
  69105. /**
  69106. * @covers XML_Util::createTag()
  69107. */
  69108. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntitiesAndMultilineTrue()
  69109. {
  69110. $originalTag = "myNs:myTag";
  69111. $originalAttributes = array("foo" => "bar");
  69112. $originalContent = "This is inside the tag and has < & @ > in it";
  69113. $originalNamespace = "http://www.w3c.org/myNs#";
  69114. $multiline = true;
  69115. $expected =
  69116. <<< EOF
  69117. <myNs:myTag foo="bar"
  69118. xmlns:myNs="http://www.w3c.org/myNs#">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>
  69119. EOF;
  69120. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES, $multiline));
  69121. }
  69122. /**
  69123. * @covers XML_Util::createTag()
  69124. */
  69125. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntitiesAndMultilineTrueAndIndent()
  69126. {
  69127. $originalTag = "myNs:myTag";
  69128. $originalAttributes = array("foo" => "bar");
  69129. $originalContent = "This is inside the tag and has < & @ > in it";
  69130. $originalNamespace = "http://www.w3c.org/myNs#";
  69131. $multiline = true;
  69132. $indent = " ";
  69133. $expected =
  69134. <<< EOF
  69135. <myNs:myTag foo="bar"
  69136. xmlns:myNs="http://www.w3c.org/myNs#">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>
  69137. EOF;
  69138. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent));
  69139. }
  69140. /**
  69141. * @covers XML_Util::createTag()
  69142. */
  69143. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntitiesAndMultilineTrueAndIndentAndLinebreak()
  69144. {
  69145. $originalTag = "myNs:myTag";
  69146. $originalAttributes = array("foo" => "bar");
  69147. $originalContent = "This is inside the tag and has < & @ > in it";
  69148. $originalNamespace = "http://www.w3c.org/myNs#";
  69149. $multiline = true;
  69150. $indent = " ";
  69151. $linebreak = "^";
  69152. $expected = "<myNs:myTag foo=\"bar\"^ xmlns:myNs=\"http://www.w3c.org/myNs#\">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>";
  69153. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent, $linebreak));
  69154. }
  69155. /**
  69156. * @covers XML_Util::createTag()
  69157. */
  69158. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntitiesAndMultilineTrueAndIndentAndLinebreakAndSortAttributesTrue()
  69159. {
  69160. $originalTag = "myNs:myTag";
  69161. $originalAttributes = array("foo" => "bar", "boo" => "baz");
  69162. $originalContent = "This is inside the tag and has < & @ > in it";
  69163. $originalNamespace = "http://www.w3c.org/myNs#";
  69164. $multiline = true;
  69165. $indent = " ";
  69166. $linebreak = "^";
  69167. $sortAttributes = true;
  69168. $expected = "<myNs:myTag boo=\"baz\"^ foo=\"bar\"^ xmlns:myNs=\"http://www.w3c.org/myNs#\">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>";
  69169. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent, $linebreak, $sortAttributes));
  69170. }
  69171. /**
  69172. * @covers XML_Util::createTag()
  69173. */
  69174. public function testCreateTagForTagWithAttributesAndContentAndNamespaceWithReplaceEntitiesAndMultilineTrueAndIndentAndLinebreakAndSortAttributesFalse()
  69175. {
  69176. $originalTag = "myNs:myTag";
  69177. $originalAttributes = array("foo" => "bar", "boo" => "baz");
  69178. $originalContent = "This is inside the tag and has < & @ > in it";
  69179. $originalNamespace = "http://www.w3c.org/myNs#";
  69180. $multiline = true;
  69181. $indent = " ";
  69182. $linebreak = "^";
  69183. $sortAttributes = false;
  69184. $expected = "<myNs:myTag foo=\"bar\"^ boo=\"baz\"^ xmlns:myNs=\"http://www.w3c.org/myNs#\">This is inside the tag and has &lt; &amp; @ &gt; in it</myNs:myTag>";
  69185. $this->assertEquals($expected, XML_Util::createTag($originalTag, $originalAttributes, $originalContent, $originalNamespace, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent, $linebreak, $sortAttributes));
  69186. }
  69187. }
  69188. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/CreateTagFromArrayTests.php����������������������������������������������������0000644�0001750�0000144�00000032264�13125000640�021103 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69189. class CreateTagFromArrayTests extends AbstractUnitTests
  69190. {
  69191. /**
  69192. * @covers XML_Util::createTagFromArray()
  69193. */
  69194. public function testCreateTagFromArrayWithQname()
  69195. {
  69196. $original = array(
  69197. "qname" => "foo:bar",
  69198. );
  69199. $expected = "<foo:bar />";
  69200. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69201. }
  69202. /**
  69203. * @covers XML_Util::createTagFromArray()
  69204. */
  69205. public function testCreateTagFromArrayWithQnameAndNamespace()
  69206. {
  69207. $original = array(
  69208. "qname" => "foo:bar",
  69209. "namespaceUri" => "http://foo.com",
  69210. );
  69211. $expected = "<foo:bar xmlns:foo=\"http://foo.com\" />";
  69212. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69213. }
  69214. /**
  69215. * @covers XML_Util::createTagFromArray()
  69216. */
  69217. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributes()
  69218. {
  69219. $original = array(
  69220. "qname" => "foo:bar",
  69221. "namespaceUri" => "http://foo.com",
  69222. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69223. );
  69224. $expected = "<foo:bar argh=\"fruit&amp;vegetable\" key=\"value\" xmlns:foo=\"http://foo.com\" />";
  69225. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69226. }
  69227. /**
  69228. * @covers XML_Util::createTagFromArray()
  69229. */
  69230. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContent()
  69231. {
  69232. $original = array(
  69233. "qname" => "foo:bar",
  69234. "namespaceUri" => "http://foo.com",
  69235. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69236. "content" => "I'm inside the tag",
  69237. );
  69238. $expected = "<foo:bar argh=\"fruit&amp;vegetable\" key=\"value\" xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69239. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69240. }
  69241. /**
  69242. * @covers XML_Util::createTagFromArray()
  69243. */
  69244. public function testCreateTagFromArrayWithQnameAndAttributesAndContent()
  69245. {
  69246. $original = array(
  69247. "qname" => "foo:bar",
  69248. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69249. "content" => "I'm inside the tag",
  69250. );
  69251. $expected = "<foo:bar argh=\"fruit&amp;vegetable\" key=\"value\">I&apos;m inside the tag</foo:bar>";
  69252. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69253. }
  69254. /**
  69255. * @covers XML_Util::createTagFromArray()
  69256. */
  69257. public function testCreateTagFromArrayWithQnameAndNamespaceAndContent()
  69258. {
  69259. $original = array(
  69260. "qname" => "foo:bar",
  69261. "namespaceUri" => "http://foo.com",
  69262. "content" => "I'm inside the tag",
  69263. );
  69264. $expected = "<foo:bar xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69265. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69266. }
  69267. /**
  69268. * @covers XML_Util::createTagFromArray()
  69269. */
  69270. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithEntitiesNone()
  69271. {
  69272. $original = array(
  69273. "qname" => "foo:bar",
  69274. "namespaceUri" => "http://foo.com",
  69275. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69276. "content" => "I'm inside the tag",
  69277. );
  69278. $expected = "<foo:bar argh=\"fruit&amp;vegetable\" key=\"value\" xmlns:foo=\"http://foo.com\">I'm inside the tag</foo:bar>";
  69279. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_ENTITIES_NONE));
  69280. }
  69281. /**
  69282. * @covers XML_Util::createTagFromArray()
  69283. */
  69284. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntities()
  69285. {
  69286. $original = array(
  69287. "qname" => "foo:bar",
  69288. "namespaceUri" => "http://foo.com",
  69289. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69290. "content" => "I'm inside the tag",
  69291. );
  69292. $expected = "<foo:bar argh=\"fruit&amp;vegetable\" key=\"value\" xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69293. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES));
  69294. }
  69295. /**
  69296. * @covers XML_Util::createTagFromArray()
  69297. */
  69298. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntitiesAndMultilineFalse()
  69299. {
  69300. $original = array(
  69301. "qname" => "foo:bar",
  69302. "namespaceUri" => "http://foo.com",
  69303. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69304. "content" => "I'm inside the tag",
  69305. );
  69306. $multiline = false;
  69307. $expected = "<foo:bar argh=\"fruit&amp;vegetable\" key=\"value\" xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69308. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES, $multiline));
  69309. }
  69310. /**
  69311. * @covers XML_Util::createTagFromArray()
  69312. */
  69313. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntitiesAndMultilineTrue()
  69314. {
  69315. $original = array(
  69316. "qname" => "foo:bar",
  69317. "namespaceUri" => "http://foo.com",
  69318. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69319. "content" => "I'm inside the tag",
  69320. );
  69321. $multiline = true;
  69322. $expected =
  69323. <<< EOF
  69324. <foo:bar argh="fruit&amp;vegetable"
  69325. key="value"
  69326. xmlns:foo="http://foo.com">I&apos;m inside the tag</foo:bar>
  69327. EOF;
  69328. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES, $multiline));
  69329. }
  69330. /**
  69331. * @covers XML_Util::createTagFromArray()
  69332. */
  69333. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntitiesAndMultilineTrueAndIndent()
  69334. {
  69335. $original = array(
  69336. "qname" => "foo:bar",
  69337. "namespaceUri" => "http://foo.com",
  69338. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69339. "content" => "I'm inside the tag",
  69340. );
  69341. $multiline = true;
  69342. $indent = " ";
  69343. $expected =
  69344. <<< EOF
  69345. <foo:bar argh="fruit&amp;vegetable"
  69346. key="value"
  69347. xmlns:foo="http://foo.com">I&apos;m inside the tag</foo:bar>
  69348. EOF;
  69349. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent));
  69350. }
  69351. /**
  69352. * @covers XML_Util::createTagFromArray()
  69353. */
  69354. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntitiesAndMultilineTrueAndIndentAndLinebreak()
  69355. {
  69356. $original = array(
  69357. "qname" => "foo:bar",
  69358. "namespaceUri" => "http://foo.com",
  69359. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69360. "content" => "I'm inside the tag",
  69361. );
  69362. $multiline = true;
  69363. $indent = " ";
  69364. $linebreak = "^";
  69365. $expected = "<foo:bar argh=\"fruit&amp;vegetable\"^ key=\"value\"^ xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69366. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent, $linebreak));
  69367. }
  69368. /**
  69369. * @covers XML_Util::createTagFromArray()
  69370. */
  69371. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntitiesAndMultilineTrueAndIndentAndLinebreakAndSortAttributesTrue()
  69372. {
  69373. $original = array(
  69374. "qname" => "foo:bar",
  69375. "namespaceUri" => "http://foo.com",
  69376. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69377. "content" => "I'm inside the tag",
  69378. );
  69379. $multiline = true;
  69380. $indent = " ";
  69381. $linebreak = "^";
  69382. $sortAttributes = true;
  69383. $expected = "<foo:bar argh=\"fruit&amp;vegetable\"^ key=\"value\"^ xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69384. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent, $linebreak, $sortAttributes));
  69385. }
  69386. /**
  69387. * @covers XML_Util::createTagFromArray()
  69388. */
  69389. public function testCreateTagFromArrayWithQnameAndNamespaceAndAttributesAndContentWithReplaceEntitiesAndMultilineTrueAndIndentAndLinebreakAndSortAttributesFalse()
  69390. {
  69391. $original = array(
  69392. "qname" => "foo:bar",
  69393. "namespaceUri" => "http://foo.com",
  69394. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69395. "content" => "I'm inside the tag",
  69396. );
  69397. $multiline = true;
  69398. $indent = " ";
  69399. $linebreak = "^";
  69400. $sortAttributes = false;
  69401. $expected = "<foo:bar key=\"value\"^ argh=\"fruit&amp;vegetable\"^ xmlns:foo=\"http://foo.com\">I&apos;m inside the tag</foo:bar>";
  69402. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_REPLACE_ENTITIES, $multiline, $indent, $linebreak, $sortAttributes));
  69403. }
  69404. /**
  69405. * @covers XML_Util::createTagFromArray()
  69406. */
  69407. public function testCreateTagFromArrayWithInvalidArray()
  69408. {
  69409. $badArray = array(
  69410. "foo" => "bar",
  69411. );
  69412. $expectedError = "You must either supply a qualified name (qname) or local tag name (localPart).";
  69413. $this->assertEquals($expectedError, XML_Util::createTagFromArray($badArray));
  69414. }
  69415. /**
  69416. * @covers XML_Util::createTagFromArray()
  69417. */
  69418. public function testCreateTagFromArrayWithNamespaceAndAttributesAndContentButWithoutQname()
  69419. {
  69420. $original = array(
  69421. "namespaceUri" => "http://foo.com",
  69422. "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  69423. "content" => "I'm inside the tag",
  69424. );
  69425. $expectedError = "You must either supply a qualified name (qname) or local tag name (localPart).";
  69426. $this->assertEquals($expectedError, XML_Util::createTagFromArray($original));
  69427. }
  69428. /**
  69429. * @covers XML_Util::createTagFromArray()
  69430. */
  69431. public function testCreateTagFromArrayWithNonScalarContent()
  69432. {
  69433. $badArray = array(
  69434. 'content' => array('foo', 'bar'),
  69435. );
  69436. $expectedError = "Supplied non-scalar value as tag content";
  69437. $this->assertEquals($expectedError, XML_Util::createTagFromArray($badArray));
  69438. }
  69439. /**
  69440. * @covers XML_Util::createTagFromArray()
  69441. */
  69442. public function testCreateTagFromArrayWithArrayOfNamespaces()
  69443. {
  69444. $original = array(
  69445. 'qname' => 'foo:bar',
  69446. 'namespaces' => array('ns1' => 'uri1', 'ns2' => 'uri2'),
  69447. );
  69448. $expected = "<foo:bar xmlns:ns1=\"uri1\" xmlns:ns2=\"uri2\" />";
  69449. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69450. }
  69451. /**
  69452. * @covers XML_Util::createTagFromArray()
  69453. */
  69454. public function testCreateTagFromArrayWithQnameDerivedFromNamespaceUriAndLocalPart()
  69455. {
  69456. $original = array(
  69457. 'namespaceUri' => 'http://bar.org',
  69458. 'localPart' => 'foo'
  69459. );
  69460. $expected = "<foo xmlns=\"http://bar.org\" />";
  69461. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69462. }
  69463. /**
  69464. * @covers XML_Util::createTagFromArray()
  69465. */
  69466. public function testCreateTagFromArrayWithQnameDerivedFromNamespaceAndLocalPart()
  69467. {
  69468. $original = array(
  69469. 'namespace' => 'http://foo.org',
  69470. 'localPart' => 'bar'
  69471. );
  69472. $expected = "<http://foo.org:bar />";
  69473. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69474. }
  69475. /**
  69476. * @covers XML_Util::createTagFromArray()
  69477. */
  69478. public function testCreateTagFromArrayWithQnameDerivedFromLocalPart()
  69479. {
  69480. $original = array(
  69481. 'namespace' => '',
  69482. 'localPart' => 'bar'
  69483. );
  69484. $expected = "<bar />";
  69485. $this->assertEquals($expected, XML_Util::createTagFromArray($original));
  69486. }
  69487. /**
  69488. * @covers XML_Util::createTagFromArray()
  69489. */
  69490. public function testCreateTagFromArrayWithImplicitlyEmptyContentAndCollapseNoneDoesNotCollapseTag()
  69491. {
  69492. $original = array('qname' => 'tag1');
  69493. $expected = "<tag1></tag1>";
  69494. $actual = XML_Util::createTagFromArray(
  69495. $original,
  69496. XML_UTIL_REPLACE_ENTITIES, // default $replaceEntities
  69497. false, // default $multiline
  69498. '_auto', // default $indent
  69499. "\n", // default $linebreak
  69500. true, // default $sortAttributes
  69501. XML_UTIL_COLLAPSE_NONE
  69502. );
  69503. $this->assertEquals($expected, $actual);
  69504. }
  69505. /**
  69506. * @covers XML_Util::createTagFromArray()
  69507. */
  69508. public function testCreateTagFromArrayForCdataWithExplicitlyEmptyContentDoesNotCollapseTag()
  69509. {
  69510. $original = array('qname' => 'tag1', 'content' => '');
  69511. $expected = "<tag1><![CDATA[]]></tag1>";
  69512. $this->assertEquals($expected, XML_Util::createTagFromArray($original, XML_UTIL_CDATA_SECTION));
  69513. }
  69514. }
  69515. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/GetDocTypeDeclarationTests.php�������������������������������������������������0000644�0001750�0000144�00000003363�13125000640�021574 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69516. class GetDocTypeDeclarationTests extends AbstractUnitTests
  69517. {
  69518. /**
  69519. * @covers XML_Util::getDocTypeDeclaration()
  69520. */
  69521. public function testGetDocTypeDeclarationUsingRoot()
  69522. {
  69523. $expected = "<!DOCTYPE rootTag>";
  69524. $this->assertEquals($expected, XML_Util::getDocTypeDeclaration("rootTag"));
  69525. }
  69526. /**
  69527. * @covers XML_Util::getDocTypeDeclaration()
  69528. */
  69529. public function testGetDocTypeDeclarationUsingRootAndStringUri()
  69530. {
  69531. $expected = "<!DOCTYPE rootTag SYSTEM \"myDocType.dtd\">";
  69532. $this->assertEquals($expected, XML_Util::getDocTypeDeclaration("rootTag", "myDocType.dtd"));
  69533. }
  69534. /**
  69535. * @covers XML_Util::getDocTypeDeclaration()
  69536. */
  69537. public function testGetDocTypeDeclarationUsingRootAndArrayUri()
  69538. {
  69539. $uri = array(
  69540. 'uri' => 'http://pear.php.net/dtd/package-1.0',
  69541. 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1'
  69542. );
  69543. $expected = "<!DOCTYPE rootTag PUBLIC \"-//PHP//PEAR/DTD PACKAGE 0.1\" \"http://pear.php.net/dtd/package-1.0\">";
  69544. $this->assertEquals($expected, XML_Util::getDocTypeDeclaration("rootTag", $uri));
  69545. }
  69546. /**
  69547. * @covers XML_Util::getDocTypeDeclaration()
  69548. */
  69549. public function testGetDocTypeDeclarationUsingRootAndArrayUriAndInternalDtd()
  69550. {
  69551. $uri = array(
  69552. 'uri' => 'http://pear.php.net/dtd/package-1.0',
  69553. 'id' => '-//PHP//PEAR/DTD PACKAGE 0.1'
  69554. );
  69555. $dtdEntry = '<!ELEMENT additionalInfo (#PCDATA)>';
  69556. $expected =
  69557. <<< EOF
  69558. <!DOCTYPE rootTag PUBLIC "-//PHP//PEAR/DTD PACKAGE 0.1" "http://pear.php.net/dtd/package-1.0" [
  69559. <!ELEMENT additionalInfo (#PCDATA)>
  69560. ]>
  69561. EOF;
  69562. $this->assertEquals($expected, XML_Util::getDocTypeDeclaration("rootTag", $uri, $dtdEntry));
  69563. }
  69564. }
  69565. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/GetXmlDeclarationTests.php�����������������������������������������������������0000644�0001750�0000144�00000002214�13125000640�020757 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69566. class GetXMLDeclarationTests extends AbstractUnitTests
  69567. {
  69568. /**
  69569. * @covers XML_Util::getXMLDeclaration()
  69570. */
  69571. public function testGetXMLDeclarationUsingVersion()
  69572. {
  69573. $version = "1.0";
  69574. $expected = "<?xml version=\"1.0\"?>";
  69575. $this->assertEquals($expected, XML_Util::getXMLDeclaration($version));
  69576. }
  69577. /**
  69578. * @covers XML_Util::getXMLDeclaration()
  69579. */
  69580. public function testGetXMLDeclarationUsingVersionAndEncodingAndStandalone()
  69581. {
  69582. $version = "1.0";
  69583. $encoding = "UTF-8";
  69584. $standalone = true;
  69585. $expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
  69586. $this->assertEquals($expected, XML_Util::getXMLDeclaration($version, $encoding, $standalone));
  69587. }
  69588. /**
  69589. * @covers XML_Util::getXMLDeclaration()
  69590. */
  69591. public function testGetXMLDeclarationUsingVersionAndStandalone()
  69592. {
  69593. $version = "1.0";
  69594. $encoding = null;
  69595. $standalone = true;
  69596. $expected = "<?xml version=\"1.0\" standalone=\"yes\"?>";
  69597. $this->assertEquals($expected, XML_Util::getXMLDeclaration($version, $encoding, $standalone));
  69598. }
  69599. }
  69600. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/IsValidNameTests.php�����������������������������������������������������������0000644�0001750�0000144�00000002256�13125000640�017553 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69601. class IsValidNameTests extends AbstractUnitTests
  69602. {
  69603. /**
  69604. * @covers XML_Util::isValidName()
  69605. */
  69606. public function testIsValidNameForTagNameThatIsValid()
  69607. {
  69608. $tagName = "alpha-x_y_z.123";
  69609. $result = XML_Util::isValidName($tagName);
  69610. $this->assertTrue($result);
  69611. }
  69612. /**
  69613. * @covers XML_Util::isValidName()
  69614. */
  69615. public function testIsValidNameForTagNameWithInvalidCharacter()
  69616. {
  69617. $tagName = "invalidTag?";
  69618. $result = XML_Util::isValidName($tagName);
  69619. $this->assertInstanceOf('PEAR_Error', $result);
  69620. $expectedError = "XML names may only contain alphanumeric chars, period, hyphen, colon and underscores";
  69621. $this->assertEquals($expectedError, $result->getMessage());
  69622. }
  69623. /**
  69624. * @covers XML_Util::isValidName()
  69625. */
  69626. public function testIsValidNameForTagNameWithInvalidStartingCharacter()
  69627. {
  69628. $tagName = "1234five";
  69629. $result = XML_Util::isValidName($tagName);
  69630. $this->assertInstanceOf('PEAR_Error', $result);
  69631. $expectedError = "XML names may only start with letter or underscore";
  69632. $this->assertEquals($expectedError, $result->getMessage());
  69633. }
  69634. }
  69635. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/RaiseErrorTests.php������������������������������������������������������������0000644�0001750�0000144�00000000700�13125000640�017464 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69636. class RaiseErrorTests extends AbstractUnitTests
  69637. {
  69638. /**
  69639. * @covers XML_Util::raiseError()
  69640. */
  69641. public function testRaiseError()
  69642. {
  69643. $code = 12345;
  69644. $message = "I am an error";
  69645. $error = XML_Util::raiseError($message, $code);
  69646. $this->assertInstanceOf('PEAR_Error', $error);
  69647. $this->assertEquals($message, $error->getMessage());
  69648. $this->assertEquals($code, $error->getCode());
  69649. }
  69650. }
  69651. ����������������������������������������������������������������XML_Util-1.4.3/tests/ReplaceEntitiesTests.php�������������������������������������������������������0000644�0001750�0000144�00000010341�13125000640�020471 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69652. class ReplaceEntitiesTests extends AbstractUnitTests
  69653. {
  69654. protected function getSimpleData()
  69655. {
  69656. return 'This string contains < & >.';
  69657. }
  69658. protected function getUtf8Data()
  69659. {
  69660. return 'This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê';
  69661. }
  69662. /**
  69663. * @covers XML_Util::replaceEntities()
  69664. */
  69665. public function testReplaceEntitiesForSimpleData()
  69666. {
  69667. $expected = "This string contains &lt; &amp; &gt;.";
  69668. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData()));
  69669. }
  69670. /**
  69671. * @covers XML_Util::replaceEntities()
  69672. */
  69673. public function testReplaceEntitiesForSimpleDataWithInvalidOptionReturnsOriginalData()
  69674. {
  69675. $expected = "This string contains < & >.";
  69676. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), 'INVALID_OPTION'));
  69677. }
  69678. /**
  69679. * @covers XML_Util::replaceEntities()
  69680. */
  69681. public function testReplaceEntitiesForSimpleDataWithEntitiesXml()
  69682. {
  69683. $expected = "This string contains &lt; &amp; &gt;.";
  69684. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML));
  69685. }
  69686. /**
  69687. * @covers XML_Util::replaceEntities()
  69688. */
  69689. public function testReplaceEntitiesForSimpleDataWithEntitiesXmlAndEncoding()
  69690. {
  69691. $encoding = "UTF-8";
  69692. $expected = "This string contains &lt; &amp; &gt;.";
  69693. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML, $encoding));
  69694. }
  69695. /**
  69696. * @covers XML_Util::replaceEntities()
  69697. */
  69698. public function testReplaceEntitiesForUtf8DataWithEntitiesXmlAndEncoding()
  69699. {
  69700. $encoding = "UTF-8";
  69701. $expected = "This data contains special chars like &lt;, &gt;, &amp; and &quot; as well as ä, ö, ß, à and ê";
  69702. $this->assertEquals($expected, XML_Util::replaceEntities($this->getUtf8Data(), XML_UTIL_ENTITIES_XML, $encoding));
  69703. }
  69704. /**
  69705. * @covers XML_Util::replaceEntities()
  69706. */
  69707. public function testReplaceEntitiesForSimpleDataWithEntitiesXmlRequired()
  69708. {
  69709. $expected = "This string contains &lt; &amp; >.";
  69710. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML_REQUIRED));
  69711. }
  69712. /**
  69713. * @covers XML_Util::replaceEntities()
  69714. */
  69715. public function testReplaceEntitiesForSimpleDataWithEntitiesXmlRequiredAndEncoding()
  69716. {
  69717. $encoding = "UTF-8";
  69718. $expected = "This string contains &lt; &amp; >.";
  69719. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML_REQUIRED, $encoding));
  69720. }
  69721. /**
  69722. * @covers XML_Util::replaceEntities()
  69723. */
  69724. public function testReplaceEntitiesForUtf8DataWithEntitiesXmlRequiredAndEncoding()
  69725. {
  69726. $encoding = "UTF-8";
  69727. $expected = "This data contains special chars like &lt;, >, &amp; and &quot; as well as ä, ö, ß, à and ê";
  69728. $this->assertEquals($expected, XML_Util::replaceEntities($this->getUtf8Data(), XML_UTIL_ENTITIES_XML_REQUIRED, $encoding));
  69729. }
  69730. /**
  69731. * @covers XML_Util::replaceEntities()
  69732. */
  69733. public function testReplaceEntitiesForSimpleDataWithEntitiesHtml()
  69734. {
  69735. $expected = "This string contains &lt; &amp; &gt;.";
  69736. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), XML_UTIL_ENTITIES_HTML));
  69737. }
  69738. /**
  69739. * @covers XML_Util::replaceEntities()
  69740. */
  69741. public function testReplaceEntitiesForSimpleDataWithEntitiesHtmlAndEncoding()
  69742. {
  69743. $encoding = "UTF-8";
  69744. $expected = "This string contains &lt; &amp; &gt;.";
  69745. $this->assertEquals($expected, XML_Util::replaceEntities($this->getSimpleData(), XML_UTIL_ENTITIES_HTML, $encoding));
  69746. }
  69747. /**
  69748. * @covers XML_Util::replaceEntities()
  69749. */
  69750. public function testReplaceEntitiesForUtf8DataWithEntitiesHtmlAndEncoding()
  69751. {
  69752. $encoding = "UTF-8";
  69753. $expected = "This data contains special chars like &lt;, &gt;, &amp; and &quot; as well as &auml;, &ouml;, &szlig;, &agrave; and &ecirc;";
  69754. $this->assertEquals($expected, XML_Util::replaceEntities($this->getUtf8Data(), XML_UTIL_ENTITIES_HTML, $encoding));
  69755. }
  69756. }
  69757. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/ReverseEntitiesTests.php�������������������������������������������������������0000644�0001750�0000144�00000010326�13125000640�020534 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69758. class ReverseEntitiesTests extends AbstractUnitTests
  69759. {
  69760. protected function getSimpleData()
  69761. {
  69762. return 'This string contains &lt; &amp; &gt;.';
  69763. }
  69764. protected function getUtf8Data()
  69765. {
  69766. return 'This data contains special chars like &lt;, &gt;, &amp; and &quot; as well as &auml;, &ouml;, &szlig;, &agrave; and &ecirc;';
  69767. }
  69768. /**
  69769. * @covers XML_Util::reverseEntities()
  69770. */
  69771. public function testReverseEntitiesForSimpleData()
  69772. {
  69773. $expected = "This string contains < & >.";
  69774. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData()));
  69775. }
  69776. /**
  69777. * @covers XML_Util::reverseEntities()
  69778. */
  69779. public function testReverseEntitiesForSimpleDataWithInvalidOptionReturnsOriginalData()
  69780. {
  69781. $expected = "This string contains &lt; &amp; &gt;.";
  69782. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), 'INVALID_OPTION'));
  69783. }
  69784. /**
  69785. * @covers XML_Util::reverseEntities()
  69786. */
  69787. public function testReverseEntitiesForSimpleDataWithEntitiesXml()
  69788. {
  69789. $expected = "This string contains < & >.";
  69790. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML));
  69791. }
  69792. /**
  69793. * @covers XML_Util::reverseEntities()
  69794. */
  69795. public function testReverseEntitiesForSimpleDataWithEntitiesXmlAndEncoding()
  69796. {
  69797. $encoding = "UTF-8";
  69798. $expected = "This string contains < & >.";
  69799. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML), $encoding);
  69800. }
  69801. /**
  69802. * @covers XML_Util::reverseEntities()
  69803. */
  69804. public function testReverseEntitiesForUtf8DataWithEntitiesXmlAndEncoding()
  69805. {
  69806. $encoding = "UTF-8";
  69807. $expected = "This data contains special chars like <, >, & and \" as well as &auml;, &ouml;, &szlig;, &agrave; and &ecirc;";
  69808. $this->assertEquals($expected, XML_Util::reverseEntities($this->getUtf8Data(), XML_UTIL_ENTITIES_XML), $encoding);
  69809. }
  69810. /**
  69811. * @covers XML_Util::reverseEntities()
  69812. */
  69813. public function testReverseEntitiesForSimpleDataWithEntitiesXmlRequired()
  69814. {
  69815. $expected = "This string contains < & &gt;.";
  69816. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML_REQUIRED));
  69817. }
  69818. /**
  69819. * @covers XML_Util::reverseEntities()
  69820. */
  69821. public function testReverseEntitiesForSimpleDataWithEntitiesXmlRequiredAndEncoding()
  69822. {
  69823. $encoding = "UTF-8";
  69824. $expected = "This string contains < & &gt;.";
  69825. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), XML_UTIL_ENTITIES_XML_REQUIRED, $encoding));
  69826. }
  69827. /**
  69828. * @covers XML_Util::reverseEntities()
  69829. */
  69830. public function testReverseEntitiesForUtf8DataWithEntitiesXmlRequiredAndEncoding()
  69831. {
  69832. $encoding = "UTF-8";
  69833. $expected = "This data contains special chars like <, &gt;, & and \" as well as &auml;, &ouml;, &szlig;, &agrave; and &ecirc;";
  69834. $this->assertEquals($expected, XML_Util::reverseEntities($this->getUtf8Data(), XML_UTIL_ENTITIES_XML_REQUIRED, $encoding));
  69835. }
  69836. /**
  69837. * @covers XML_Util::reverseEntities()
  69838. */
  69839. public function testReverseEntitiesForSimpleDataWithEntitiesHtml()
  69840. {
  69841. $expected = "This string contains < & >.";
  69842. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), XML_UTIL_ENTITIES_HTML));
  69843. }
  69844. /**
  69845. * @covers XML_Util::reverseEntities()
  69846. */
  69847. public function testReverseEntitiesForSimpleDataWithEntitiesHtmlAndEncoding()
  69848. {
  69849. $encoding = "UTF-8";
  69850. $expected = "This string contains < & >.";
  69851. $this->assertEquals($expected, XML_Util::reverseEntities($this->getSimpleData(), XML_UTIL_ENTITIES_HTML, $encoding));
  69852. }
  69853. /**
  69854. * @covers XML_Util::reverseEntities()
  69855. */
  69856. public function testReverseEntitiesForUtf8DataWithEntitiesHtmlAndEncoding()
  69857. {
  69858. $encoding = "UTF-8";
  69859. $expected = "This data contains special chars like <, >, & and \" as well as ä, ö, ß, à and ê";
  69860. $this->assertEquals($expected, XML_Util::reverseEntities($this->getUtf8Data(), XML_UTIL_ENTITIES_HTML, $encoding));
  69861. }
  69862. }
  69863. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/SplitQualifiedNameTests.php����������������������������������������������������0000644�0001750�0000144�00000001507�13125000640�021135 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69864. class SplitQualifiedNameTests extends AbstractUnitTests
  69865. {
  69866. /**
  69867. * @covers XML_Util::splitQualifiedName()
  69868. */
  69869. public function testSplitQualifiedNameWithoutNamespace()
  69870. {
  69871. $original = "xslt:stylesheet";
  69872. $expected = array(
  69873. 'namespace' => 'xslt',
  69874. 'localPart' => 'stylesheet',
  69875. );
  69876. $this->assertEquals($expected, XML_Util::splitQualifiedName($original));
  69877. }
  69878. /**
  69879. * @covers XML_Util::splitQualifiedName()
  69880. */
  69881. public function testSplitQualifiedNameWithNamespace()
  69882. {
  69883. $original = "stylesheet";
  69884. $namespace = "myNs";
  69885. $expected = array(
  69886. 'namespace' => 'myNs',
  69887. 'localPart' => 'stylesheet',
  69888. );
  69889. $this->assertEquals($expected, XML_Util::splitQualifiedName($original, $namespace));
  69890. }
  69891. }
  69892. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/Bug4950Tests.php���������������������������������������������������������������0000644�0001750�0000144�00000001331�13125000640�016447 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69893. /**
  69894. * Bug #4950 "Incorrect CDATA serializing"
  69895. *
  69896. * Content that looks like CDATA end characters and tags
  69897. * should still be recognized solely as content text.
  69898. *
  69899. * @link https://pear.php.net/bugs/bug.php?id=4950
  69900. */
  69901. class Bug4950Tests extends AbstractUnitTests
  69902. {
  69903. public function testCreateTagForBug4950()
  69904. {
  69905. $qname = "test";
  69906. $attributes = array();
  69907. $content = "Content ]]></test> here!";
  69908. $namespaceUrl = null;
  69909. $expected = "<test><![CDATA[Content ]]]]><![CDATA[></test> here!]]></test>";
  69910. $result = XML_Util::createTag($qname, $attributes, $content, $namespaceUrl, XML_UTIL_CDATA_SECTION);
  69911. $this->assertEquals($expected, $result, "Failed bugcheck.");
  69912. }
  69913. }
  69914. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/Bug5392Tests.php���������������������������������������������������������������0000644�0001750�0000144�00000001377�13125000640�016462 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69915. /**
  69916. * Bug #5392 "encoding of ISO-8859-1 is the only supported encoding"
  69917. *
  69918. * Original characters of the given encoding that are "replaced"
  69919. * should then "reverse" back to perfectly match the original.
  69920. *
  69921. * @link https://pear.php.net/bugs/bug.php?id=5392
  69922. */
  69923. class Bug5392Tests extends AbstractUnitTests
  69924. {
  69925. public function testReplaceEntitiesForBug5392()
  69926. {
  69927. $original = 'This data contains special chars like <, >, & and " as well as ä, ö, ß, à and ê';
  69928. $replacedResult = XML_Util::replaceEntities($original, XML_UTIL_ENTITIES_HTML, "UTF-8");
  69929. $reversedResult = XML_Util::reverseEntities($replacedResult, XML_UTIL_ENTITIES_HTML, "UTF-8");
  69930. $this->assertEquals($original, $reversedResult, "Failed bugcheck.");
  69931. }
  69932. }
  69933. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/Bug18343Tests.php��������������������������������������������������������������0000644�0001750�0000144�00000003316�13125000640�016535 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69934. /**
  69935. * Bug #18343 "Entities in file names decoded during packaging"
  69936. *
  69937. * No matter what flags are given to createTagFromArray(),
  69938. * an attribute must *always* be at least ENTITIES_XML encoded.
  69939. *
  69940. * @link https://pear.php.net/bugs/bug.php?id=18343
  69941. */
  69942. class Bug18343Tests extends AbstractUnitTests
  69943. {
  69944. private $tagArray = array(
  69945. "qname" => "install",
  69946. "attributes" => array(
  69947. "as" => "Horde/Feed/fixtures/lexicon/http-p.moreover.com-cgi-local-page%2Fo=rss&s=Newsweek",
  69948. "name" => "test/Horde/Feed/fixtures/lexicon/http-p.moreover.com-cgi-local-page%2Fo=rss&s=Newsweek",
  69949. )
  69950. );
  69951. public function getFlagsToTest()
  69952. {
  69953. new XML_Util(); // for constants to be declared
  69954. return array(
  69955. array('no flag', null),
  69956. array('false', false),
  69957. array('ENTITIES_NONE', XML_UTIL_ENTITIES_NONE),
  69958. array('ENTITIES_XML', XML_UTIL_ENTITIES_XML),
  69959. array('ENTITIES_XML_REQUIRED', XML_UTIL_ENTITIES_XML_REQUIRED),
  69960. array('ENTITIES_HTML', XML_UTIL_ENTITIES_HTML),
  69961. array('REPLACE_ENTITIES', XML_UTIL_REPLACE_ENTITIES),
  69962. );
  69963. }
  69964. /**
  69965. * @dataProvider getFlagsToTest()
  69966. */
  69967. public function testCreateTagFromArrayForBug18343($key, $flag)
  69968. {
  69969. // all flags for the candidate input should return the same result
  69970. $expected =
  69971. <<< EOF
  69972. <install as="Horde/Feed/fixtures/lexicon/http-p.moreover.com-cgi-local-page%2Fo=rss&amp;s=Newsweek" name="test/Horde/Feed/fixtures/lexicon/http-p.moreover.com-cgi-local-page%2Fo=rss&amp;s=Newsweek" />
  69973. EOF;
  69974. $this->assertEquals($expected, XML_Util::createTagFromArray($this->tagArray, $flag), "Failed bugcheck for $key.");
  69975. }
  69976. }
  69977. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/Bug21177Tests.php��������������������������������������������������������������0000644�0001750�0000144�00000002036�13125000640�016532 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  69978. /**
  69979. * Bug #21177 "XML_Util::collapseEmptyTags() can return NULL"
  69980. *
  69981. * PREG returns NULL when it encounters an error.
  69982. * In this case, it was encountering PREG_BACKTRACK_LIMIT_ERROR.
  69983. *
  69984. * @link https://pear.php.net/bugs/bug.php?id=21177
  69985. */
  69986. class Bug21177Tests extends AbstractUnitTests
  69987. {
  69988. public function getTestCandidate()
  69989. {
  69990. $expected = '<id_mytest_yesorno />';
  69991. return array(
  69992. array('<idmytestyesorno></idmytestyesorno>', '<idmytestyesorno />'),
  69993. array('<idmytestyesorno />', '<idmytestyesorno />'),
  69994. array('<id_mytest_yesorno></id_mytest_yesorno>', '<id_mytest_yesorno />'),
  69995. array('<id_mytest_yesorno />', '<id_mytest_yesorno />'),
  69996. );
  69997. }
  69998. /**
  69999. * @dataProvider getTestCandidate()
  70000. */
  70001. public function testCollapseEmptyTagsForBug21177($original, $expected)
  70002. {
  70003. $this->assertEquals($expected, XML_Util::collapseEmptyTags($original, XML_UTIL_COLLAPSE_ALL), "Failed bugcheck.");
  70004. }
  70005. }
  70006. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������XML_Util-1.4.3/tests/Bug21184Tests.php��������������������������������������������������������������0000644�0001750�0000144�00000000702�13125000640�016526 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  70007. /**
  70008. * Bug #21184
  70009. *
  70010. * PREG returns NULL when it encounters an error.
  70011. * In this case, it was encountering PREG_BACKTRACK_LIMIT_ERROR.
  70012. *
  70013. * @link https://pear.php.net/bugs/bug.php?id=21177
  70014. */
  70015. class Bug21184 extends AbstractUnitTests
  70016. {
  70017. public function testBug21184()
  70018. {
  70019. $xml = '<XML_Serializer_Tag>one</XML_Serializer_Tag>';
  70020. $this->assertEquals($xml, XML_Util::collapseEmptyTags($xml, XML_UTIL_COLLAPSE_ALL));
  70021. }
  70022. }
  70023. ��������������������������������������������������������������XML_Util-1.4.3/XML/Util.php�������������������������������������������������������������������������0000644�0001750�0000144�00000076605�13125000640�014620 �0����������������������������������������������������������������������������������������������������ustar �cweiske�������������������������users������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  70024. /**
  70025. * XML_Util
  70026. *
  70027. * XML Utilities package
  70028. *
  70029. * PHP versions 4 and 5
  70030. *
  70031. * LICENSE:
  70032. *
  70033. * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
  70034. * All rights reserved.
  70035. *
  70036. * Redistribution and use in source and binary forms, with or without
  70037. * modification, are permitted provided that the following conditions
  70038. * are met:
  70039. *
  70040. * * Redistributions of source code must retain the above copyright
  70041. * notice, this list of conditions and the following disclaimer.
  70042. * * Redistributions in binary form must reproduce the above copyright
  70043. * notice, this list of conditions and the following disclaimer in the
  70044. * documentation and/or other materials provided with the distribution.
  70045. * * The name of the author may not be used to endorse or promote products
  70046. * derived from this software without specific prior written permission.
  70047. *
  70048. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  70049. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  70050. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  70051. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  70052. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  70053. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  70054. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  70055. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  70056. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  70057. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  70058. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  70059. *
  70060. * @category XML
  70061. * @package XML_Util
  70062. * @author Stephan Schmidt <schst@php.net>
  70063. * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
  70064. * @license http://opensource.org/licenses/bsd-license New BSD License
  70065. * @version CVS: $Id$
  70066. * @link http://pear.php.net/package/XML_Util
  70067. */
  70068. /**
  70069. * Error code for invalid chars in XML name
  70070. */
  70071. define('XML_UTIL_ERROR_INVALID_CHARS', 51);
  70072. /**
  70073. * Error code for invalid chars in XML name
  70074. */
  70075. define('XML_UTIL_ERROR_INVALID_START', 52);
  70076. /**
  70077. * Error code for non-scalar tag content
  70078. */
  70079. define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60);
  70080. /**
  70081. * Error code for missing tag name
  70082. */
  70083. define('XML_UTIL_ERROR_NO_TAG_NAME', 61);
  70084. /**
  70085. * Replace XML entities
  70086. */
  70087. define('XML_UTIL_REPLACE_ENTITIES', 1);
  70088. /**
  70089. * Embedd content in a CData Section
  70090. */
  70091. define('XML_UTIL_CDATA_SECTION', 5);
  70092. /**
  70093. * Do not replace entitites
  70094. */
  70095. define('XML_UTIL_ENTITIES_NONE', 0);
  70096. /**
  70097. * Replace all XML entitites
  70098. * This setting will replace <, >, ", ' and &
  70099. */
  70100. define('XML_UTIL_ENTITIES_XML', 1);
  70101. /**
  70102. * Replace only required XML entitites
  70103. * This setting will replace <, " and &
  70104. */
  70105. define('XML_UTIL_ENTITIES_XML_REQUIRED', 2);
  70106. /**
  70107. * Replace HTML entitites
  70108. * @link http://www.php.net/htmlentities
  70109. */
  70110. define('XML_UTIL_ENTITIES_HTML', 3);
  70111. /**
  70112. * Do not collapse any empty tags.
  70113. */
  70114. define('XML_UTIL_COLLAPSE_NONE', 0);
  70115. /**
  70116. * Collapse all empty tags.
  70117. */
  70118. define('XML_UTIL_COLLAPSE_ALL', 1);
  70119. /**
  70120. * Collapse only empty XHTML tags that have no end tag.
  70121. */
  70122. define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2);
  70123. /**
  70124. * Utility class for working with XML documents
  70125. *
  70126. * @category XML
  70127. * @package XML_Util
  70128. * @author Stephan Schmidt <schst@php.net>
  70129. * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
  70130. * @license http://opensource.org/licenses/bsd-license New BSD License
  70131. * @version Release: 1.4.3
  70132. * @link http://pear.php.net/package/XML_Util
  70133. */
  70134. class XML_Util
  70135. {
  70136. /**
  70137. * Return API version
  70138. *
  70139. * @return string $version API version
  70140. */
  70141. public static function apiVersion()
  70142. {
  70143. return '1.4';
  70144. }
  70145. /**
  70146. * Replace XML entities
  70147. *
  70148. * With the optional second parameter, you may select, which
  70149. * entities should be replaced.
  70150. *
  70151. * <code>
  70152. * require_once 'XML/Util.php';
  70153. *
  70154. * // replace XML entites:
  70155. * $string = XML_Util::replaceEntities('This string contains < & >.');
  70156. * </code>
  70157. *
  70158. * With the optional third parameter, you may pass the character encoding
  70159. * <code>
  70160. * require_once 'XML/Util.php';
  70161. *
  70162. * // replace XML entites in UTF-8:
  70163. * $string = XML_Util::replaceEntities(
  70164. * 'This string contains < & > as well as ä, ö, ß, à and ê',
  70165. * XML_UTIL_ENTITIES_HTML,
  70166. * 'UTF-8'
  70167. * );
  70168. * </code>
  70169. *
  70170. * @param string $string string where XML special chars
  70171. * should be replaced
  70172. * @param int $replaceEntities setting for entities in attribute values
  70173. * (one of XML_UTIL_ENTITIES_XML,
  70174. * XML_UTIL_ENTITIES_XML_REQUIRED,
  70175. * XML_UTIL_ENTITIES_HTML)
  70176. * @param string $encoding encoding value (if any)...
  70177. * must be a valid encoding as determined
  70178. * by the htmlentities() function
  70179. *
  70180. * @return string string with replaced chars
  70181. * @see reverseEntities()
  70182. */
  70183. public static function replaceEntities(
  70184. $string, $replaceEntities = XML_UTIL_ENTITIES_XML, $encoding = 'ISO-8859-1'
  70185. ) {
  70186. switch ($replaceEntities) {
  70187. case XML_UTIL_ENTITIES_XML:
  70188. return strtr(
  70189. $string,
  70190. array(
  70191. '&' => '&amp;',
  70192. '>' => '&gt;',
  70193. '<' => '&lt;',
  70194. '"' => '&quot;',
  70195. '\'' => '&apos;'
  70196. )
  70197. );
  70198. break;
  70199. case XML_UTIL_ENTITIES_XML_REQUIRED:
  70200. return strtr(
  70201. $string,
  70202. array(
  70203. '&' => '&amp;',
  70204. '<' => '&lt;',
  70205. '"' => '&quot;'
  70206. )
  70207. );
  70208. break;
  70209. case XML_UTIL_ENTITIES_HTML:
  70210. return htmlentities($string, ENT_COMPAT, $encoding);
  70211. break;
  70212. }
  70213. return $string;
  70214. }
  70215. /**
  70216. * Reverse XML entities
  70217. *
  70218. * With the optional second parameter, you may select, which
  70219. * entities should be reversed.
  70220. *
  70221. * <code>
  70222. * require_once 'XML/Util.php';
  70223. *
  70224. * // reverse XML entites:
  70225. * $string = XML_Util::reverseEntities('This string contains &lt; &amp; &gt;.');
  70226. * </code>
  70227. *
  70228. * With the optional third parameter, you may pass the character encoding
  70229. * <code>
  70230. * require_once 'XML/Util.php';
  70231. *
  70232. * // reverse XML entites in UTF-8:
  70233. * $string = XML_Util::reverseEntities(
  70234. * 'This string contains &lt; &amp; &gt; as well as'
  70235. * . ' &auml;, &ouml;, &szlig;, &agrave; and &ecirc;',
  70236. * XML_UTIL_ENTITIES_HTML,
  70237. * 'UTF-8'
  70238. * );
  70239. * </code>
  70240. *
  70241. * @param string $string string where XML special chars
  70242. * should be replaced
  70243. * @param int $replaceEntities setting for entities in attribute values
  70244. * (one of XML_UTIL_ENTITIES_XML,
  70245. * XML_UTIL_ENTITIES_XML_REQUIRED,
  70246. * XML_UTIL_ENTITIES_HTML)
  70247. * @param string $encoding encoding value (if any)...
  70248. * must be a valid encoding as determined
  70249. * by the html_entity_decode() function
  70250. *
  70251. * @return string string with replaced chars
  70252. * @see replaceEntities()
  70253. */
  70254. public static function reverseEntities(
  70255. $string, $replaceEntities = XML_UTIL_ENTITIES_XML, $encoding = 'ISO-8859-1'
  70256. ) {
  70257. switch ($replaceEntities) {
  70258. case XML_UTIL_ENTITIES_XML:
  70259. return strtr(
  70260. $string,
  70261. array(
  70262. '&amp;' => '&',
  70263. '&gt;' => '>',
  70264. '&lt;' => '<',
  70265. '&quot;' => '"',
  70266. '&apos;' => '\''
  70267. )
  70268. );
  70269. break;
  70270. case XML_UTIL_ENTITIES_XML_REQUIRED:
  70271. return strtr(
  70272. $string,
  70273. array(
  70274. '&amp;' => '&',
  70275. '&lt;' => '<',
  70276. '&quot;' => '"'
  70277. )
  70278. );
  70279. break;
  70280. case XML_UTIL_ENTITIES_HTML:
  70281. return html_entity_decode($string, ENT_COMPAT, $encoding);
  70282. break;
  70283. }
  70284. return $string;
  70285. }
  70286. /**
  70287. * Build an xml declaration
  70288. *
  70289. * <code>
  70290. * require_once 'XML/Util.php';
  70291. *
  70292. * // get an XML declaration:
  70293. * $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true);
  70294. * </code>
  70295. *
  70296. * @param string $version xml version
  70297. * @param string $encoding character encoding
  70298. * @param bool $standalone document is standalone (or not)
  70299. *
  70300. * @return string xml declaration
  70301. * @uses attributesToString() to serialize the attributes of the
  70302. * XML declaration
  70303. */
  70304. public static function getXMLDeclaration(
  70305. $version = '1.0', $encoding = null, $standalone = null
  70306. ) {
  70307. $attributes = array(
  70308. 'version' => $version,
  70309. );
  70310. // add encoding
  70311. if ($encoding !== null) {
  70312. $attributes['encoding'] = $encoding;
  70313. }
  70314. // add standalone, if specified
  70315. if ($standalone !== null) {
  70316. $attributes['standalone'] = $standalone ? 'yes' : 'no';
  70317. }
  70318. return sprintf(
  70319. '<?xml%s?>',
  70320. XML_Util::attributesToString($attributes, false)
  70321. );
  70322. }
  70323. /**
  70324. * Build a document type declaration
  70325. *
  70326. * <code>
  70327. * require_once 'XML/Util.php';
  70328. *
  70329. * // get a doctype declaration:
  70330. * $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd');
  70331. * </code>
  70332. *
  70333. * @param string $root name of the root tag
  70334. * @param string $uri uri of the doctype definition
  70335. * (or array with uri and public id)
  70336. * @param string $internalDtd internal dtd entries
  70337. *
  70338. * @return string doctype declaration
  70339. * @since 0.2
  70340. */
  70341. public static function getDocTypeDeclaration(
  70342. $root, $uri = null, $internalDtd = null
  70343. ) {
  70344. if (is_array($uri)) {
  70345. $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']);
  70346. } elseif (!empty($uri)) {
  70347. $ref = sprintf(' SYSTEM "%s"', $uri);
  70348. } else {
  70349. $ref = '';
  70350. }
  70351. if (empty($internalDtd)) {
  70352. return sprintf('<!DOCTYPE %s%s>', $root, $ref);
  70353. } else {
  70354. return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
  70355. }
  70356. }
  70357. /**
  70358. * Create string representation of an attribute list
  70359. *
  70360. * <code>
  70361. * require_once 'XML/Util.php';
  70362. *
  70363. * // build an attribute string
  70364. * $att = array(
  70365. * 'foo' => 'bar',
  70366. * 'argh' => 'tomato'
  70367. * );
  70368. *
  70369. * $attList = XML_Util::attributesToString($att);
  70370. * </code>
  70371. *
  70372. * @param array $attributes attribute array
  70373. * @param bool|array $sort sort attribute list alphabetically,
  70374. * may also be an assoc array containing
  70375. * the keys 'sort', 'multiline', 'indent',
  70376. * 'linebreak' and 'entities'
  70377. * @param bool $multiline use linebreaks, if more than
  70378. * one attribute is given
  70379. * @param string $indent string used for indentation of
  70380. * multiline attributes
  70381. * @param string $linebreak string used for linebreaks of
  70382. * multiline attributes
  70383. * @param int $entities setting for entities in attribute values
  70384. * (one of XML_UTIL_ENTITIES_NONE,
  70385. * XML_UTIL_ENTITIES_XML,
  70386. * XML_UTIL_ENTITIES_XML_REQUIRED,
  70387. * XML_UTIL_ENTITIES_HTML)
  70388. *
  70389. * @return string string representation of the attributes
  70390. * @uses replaceEntities() to replace XML entities in attribute values
  70391. * @todo allow sort also to be an options array
  70392. */
  70393. public static function attributesToString(
  70394. $attributes, $sort = true, $multiline = false,
  70395. $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML
  70396. ) {
  70397. /*
  70398. * second parameter may be an array
  70399. */
  70400. if (is_array($sort)) {
  70401. if (isset($sort['multiline'])) {
  70402. $multiline = $sort['multiline'];
  70403. }
  70404. if (isset($sort['indent'])) {
  70405. $indent = $sort['indent'];
  70406. }
  70407. if (isset($sort['linebreak'])) {
  70408. $multiline = $sort['linebreak'];
  70409. }
  70410. if (isset($sort['entities'])) {
  70411. $entities = $sort['entities'];
  70412. }
  70413. if (isset($sort['sort'])) {
  70414. $sort = $sort['sort'];
  70415. } else {
  70416. $sort = true;
  70417. }
  70418. }
  70419. $string = '';
  70420. if (is_array($attributes) && !empty($attributes)) {
  70421. if ($sort) {
  70422. ksort($attributes);
  70423. }
  70424. if (!$multiline || count($attributes) == 1) {
  70425. foreach ($attributes as $key => $value) {
  70426. if ($entities != XML_UTIL_ENTITIES_NONE) {
  70427. if ($entities === XML_UTIL_CDATA_SECTION) {
  70428. $entities = XML_UTIL_ENTITIES_XML;
  70429. }
  70430. $value = XML_Util::replaceEntities($value, $entities);
  70431. }
  70432. $string .= ' ' . $key . '="' . $value . '"';
  70433. }
  70434. } else {
  70435. $first = true;
  70436. foreach ($attributes as $key => $value) {
  70437. if ($entities != XML_UTIL_ENTITIES_NONE) {
  70438. $value = XML_Util::replaceEntities($value, $entities);
  70439. }
  70440. if ($first) {
  70441. $string .= ' ' . $key . '="' . $value . '"';
  70442. $first = false;
  70443. } else {
  70444. $string .= $linebreak . $indent . $key . '="' . $value . '"';
  70445. }
  70446. }
  70447. }
  70448. }
  70449. return $string;
  70450. }
  70451. /**
  70452. * Collapses empty tags.
  70453. *
  70454. * @param string $xml XML
  70455. * @param int $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL)
  70456. * or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.
  70457. *
  70458. * @return string XML
  70459. */
  70460. public static function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL)
  70461. {
  70462. if (preg_match('~<([^>])+/>~s', $xml, $matches)) {
  70463. // it's already an empty tag
  70464. return $xml;
  70465. }
  70466. switch ($mode) {
  70467. case XML_UTIL_COLLAPSE_ALL:
  70468. $preg1 =
  70469. '~<' .
  70470. '(?:' .
  70471. '(https?://[^:\s]+:\w+)' . // <http://foo.com:bar ($1)
  70472. '|(\w+:\w+)' . // <foo:bar ($2)
  70473. '|(\w+)' . // <foo ($3)
  70474. ')+' .
  70475. '([^>]*)' . // attributes ($4)
  70476. '>' .
  70477. '<\/(\1|\2|\3)>' . // 1, 2, or 3 again ($5)
  70478. '~s'
  70479. ;
  70480. $preg2 =
  70481. '<' .
  70482. '${1}${2}${3}' . // tag (only one should have been populated)
  70483. '${4}' . // attributes
  70484. ' />'
  70485. ;
  70486. return (preg_replace($preg1, $preg2, $xml)?:$xml);
  70487. break;
  70488. case XML_UTIL_COLLAPSE_XHTML_ONLY:
  70489. return (
  70490. preg_replace(
  70491. '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|'
  70492. . 'param)([^>]*)><\/\\1>/s',
  70493. '<\\1\\2 />',
  70494. $xml
  70495. ) ?: $xml
  70496. );
  70497. break;
  70498. case XML_UTIL_COLLAPSE_NONE:
  70499. // fall thru
  70500. default:
  70501. return $xml;
  70502. }
  70503. }
  70504. /**
  70505. * Create a tag
  70506. *
  70507. * This method will call XML_Util::createTagFromArray(), which
  70508. * is more flexible.
  70509. *
  70510. * <code>
  70511. * require_once 'XML/Util.php';
  70512. *
  70513. * // create an XML tag:
  70514. * $tag = XML_Util::createTag('myNs:myTag',
  70515. * array('foo' => 'bar'),
  70516. * 'This is inside the tag',
  70517. * 'http://www.w3c.org/myNs#');
  70518. * </code>
  70519. *
  70520. * @param string $qname qualified tagname (including namespace)
  70521. * @param array $attributes array containg attributes
  70522. * @param mixed $content the content
  70523. * @param string $namespaceUri URI of the namespace
  70524. * @param int $replaceEntities whether to replace XML special chars in
  70525. * content, embedd it in a CData section
  70526. * or none of both
  70527. * @param bool $multiline whether to create a multiline tag where
  70528. * each attribute gets written to a single line
  70529. * @param string $indent string used to indent attributes
  70530. * (_auto indents attributes so they start
  70531. * at the same column)
  70532. * @param string $linebreak string used for linebreaks
  70533. * @param bool $sortAttributes Whether to sort the attributes or not
  70534. * @param int $collapseTagMode How to handle a content-less, and thus collapseable, tag
  70535. *
  70536. * @return string XML tag
  70537. * @see createTagFromArray()
  70538. * @uses createTagFromArray() to create the tag
  70539. */
  70540. public static function createTag(
  70541. $qname, $attributes = array(), $content = null,
  70542. $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
  70543. $multiline = false, $indent = '_auto', $linebreak = "\n",
  70544. $sortAttributes = true, $collapseTagMode = XML_UTIL_COLLAPSE_ALL
  70545. ) {
  70546. $tag = array(
  70547. 'qname' => $qname,
  70548. 'attributes' => $attributes
  70549. );
  70550. // add tag content
  70551. if ($content !== null) {
  70552. $tag['content'] = $content;
  70553. }
  70554. // add namespace Uri
  70555. if ($namespaceUri !== null) {
  70556. $tag['namespaceUri'] = $namespaceUri;
  70557. }
  70558. return XML_Util::createTagFromArray(
  70559. $tag, $replaceEntities, $multiline,
  70560. $indent, $linebreak, $sortAttributes,
  70561. $collapseTagMode
  70562. );
  70563. }
  70564. /**
  70565. * Create a tag from an array.
  70566. * This method awaits an array in the following format
  70567. * <pre>
  70568. * array(
  70569. * // qualified name of the tag
  70570. * 'qname' => $qname
  70571. *
  70572. * // namespace prefix (optional, if qname is specified or no namespace)
  70573. * 'namespace' => $namespace
  70574. *
  70575. * // local part of the tagname (optional, if qname is specified)
  70576. * 'localpart' => $localpart,
  70577. *
  70578. * // array containing all attributes (optional)
  70579. * 'attributes' => array(),
  70580. *
  70581. * // tag content (optional)
  70582. * 'content' => $content,
  70583. *
  70584. * // namespaceUri for the given namespace (optional)
  70585. * 'namespaceUri' => $namespaceUri
  70586. * )
  70587. * </pre>
  70588. *
  70589. * <code>
  70590. * require_once 'XML/Util.php';
  70591. *
  70592. * $tag = array(
  70593. * 'qname' => 'foo:bar',
  70594. * 'namespaceUri' => 'http://foo.com',
  70595. * 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  70596. * 'content' => 'I\'m inside the tag',
  70597. * );
  70598. * // creating a tag with qualified name and namespaceUri
  70599. * $string = XML_Util::createTagFromArray($tag);
  70600. * </code>
  70601. *
  70602. * @param array $tag tag definition
  70603. * @param int $replaceEntities whether to replace XML special chars in
  70604. * content, embedd it in a CData section
  70605. * or none of both
  70606. * @param bool $multiline whether to create a multiline tag where each
  70607. * attribute gets written to a single line
  70608. * @param string $indent string used to indent attributes
  70609. * (_auto indents attributes so they start
  70610. * at the same column)
  70611. * @param string $linebreak string used for linebreaks
  70612. * @param bool $sortAttributes Whether to sort the attributes or not
  70613. * @param int $collapseTagMode How to handle a content-less, and thus collapseable, tag
  70614. *
  70615. * @return string XML tag
  70616. *
  70617. * @see createTag()
  70618. * @uses attributesToString() to serialize the attributes of the tag
  70619. * @uses splitQualifiedName() to get local part and namespace of a qualified name
  70620. * @uses createCDataSection()
  70621. * @uses collapseEmptyTags()
  70622. * @uses raiseError()
  70623. */
  70624. public static function createTagFromArray(
  70625. $tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
  70626. $multiline = false, $indent = '_auto', $linebreak = "\n",
  70627. $sortAttributes = true, $collapseTagMode = XML_UTIL_COLLAPSE_ALL
  70628. ) {
  70629. if (isset($tag['content']) && !is_scalar($tag['content'])) {
  70630. return XML_Util::raiseError(
  70631. 'Supplied non-scalar value as tag content',
  70632. XML_UTIL_ERROR_NON_SCALAR_CONTENT
  70633. );
  70634. }
  70635. if (!isset($tag['qname']) && !isset($tag['localPart'])) {
  70636. return XML_Util::raiseError(
  70637. 'You must either supply a qualified name '
  70638. . '(qname) or local tag name (localPart).',
  70639. XML_UTIL_ERROR_NO_TAG_NAME
  70640. );
  70641. }
  70642. // if no attributes hav been set, use empty attributes
  70643. if (!isset($tag['attributes']) || !is_array($tag['attributes'])) {
  70644. $tag['attributes'] = array();
  70645. }
  70646. if (isset($tag['namespaces'])) {
  70647. foreach ($tag['namespaces'] as $ns => $uri) {
  70648. $tag['attributes']['xmlns:' . $ns] = $uri;
  70649. }
  70650. }
  70651. if (!isset($tag['qname'])) {
  70652. // qualified name is not given
  70653. // check for namespace
  70654. if (isset($tag['namespace']) && !empty($tag['namespace'])) {
  70655. $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart'];
  70656. } else {
  70657. $tag['qname'] = $tag['localPart'];
  70658. }
  70659. } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) {
  70660. // namespace URI is set, but no namespace
  70661. $parts = XML_Util::splitQualifiedName($tag['qname']);
  70662. $tag['localPart'] = $parts['localPart'];
  70663. if (isset($parts['namespace'])) {
  70664. $tag['namespace'] = $parts['namespace'];
  70665. }
  70666. }
  70667. if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) {
  70668. // is a namespace given
  70669. if (isset($tag['namespace']) && !empty($tag['namespace'])) {
  70670. $tag['attributes']['xmlns:' . $tag['namespace']]
  70671. = $tag['namespaceUri'];
  70672. } else {
  70673. // define this Uri as the default namespace
  70674. $tag['attributes']['xmlns'] = $tag['namespaceUri'];
  70675. }
  70676. }
  70677. if (!array_key_exists('content', $tag)) {
  70678. $tag['content'] = '';
  70679. }
  70680. // check for multiline attributes
  70681. if ($multiline === true) {
  70682. if ($indent === '_auto') {
  70683. $indent = str_repeat(' ', (strlen($tag['qname'])+2));
  70684. }
  70685. }
  70686. // create attribute list
  70687. $attList = XML_Util::attributesToString(
  70688. $tag['attributes'],
  70689. $sortAttributes, $multiline, $indent, $linebreak
  70690. );
  70691. switch ($replaceEntities) {
  70692. case XML_UTIL_ENTITIES_NONE:
  70693. break;
  70694. case XML_UTIL_CDATA_SECTION:
  70695. $tag['content'] = XML_Util::createCDataSection($tag['content']);
  70696. break;
  70697. default:
  70698. $tag['content'] = XML_Util::replaceEntities(
  70699. $tag['content'], $replaceEntities
  70700. );
  70701. break;
  70702. }
  70703. $tag = sprintf(
  70704. '<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'],
  70705. $tag['qname']
  70706. );
  70707. return self::collapseEmptyTags($tag, $collapseTagMode);
  70708. }
  70709. /**
  70710. * Create a start element
  70711. *
  70712. * <code>
  70713. * require_once 'XML/Util.php';
  70714. *
  70715. * // create an XML start element:
  70716. * $tag = XML_Util::createStartElement('myNs:myTag',
  70717. * array('foo' => 'bar') ,'http://www.w3c.org/myNs#');
  70718. * </code>
  70719. *
  70720. * @param string $qname qualified tagname (including namespace)
  70721. * @param array $attributes array containg attributes
  70722. * @param string $namespaceUri URI of the namespace
  70723. * @param bool $multiline whether to create a multiline tag where each
  70724. * attribute gets written to a single line
  70725. * @param string $indent string used to indent attributes (_auto indents
  70726. * attributes so they start at the same column)
  70727. * @param string $linebreak string used for linebreaks
  70728. * @param bool $sortAttributes Whether to sort the attributes or not
  70729. *
  70730. * @return string XML start element
  70731. * @see createEndElement(), createTag()
  70732. */
  70733. public static function createStartElement(
  70734. $qname, $attributes = array(), $namespaceUri = null,
  70735. $multiline = false, $indent = '_auto', $linebreak = "\n",
  70736. $sortAttributes = true
  70737. ) {
  70738. // if no attributes hav been set, use empty attributes
  70739. if (!isset($attributes) || !is_array($attributes)) {
  70740. $attributes = array();
  70741. }
  70742. if ($namespaceUri != null) {
  70743. $parts = XML_Util::splitQualifiedName($qname);
  70744. }
  70745. // check for multiline attributes
  70746. if ($multiline === true) {
  70747. if ($indent === '_auto') {
  70748. $indent = str_repeat(' ', (strlen($qname)+2));
  70749. }
  70750. }
  70751. if ($namespaceUri != null) {
  70752. // is a namespace given
  70753. if (isset($parts['namespace']) && !empty($parts['namespace'])) {
  70754. $attributes['xmlns:' . $parts['namespace']] = $namespaceUri;
  70755. } else {
  70756. // define this Uri as the default namespace
  70757. $attributes['xmlns'] = $namespaceUri;
  70758. }
  70759. }
  70760. // create attribute list
  70761. $attList = XML_Util::attributesToString(
  70762. $attributes, $sortAttributes,
  70763. $multiline, $indent, $linebreak
  70764. );
  70765. $element = sprintf('<%s%s>', $qname, $attList);
  70766. return $element;
  70767. }
  70768. /**
  70769. * Create an end element
  70770. *
  70771. * <code>
  70772. * require_once 'XML/Util.php';
  70773. *
  70774. * // create an XML start element:
  70775. * $tag = XML_Util::createEndElement('myNs:myTag');
  70776. * </code>
  70777. *
  70778. * @param string $qname qualified tagname (including namespace)
  70779. *
  70780. * @return string XML end element
  70781. * @see createStartElement(), createTag()
  70782. */
  70783. public static function createEndElement($qname)
  70784. {
  70785. $element = sprintf('</%s>', $qname);
  70786. return $element;
  70787. }
  70788. /**
  70789. * Create an XML comment
  70790. *
  70791. * <code>
  70792. * require_once 'XML/Util.php';
  70793. *
  70794. * // create an XML start element:
  70795. * $tag = XML_Util::createComment('I am a comment');
  70796. * </code>
  70797. *
  70798. * @param string $content content of the comment
  70799. *
  70800. * @return string XML comment
  70801. */
  70802. public static function createComment($content)
  70803. {
  70804. $comment = sprintf('<!-- %s -->', $content);
  70805. return $comment;
  70806. }
  70807. /**
  70808. * Create a CData section
  70809. *
  70810. * <code>
  70811. * require_once 'XML/Util.php';
  70812. *
  70813. * // create a CData section
  70814. * $tag = XML_Util::createCDataSection('I am content.');
  70815. * </code>
  70816. *
  70817. * @param string $data data of the CData section
  70818. *
  70819. * @return string CData section with content
  70820. */
  70821. public static function createCDataSection($data)
  70822. {
  70823. return sprintf(
  70824. '<![CDATA[%s]]>',
  70825. preg_replace('/\]\]>/', ']]]]><![CDATA[>', strval($data))
  70826. );
  70827. }
  70828. /**
  70829. * Split qualified name and return namespace and local part
  70830. *
  70831. * <code>
  70832. * require_once 'XML/Util.php';
  70833. *
  70834. * // split qualified tag
  70835. * $parts = XML_Util::splitQualifiedName('xslt:stylesheet');
  70836. * </code>
  70837. * the returned array will contain two elements:
  70838. * <pre>
  70839. * array(
  70840. * 'namespace' => 'xslt',
  70841. * 'localPart' => 'stylesheet'
  70842. * );
  70843. * </pre>
  70844. *
  70845. * @param string $qname qualified tag name
  70846. * @param string $defaultNs default namespace (optional)
  70847. *
  70848. * @return array array containing namespace and local part
  70849. */
  70850. public static function splitQualifiedName($qname, $defaultNs = null)
  70851. {
  70852. if (strstr($qname, ':')) {
  70853. $tmp = explode(':', $qname);
  70854. return array(
  70855. 'namespace' => $tmp[0],
  70856. 'localPart' => $tmp[1]
  70857. );
  70858. }
  70859. return array(
  70860. 'namespace' => $defaultNs,
  70861. 'localPart' => $qname
  70862. );
  70863. }
  70864. /**
  70865. * Check, whether string is valid XML name
  70866. *
  70867. * <p>XML names are used for tagname, attribute names and various
  70868. * other, lesser known entities.</p>
  70869. * <p>An XML name may only consist of alphanumeric characters,
  70870. * dashes, undescores and periods, and has to start with a letter
  70871. * or an underscore.</p>
  70872. *
  70873. * <code>
  70874. * require_once 'XML/Util.php';
  70875. *
  70876. * // verify tag name
  70877. * $result = XML_Util::isValidName('invalidTag?');
  70878. * if (is_a($result, 'PEAR_Error')) {
  70879. * print 'Invalid XML name: ' . $result->getMessage();
  70880. * }
  70881. * </code>
  70882. *
  70883. * @param string $string string that should be checked
  70884. *
  70885. * @return mixed true, if string is a valid XML name, PEAR error otherwise
  70886. *
  70887. * @todo support for other charsets
  70888. * @todo PEAR CS - unable to avoid 85-char limit on second preg_match
  70889. */
  70890. public static function isValidName($string)
  70891. {
  70892. // check for invalid chars
  70893. if (!preg_match('/^[[:alpha:]_]\\z/', $string{0})) {
  70894. return XML_Util::raiseError(
  70895. 'XML names may only start with letter or underscore',
  70896. XML_UTIL_ERROR_INVALID_START
  70897. );
  70898. }
  70899. // check for invalid chars
  70900. $match = preg_match(
  70901. '/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?'
  70902. . '[[:alpha:]_]([[:alnum:]\_\-\.]+)?\\z/',
  70903. $string
  70904. );
  70905. if (!$match) {
  70906. return XML_Util::raiseError(
  70907. 'XML names may only contain alphanumeric '
  70908. . 'chars, period, hyphen, colon and underscores',
  70909. XML_UTIL_ERROR_INVALID_CHARS
  70910. );
  70911. }
  70912. // XML name is valid
  70913. return true;
  70914. }
  70915. /**
  70916. * Replacement for XML_Util::raiseError
  70917. *
  70918. * Avoids the necessity to always require
  70919. * PEAR.php
  70920. *
  70921. * @param string $msg error message
  70922. * @param int $code error code
  70923. *
  70924. * @return PEAR_Error
  70925. * @todo PEAR CS - should this use include_once instead?
  70926. */
  70927. public static function raiseError($msg, $code)
  70928. {
  70929. include_once 'PEAR.php';
  70930. return PEAR::raiseError($msg, $code);
  70931. }
  70932. }
  70933. ?>
  70934. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?php
  70935. /**
  70936. * PEAR_Installer
  70937. *
  70938. * PHP versions 4 and 5
  70939. *
  70940. * @category pear
  70941. * @package PEAR
  70942. * @author Stig Bakken <ssb@php.net>
  70943. * @author Tomas V.V. Cox <cox@idecnet.com>
  70944. * @author Martin Jansen <mj@php.net>
  70945. * @author Greg Beaver <cellog@php.net>
  70946. * @copyright 1997-2009 The Authors
  70947. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  70948. * @link http://pear.php.net/package/PEAR
  70949. * @since File available since Release 0.1
  70950. */
  70951. /**
  70952. * Used for installation groups in package.xml 2.0 and platform exceptions
  70953. */
  70954. require_once 'phar://go-pear.phar/' . 'OS/Guess.php';
  70955. require_once 'phar://go-pear.phar/' . 'PEAR/Downloader.php';
  70956. define('PEAR_INSTALLER_NOBINARY', -240);
  70957. /**
  70958. * Administration class used to install PEAR packages and maintain the
  70959. * installed package database.
  70960. *
  70961. * @category pear
  70962. * @package PEAR
  70963. * @author Stig Bakken <ssb@php.net>
  70964. * @author Tomas V.V. Cox <cox@idecnet.com>
  70965. * @author Martin Jansen <mj@php.net>
  70966. * @author Greg Beaver <cellog@php.net>
  70967. * @copyright 1997-2009 The Authors
  70968. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  70969. * @version Release: 1.10.10
  70970. * @link http://pear.php.net/package/PEAR
  70971. * @since Class available since Release 0.1
  70972. */
  70973. class PEAR_Installer extends PEAR_Downloader
  70974. {
  70975. // {{{ properties
  70976. /** name of the package directory, for example Foo-1.0
  70977. * @var string
  70978. */
  70979. var $pkgdir;
  70980. /** directory where PHP code files go
  70981. * @var string
  70982. */
  70983. var $phpdir;
  70984. /** directory where PHP extension files go
  70985. * @var string
  70986. */
  70987. var $extdir;
  70988. /** directory where documentation goes
  70989. * @var string
  70990. */
  70991. var $docdir;
  70992. /** installation root directory (ala PHP's INSTALL_ROOT or
  70993. * automake's DESTDIR
  70994. * @var string
  70995. */
  70996. var $installroot = '';
  70997. /** debug level
  70998. * @var int
  70999. */
  71000. var $debug = 1;
  71001. /** temporary directory
  71002. * @var string
  71003. */
  71004. var $tmpdir;
  71005. /**
  71006. * PEAR_Registry object used by the installer
  71007. * @var PEAR_Registry
  71008. */
  71009. var $registry;
  71010. /**
  71011. * array of PEAR_Downloader_Packages
  71012. * @var array
  71013. */
  71014. var $_downloadedPackages;
  71015. /** List of file transactions queued for an install/upgrade/uninstall.
  71016. *
  71017. * Format:
  71018. * array(
  71019. * 0 => array("rename => array("from-file", "to-file")),
  71020. * 1 => array("delete" => array("file-to-delete")),
  71021. * ...
  71022. * )
  71023. *
  71024. * @var array
  71025. */
  71026. var $file_operations = array();
  71027. // }}}
  71028. // {{{ constructor
  71029. /**
  71030. * PEAR_Installer constructor.
  71031. *
  71032. * @param object $ui user interface object (instance of PEAR_Frontend_*)
  71033. *
  71034. * @access public
  71035. */
  71036. function __construct(&$ui)
  71037. {
  71038. parent::__construct($ui, array(), null);
  71039. $this->setFrontendObject($ui);
  71040. $this->debug = $this->config->get('verbose');
  71041. }
  71042. function setOptions($options)
  71043. {
  71044. $this->_options = $options;
  71045. }
  71046. function setConfig(&$config)
  71047. {
  71048. $this->config = &$config;
  71049. $this->_registry = &$config->getRegistry();
  71050. }
  71051. // }}}
  71052. function _removeBackups($files)
  71053. {
  71054. foreach ($files as $path) {
  71055. $this->addFileOperation('removebackup', array($path));
  71056. }
  71057. }
  71058. // {{{ _deletePackageFiles()
  71059. /**
  71060. * Delete a package's installed files, does not remove empty directories.
  71061. *
  71062. * @param string package name
  71063. * @param string channel name
  71064. * @param bool if true, then files are backed up first
  71065. * @return bool TRUE on success, or a PEAR error on failure
  71066. * @access protected
  71067. */
  71068. function _deletePackageFiles($package, $channel = false, $backup = false)
  71069. {
  71070. if (!$channel) {
  71071. $channel = 'pear.php.net';
  71072. }
  71073. if (!strlen($package)) {
  71074. return $this->raiseError("No package to uninstall given");
  71075. }
  71076. if (strtolower($package) == 'pear' && $channel == 'pear.php.net') {
  71077. // to avoid race conditions, include all possible needed files
  71078. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php';
  71079. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Replace.php';
  71080. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Unixeol.php';
  71081. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Windowseol.php';
  71082. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  71083. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  71084. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v1.php';
  71085. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v2.php';
  71086. }
  71087. $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
  71088. if ($filelist == null) {
  71089. return $this->raiseError("$channel/$package not installed");
  71090. }
  71091. $ret = array();
  71092. foreach ($filelist as $file => $props) {
  71093. if (empty($props['installed_as'])) {
  71094. continue;
  71095. }
  71096. $path = $props['installed_as'];
  71097. if ($backup) {
  71098. $this->addFileOperation('backup', array($path));
  71099. $ret[] = $path;
  71100. }
  71101. $this->addFileOperation('delete', array($path));
  71102. }
  71103. if ($backup) {
  71104. return $ret;
  71105. }
  71106. return true;
  71107. }
  71108. // }}}
  71109. // {{{ _installFile()
  71110. /**
  71111. * @param string filename
  71112. * @param array attributes from <file> tag in package.xml
  71113. * @param string path to install the file in
  71114. * @param array options from command-line
  71115. * @access private
  71116. */
  71117. function _installFile($file, $atts, $tmp_path, $options)
  71118. {
  71119. // {{{ return if this file is meant for another platform
  71120. static $os;
  71121. if (!isset($this->_registry)) {
  71122. $this->_registry = &$this->config->getRegistry();
  71123. }
  71124. if (isset($atts['platform'])) {
  71125. if (empty($os)) {
  71126. $os = new OS_Guess();
  71127. }
  71128. if (strlen($atts['platform']) && $atts['platform'][0] == '!') {
  71129. $negate = true;
  71130. $platform = substr($atts['platform'], 1);
  71131. } else {
  71132. $negate = false;
  71133. $platform = $atts['platform'];
  71134. }
  71135. if ((bool) $os->matchSignature($platform) === $negate) {
  71136. $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
  71137. return PEAR_INSTALLER_SKIPPED;
  71138. }
  71139. }
  71140. // }}}
  71141. $channel = $this->pkginfo->getChannel();
  71142. // {{{ assemble the destination paths
  71143. switch ($atts['role']) {
  71144. case 'src':
  71145. case 'extsrc':
  71146. $this->source_files++;
  71147. return;
  71148. case 'doc':
  71149. case 'data':
  71150. case 'test':
  71151. $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) .
  71152. DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
  71153. unset($atts['baseinstalldir']);
  71154. break;
  71155. case 'ext':
  71156. case 'php':
  71157. $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
  71158. break;
  71159. case 'script':
  71160. $dest_dir = $this->config->get('bin_dir', null, $channel);
  71161. break;
  71162. default:
  71163. return $this->raiseError("Invalid role `$atts[role]' for file $file");
  71164. }
  71165. $save_destdir = $dest_dir;
  71166. if (!empty($atts['baseinstalldir'])) {
  71167. $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
  71168. }
  71169. if (dirname($file) != '.' && empty($atts['install-as'])) {
  71170. $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
  71171. }
  71172. if (empty($atts['install-as'])) {
  71173. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
  71174. } else {
  71175. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
  71176. }
  71177. $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
  71178. // Clean up the DIRECTORY_SEPARATOR mess
  71179. $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  71180. list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
  71181. array(DIRECTORY_SEPARATOR,
  71182. DIRECTORY_SEPARATOR,
  71183. DIRECTORY_SEPARATOR),
  71184. array($dest_file, $orig_file));
  71185. $final_dest_file = $installed_as = $dest_file;
  71186. if (isset($this->_options['packagingroot'])) {
  71187. $installedas_dest_dir = dirname($final_dest_file);
  71188. $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  71189. $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']);
  71190. } else {
  71191. $installedas_dest_dir = dirname($final_dest_file);
  71192. $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  71193. }
  71194. $dest_dir = dirname($final_dest_file);
  71195. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  71196. if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
  71197. return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
  71198. }
  71199. // }}}
  71200. if (empty($this->_options['register-only']) &&
  71201. (!file_exists($dest_dir) || !is_dir($dest_dir))) {
  71202. if (!$this->mkDirHier($dest_dir)) {
  71203. return $this->raiseError("failed to mkdir $dest_dir",
  71204. PEAR_INSTALLER_FAILED);
  71205. }
  71206. $this->log(3, "+ mkdir $dest_dir");
  71207. }
  71208. // pretty much nothing happens if we are only registering the install
  71209. if (empty($this->_options['register-only'])) {
  71210. if (empty($atts['replacements'])) {
  71211. if (!file_exists($orig_file)) {
  71212. return $this->raiseError("file $orig_file does not exist",
  71213. PEAR_INSTALLER_FAILED);
  71214. }
  71215. if (!@copy($orig_file, $dest_file)) {
  71216. return $this->raiseError(
  71217. "failed to write $dest_file: " . error_get_last()["message"],
  71218. PEAR_INSTALLER_FAILED);
  71219. }
  71220. $this->log(3, "+ cp $orig_file $dest_file");
  71221. if (isset($atts['md5sum'])) {
  71222. $md5sum = md5_file($dest_file);
  71223. }
  71224. } else {
  71225. // {{{ file with replacements
  71226. if (!file_exists($orig_file)) {
  71227. return $this->raiseError("file does not exist",
  71228. PEAR_INSTALLER_FAILED);
  71229. }
  71230. $contents = file_get_contents($orig_file);
  71231. if ($contents === false) {
  71232. $contents = '';
  71233. }
  71234. if (isset($atts['md5sum'])) {
  71235. $md5sum = md5($contents);
  71236. }
  71237. $subst_from = $subst_to = array();
  71238. foreach ($atts['replacements'] as $a) {
  71239. $to = '';
  71240. if ($a['type'] == 'php-const') {
  71241. if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) {
  71242. eval("\$to = $a[to];");
  71243. } else {
  71244. if (!isset($options['soft'])) {
  71245. $this->log(0, "invalid php-const replacement: $a[to]");
  71246. }
  71247. continue;
  71248. }
  71249. } elseif ($a['type'] == 'pear-config') {
  71250. if ($a['to'] == 'master_server') {
  71251. $chan = $this->_registry->getChannel($channel);
  71252. if (!PEAR::isError($chan)) {
  71253. $to = $chan->getServer();
  71254. } else {
  71255. $to = $this->config->get($a['to'], null, $channel);
  71256. }
  71257. } else {
  71258. $to = $this->config->get($a['to'], null, $channel);
  71259. }
  71260. if (is_null($to)) {
  71261. if (!isset($options['soft'])) {
  71262. $this->log(0, "invalid pear-config replacement: $a[to]");
  71263. }
  71264. continue;
  71265. }
  71266. } elseif ($a['type'] == 'package-info') {
  71267. if ($t = $this->pkginfo->packageInfo($a['to'])) {
  71268. $to = $t;
  71269. } else {
  71270. if (!isset($options['soft'])) {
  71271. $this->log(0, "invalid package-info replacement: $a[to]");
  71272. }
  71273. continue;
  71274. }
  71275. }
  71276. if (!is_null($to)) {
  71277. $subst_from[] = $a['from'];
  71278. $subst_to[] = $to;
  71279. }
  71280. }
  71281. $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
  71282. if (sizeof($subst_from)) {
  71283. $contents = str_replace($subst_from, $subst_to, $contents);
  71284. }
  71285. $wp = @fopen($dest_file, "wb");
  71286. if (!is_resource($wp)) {
  71287. return $this->raiseError(
  71288. "failed to create $dest_file: " . error_get_last()["message"],
  71289. PEAR_INSTALLER_FAILED);
  71290. }
  71291. if (@fwrite($wp, $contents) === false) {
  71292. return $this->raiseError(
  71293. "failed writing to $dest_file: " . error_get_last()["message"],
  71294. PEAR_INSTALLER_FAILED);
  71295. }
  71296. fclose($wp);
  71297. // }}}
  71298. }
  71299. // {{{ check the md5
  71300. if (isset($md5sum)) {
  71301. if (strtolower($md5sum) === strtolower($atts['md5sum'])) {
  71302. $this->log(2, "md5sum ok: $final_dest_file");
  71303. } else {
  71304. if (empty($options['force'])) {
  71305. // delete the file
  71306. if (file_exists($dest_file)) {
  71307. unlink($dest_file);
  71308. }
  71309. if (!isset($options['ignore-errors'])) {
  71310. return $this->raiseError("bad md5sum for file $final_dest_file",
  71311. PEAR_INSTALLER_FAILED);
  71312. }
  71313. if (!isset($options['soft'])) {
  71314. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  71315. }
  71316. } else {
  71317. if (!isset($options['soft'])) {
  71318. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  71319. }
  71320. }
  71321. }
  71322. }
  71323. // }}}
  71324. // {{{ set file permissions
  71325. if (!OS_WINDOWS) {
  71326. if ($atts['role'] == 'script') {
  71327. $mode = 0777 & ~(int)octdec($this->config->get('umask'));
  71328. $this->log(3, "+ chmod +x $dest_file");
  71329. } else {
  71330. $mode = 0666 & ~(int)octdec($this->config->get('umask'));
  71331. }
  71332. if ($atts['role'] != 'src') {
  71333. $this->addFileOperation("chmod", array($mode, $dest_file));
  71334. if (!@chmod($dest_file, $mode)) {
  71335. if (!isset($options['soft'])) {
  71336. $this->log(0, "failed to change mode of $dest_file: " .
  71337. error_get_last()["message"]);
  71338. }
  71339. }
  71340. }
  71341. }
  71342. // }}}
  71343. if ($atts['role'] == 'src') {
  71344. rename($dest_file, $final_dest_file);
  71345. $this->log(2, "renamed source file $dest_file to $final_dest_file");
  71346. } else {
  71347. $this->addFileOperation("rename", array($dest_file, $final_dest_file,
  71348. $atts['role'] == 'ext'));
  71349. }
  71350. }
  71351. // Store the full path where the file was installed for easy unistall
  71352. if ($atts['role'] != 'script') {
  71353. $loc = $this->config->get($atts['role'] . '_dir');
  71354. } else {
  71355. $loc = $this->config->get('bin_dir');
  71356. }
  71357. if ($atts['role'] != 'src') {
  71358. $this->addFileOperation("installed_as", array($file, $installed_as,
  71359. $loc,
  71360. dirname(substr($installedas_dest_file, strlen($loc)))));
  71361. }
  71362. //$this->log(2, "installed: $dest_file");
  71363. return PEAR_INSTALLER_OK;
  71364. }
  71365. // }}}
  71366. // {{{ _installFile2()
  71367. /**
  71368. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  71369. * @param string filename
  71370. * @param array attributes from <file> tag in package.xml
  71371. * @param string path to install the file in
  71372. * @param array options from command-line
  71373. * @access private
  71374. */
  71375. function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options)
  71376. {
  71377. $atts = $real_atts;
  71378. if (!isset($this->_registry)) {
  71379. $this->_registry = &$this->config->getRegistry();
  71380. }
  71381. $channel = $pkg->getChannel();
  71382. // {{{ assemble the destination paths
  71383. if (!in_array($atts['attribs']['role'],
  71384. PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
  71385. return $this->raiseError('Invalid role `' . $atts['attribs']['role'] .
  71386. "' for file $file");
  71387. }
  71388. $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config);
  71389. $err = $role->setup($this, $pkg, $atts['attribs'], $file);
  71390. if (PEAR::isError($err)) {
  71391. return $err;
  71392. }
  71393. if (!$role->isInstallable()) {
  71394. return;
  71395. }
  71396. $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
  71397. if (PEAR::isError($info)) {
  71398. return $info;
  71399. }
  71400. list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
  71401. if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
  71402. return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
  71403. }
  71404. $final_dest_file = $installed_as = $dest_file;
  71405. if (isset($this->_options['packagingroot'])) {
  71406. $final_dest_file = $this->_prependPath($final_dest_file,
  71407. $this->_options['packagingroot']);
  71408. }
  71409. $dest_dir = dirname($final_dest_file);
  71410. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
  71411. // }}}
  71412. if (empty($this->_options['register-only'])) {
  71413. if (!file_exists($dest_dir) || !is_dir($dest_dir)) {
  71414. if (!$this->mkDirHier($dest_dir)) {
  71415. return $this->raiseError("failed to mkdir $dest_dir",
  71416. PEAR_INSTALLER_FAILED);
  71417. }
  71418. $this->log(3, "+ mkdir $dest_dir");
  71419. }
  71420. }
  71421. $attribs = $atts['attribs'];
  71422. unset($atts['attribs']);
  71423. // pretty much nothing happens if we are only registering the install
  71424. if (empty($this->_options['register-only'])) {
  71425. if (!count($atts)) { // no tasks
  71426. if (!file_exists($orig_file)) {
  71427. return $this->raiseError("file $orig_file does not exist",
  71428. PEAR_INSTALLER_FAILED);
  71429. }
  71430. if (!@copy($orig_file, $dest_file)) {
  71431. return $this->raiseError(
  71432. "failed to write $dest_file: " . error_get_last()["message"],
  71433. PEAR_INSTALLER_FAILED);
  71434. }
  71435. $this->log(3, "+ cp $orig_file $dest_file");
  71436. if (isset($attribs['md5sum'])) {
  71437. $md5sum = md5_file($dest_file);
  71438. }
  71439. } else { // file with tasks
  71440. if (!file_exists($orig_file)) {
  71441. return $this->raiseError("file $orig_file does not exist",
  71442. PEAR_INSTALLER_FAILED);
  71443. }
  71444. $contents = file_get_contents($orig_file);
  71445. if ($contents === false) {
  71446. $contents = '';
  71447. }
  71448. if (isset($attribs['md5sum'])) {
  71449. $md5sum = md5($contents);
  71450. }
  71451. foreach ($atts as $tag => $raw) {
  71452. $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag);
  71453. $task = "PEAR_Task_$tag";
  71454. $task = new $task($this->config, $this, PEAR_TASK_INSTALL);
  71455. if (!$task->isScript()) { // scripts are only handled after installation
  71456. $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
  71457. $res = $task->startSession($pkg, $contents, $final_dest_file);
  71458. if ($res === false) {
  71459. continue; // skip this file
  71460. }
  71461. if (PEAR::isError($res)) {
  71462. return $res;
  71463. }
  71464. $contents = $res; // save changes
  71465. }
  71466. $wp = @fopen($dest_file, "wb");
  71467. if (!is_resource($wp)) {
  71468. return $this->raiseError(
  71469. "failed to create $dest_file: " . error_get_last()["message"],
  71470. PEAR_INSTALLER_FAILED);
  71471. }
  71472. if (fwrite($wp, $contents) === false) {
  71473. return $this->raiseError(
  71474. "failed writing to $dest_file: " . error_get_last()["message"],
  71475. PEAR_INSTALLER_FAILED);
  71476. }
  71477. fclose($wp);
  71478. }
  71479. }
  71480. // {{{ check the md5
  71481. if (isset($md5sum)) {
  71482. // Make sure the original md5 sum matches with expected
  71483. if (strtolower($md5sum) === strtolower($attribs['md5sum'])) {
  71484. $this->log(2, "md5sum ok: $final_dest_file");
  71485. if (isset($contents)) {
  71486. // set md5 sum based on $content in case any tasks were run.
  71487. $real_atts['attribs']['md5sum'] = md5($contents);
  71488. }
  71489. } else {
  71490. if (empty($options['force'])) {
  71491. // delete the file
  71492. if (file_exists($dest_file)) {
  71493. unlink($dest_file);
  71494. }
  71495. if (!isset($options['ignore-errors'])) {
  71496. return $this->raiseError("bad md5sum for file $final_dest_file",
  71497. PEAR_INSTALLER_FAILED);
  71498. }
  71499. if (!isset($options['soft'])) {
  71500. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  71501. }
  71502. } else {
  71503. if (!isset($options['soft'])) {
  71504. $this->log(0, "warning : bad md5sum for file $final_dest_file");
  71505. }
  71506. }
  71507. }
  71508. } else {
  71509. $real_atts['attribs']['md5sum'] = md5_file($dest_file);
  71510. }
  71511. // }}}
  71512. // {{{ set file permissions
  71513. if (!OS_WINDOWS) {
  71514. if ($role->isExecutable()) {
  71515. $mode = 0777 & ~(int)octdec($this->config->get('umask'));
  71516. $this->log(3, "+ chmod +x $dest_file");
  71517. } else {
  71518. $mode = 0666 & ~(int)octdec($this->config->get('umask'));
  71519. }
  71520. if ($attribs['role'] != 'src') {
  71521. $this->addFileOperation("chmod", array($mode, $dest_file));
  71522. if (!@chmod($dest_file, $mode)) {
  71523. if (!isset($options['soft'])) {
  71524. $this->log(0, "failed to change mode of $dest_file: " .
  71525. error_get_last()["message"]);
  71526. }
  71527. }
  71528. }
  71529. }
  71530. // }}}
  71531. if ($attribs['role'] == 'src') {
  71532. rename($dest_file, $final_dest_file);
  71533. $this->log(2, "renamed source file $dest_file to $final_dest_file");
  71534. } else {
  71535. $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
  71536. }
  71537. }
  71538. // Store the full path where the file was installed for easy uninstall
  71539. if ($attribs['role'] != 'src') {
  71540. $loc = $this->config->get($role->getLocationConfig(), null, $channel);
  71541. $this->addFileOperation('installed_as', array($file, $installed_as,
  71542. $loc,
  71543. dirname(substr($installed_as, strlen($loc)))));
  71544. }
  71545. //$this->log(2, "installed: $dest_file");
  71546. return PEAR_INSTALLER_OK;
  71547. }
  71548. // }}}
  71549. // {{{ addFileOperation()
  71550. /**
  71551. * Add a file operation to the current file transaction.
  71552. *
  71553. * @see startFileTransaction()
  71554. * @param string $type This can be one of:
  71555. * - rename: rename a file ($data has 3 values)
  71556. * - backup: backup an existing file ($data has 1 value)
  71557. * - removebackup: clean up backups created during install ($data has 1 value)
  71558. * - chmod: change permissions on a file ($data has 2 values)
  71559. * - delete: delete a file ($data has 1 value)
  71560. * - rmdir: delete a directory if empty ($data has 1 value)
  71561. * - installed_as: mark a file as installed ($data has 4 values).
  71562. * @param array $data For all file operations, this array must contain the
  71563. * full path to the file or directory that is being operated on. For
  71564. * the rename command, the first parameter must be the file to rename,
  71565. * the second its new name, the third whether this is a PHP extension.
  71566. *
  71567. * The installed_as operation contains 4 elements in this order:
  71568. * 1. Filename as listed in the filelist element from package.xml
  71569. * 2. Full path to the installed file
  71570. * 3. Full path from the php_dir configuration variable used in this
  71571. * installation
  71572. * 4. Relative path from the php_dir that this file is installed in
  71573. */
  71574. function addFileOperation($type, $data)
  71575. {
  71576. if (!is_array($data)) {
  71577. return $this->raiseError('Internal Error: $data in addFileOperation'
  71578. . ' must be an array, was ' . gettype($data));
  71579. }
  71580. if ($type == 'chmod') {
  71581. $octmode = decoct($data[0]);
  71582. $this->log(3, "adding to transaction: $type $octmode $data[1]");
  71583. } else {
  71584. $this->log(3, "adding to transaction: $type " . implode(" ", $data));
  71585. }
  71586. $this->file_operations[] = array($type, $data);
  71587. }
  71588. // }}}
  71589. // {{{ startFileTransaction()
  71590. function startFileTransaction($rollback_in_case = false)
  71591. {
  71592. if (count($this->file_operations) && $rollback_in_case) {
  71593. $this->rollbackFileTransaction();
  71594. }
  71595. $this->file_operations = array();
  71596. }
  71597. // }}}
  71598. // {{{ commitFileTransaction()
  71599. function commitFileTransaction()
  71600. {
  71601. // {{{ first, check permissions and such manually
  71602. $errors = array();
  71603. foreach ($this->file_operations as $key => $tr) {
  71604. list($type, $data) = $tr;
  71605. switch ($type) {
  71606. case 'rename':
  71607. if (!file_exists($data[0])) {
  71608. $errors[] = "cannot rename file $data[0], doesn't exist";
  71609. }
  71610. // check that dest dir. is writable
  71611. if (!is_writable(dirname($data[1]))) {
  71612. $errors[] = "permission denied ($type): $data[1]";
  71613. }
  71614. break;
  71615. case 'chmod':
  71616. // check that file is writable
  71617. if (!is_writable($data[1])) {
  71618. $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
  71619. }
  71620. break;
  71621. case 'delete':
  71622. if (!file_exists($data[0])) {
  71623. $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
  71624. }
  71625. // check that directory is writable
  71626. if (file_exists($data[0])) {
  71627. if (!is_writable(dirname($data[0]))) {
  71628. $errors[] = "permission denied ($type): $data[0]";
  71629. } else {
  71630. // make sure the file to be deleted can be opened for writing
  71631. $fp = false;
  71632. if (!is_dir($data[0]) &&
  71633. (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) {
  71634. $errors[] = "permission denied ($type): $data[0]";
  71635. } elseif ($fp) {
  71636. fclose($fp);
  71637. }
  71638. }
  71639. /* Verify we are not deleting a file owned by another package
  71640. * This can happen when a file moves from package A to B in
  71641. * an upgrade ala http://pear.php.net/17986
  71642. */
  71643. $info = array(
  71644. 'package' => strtolower($this->pkginfo->getName()),
  71645. 'channel' => strtolower($this->pkginfo->getChannel()),
  71646. );
  71647. $result = $this->_registry->checkFileMap($data[0], $info, '1.1');
  71648. if (is_array($result)) {
  71649. $res = array_diff($result, $info);
  71650. if (!empty($res)) {
  71651. $new = $this->_registry->getPackage($result[1], $result[0]);
  71652. $this->file_operations[$key] = false;
  71653. $pkginfoName = $this->pkginfo->getName();
  71654. $newChannel = $new->getChannel();
  71655. $newPackage = $new->getName();
  71656. $this->log(3, "file $data[0] was scheduled for removal from $pkginfoName but is owned by $newChannel/$newPackage, removal has been cancelled.");
  71657. }
  71658. }
  71659. }
  71660. break;
  71661. }
  71662. }
  71663. // }}}
  71664. $n = count($this->file_operations);
  71665. $this->log(2, "about to commit $n file operations for " . $this->pkginfo->getName());
  71666. $m = count($errors);
  71667. if ($m > 0) {
  71668. foreach ($errors as $error) {
  71669. if (!isset($this->_options['soft'])) {
  71670. $this->log(1, $error);
  71671. }
  71672. }
  71673. if (!isset($this->_options['ignore-errors'])) {
  71674. return false;
  71675. }
  71676. }
  71677. $this->_dirtree = array();
  71678. // {{{ really commit the transaction
  71679. foreach ($this->file_operations as $i => $tr) {
  71680. if (!$tr) {
  71681. // support removal of non-existing backups
  71682. continue;
  71683. }
  71684. list($type, $data) = $tr;
  71685. switch ($type) {
  71686. case 'backup':
  71687. if (!file_exists($data[0])) {
  71688. $this->file_operations[$i] = false;
  71689. break;
  71690. }
  71691. if (!@copy($data[0], $data[0] . '.bak')) {
  71692. $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] .
  71693. '.bak ' . error_get_last()["message"]);
  71694. return false;
  71695. }
  71696. $this->log(3, "+ backup $data[0] to $data[0].bak");
  71697. break;
  71698. case 'removebackup':
  71699. if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
  71700. unlink($data[0] . '.bak');
  71701. $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
  71702. }
  71703. break;
  71704. case 'rename':
  71705. $test = file_exists($data[1]) ? @unlink($data[1]) : null;
  71706. if (!$test && file_exists($data[1])) {
  71707. if ($data[2]) {
  71708. $extra = ', this extension must be installed manually. Rename to "' .
  71709. basename($data[1]) . '"';
  71710. } else {
  71711. $extra = '';
  71712. }
  71713. if (!isset($this->_options['soft'])) {
  71714. $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' .
  71715. $data[0] . $extra);
  71716. }
  71717. if (!isset($this->_options['ignore-errors'])) {
  71718. return false;
  71719. }
  71720. }
  71721. // permissions issues with rename - copy() is far superior
  71722. $perms = @fileperms($data[0]);
  71723. if (!@copy($data[0], $data[1])) {
  71724. $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] .
  71725. ' ' . error_get_last()["message"]);
  71726. return false;
  71727. }
  71728. // copy over permissions, otherwise they are lost
  71729. @chmod($data[1], $perms);
  71730. @unlink($data[0]);
  71731. $this->log(3, "+ mv $data[0] $data[1]");
  71732. break;
  71733. case 'chmod':
  71734. if (!@chmod($data[1], $data[0])) {
  71735. $this->log(1, 'Could not chmod ' . $data[1] . ' to ' .
  71736. decoct($data[0]) . ' ' . error_get_last()["message"]);
  71737. return false;
  71738. }
  71739. $octmode = decoct($data[0]);
  71740. $this->log(3, "+ chmod $octmode $data[1]");
  71741. break;
  71742. case 'delete':
  71743. if (file_exists($data[0])) {
  71744. if (!@unlink($data[0])) {
  71745. $this->log(1, 'Could not delete ' . $data[0] . ' ' .
  71746. error_get_last()["message"]);
  71747. return false;
  71748. }
  71749. $this->log(3, "+ rm $data[0]");
  71750. }
  71751. break;
  71752. case 'rmdir':
  71753. if (file_exists($data[0])) {
  71754. do {
  71755. $testme = opendir($data[0]);
  71756. while (false !== ($entry = readdir($testme))) {
  71757. if ($entry == '.' || $entry == '..') {
  71758. continue;
  71759. }
  71760. closedir($testme);
  71761. break 2; // this directory is not empty and can't be
  71762. // deleted
  71763. }
  71764. closedir($testme);
  71765. if (!@rmdir($data[0])) {
  71766. $this->log(1, 'Could not rmdir ' . $data[0] . ' ' .
  71767. error_get_last()["message"]);
  71768. return false;
  71769. }
  71770. $this->log(3, "+ rmdir $data[0]");
  71771. } while (false);
  71772. }
  71773. break;
  71774. case 'installed_as':
  71775. $this->pkginfo->setInstalledAs($data[0], $data[1]);
  71776. if (!isset($this->_dirtree[dirname($data[1])])) {
  71777. $this->_dirtree[dirname($data[1])] = true;
  71778. $this->pkginfo->setDirtree(dirname($data[1]));
  71779. while(!empty($data[3]) && dirname($data[3]) != $data[3] &&
  71780. $data[3] != '/' && $data[3] != '\\') {
  71781. $this->pkginfo->setDirtree($pp =
  71782. $this->_prependPath($data[3], $data[2]));
  71783. $this->_dirtree[$pp] = true;
  71784. $data[3] = dirname($data[3]);
  71785. }
  71786. }
  71787. break;
  71788. }
  71789. }
  71790. // }}}
  71791. $this->log(2, "successfully committed $n file operations");
  71792. $this->file_operations = array();
  71793. return true;
  71794. }
  71795. // }}}
  71796. // {{{ rollbackFileTransaction()
  71797. function rollbackFileTransaction()
  71798. {
  71799. $n = count($this->file_operations);
  71800. $this->log(2, "rolling back $n file operations");
  71801. foreach ($this->file_operations as $tr) {
  71802. list($type, $data) = $tr;
  71803. switch ($type) {
  71804. case 'backup':
  71805. if (file_exists($data[0] . '.bak')) {
  71806. if (file_exists($data[0] && is_writable($data[0]))) {
  71807. unlink($data[0]);
  71808. }
  71809. @copy($data[0] . '.bak', $data[0]);
  71810. $this->log(3, "+ restore $data[0] from $data[0].bak");
  71811. }
  71812. break;
  71813. case 'removebackup':
  71814. if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
  71815. unlink($data[0] . '.bak');
  71816. $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
  71817. }
  71818. break;
  71819. case 'rename':
  71820. @unlink($data[0]);
  71821. $this->log(3, "+ rm $data[0]");
  71822. break;
  71823. case 'mkdir':
  71824. @rmdir($data[0]);
  71825. $this->log(3, "+ rmdir $data[0]");
  71826. break;
  71827. case 'chmod':
  71828. break;
  71829. case 'delete':
  71830. break;
  71831. case 'installed_as':
  71832. $this->pkginfo->setInstalledAs($data[0], false);
  71833. break;
  71834. }
  71835. }
  71836. $this->pkginfo->resetDirtree();
  71837. $this->file_operations = array();
  71838. }
  71839. // }}}
  71840. // {{{ mkDirHier($dir)
  71841. function mkDirHier($dir)
  71842. {
  71843. $this->addFileOperation('mkdir', array($dir));
  71844. return parent::mkDirHier($dir);
  71845. }
  71846. // }}}
  71847. // {{{ _parsePackageXml()
  71848. function _parsePackageXml(&$descfile)
  71849. {
  71850. // Parse xml file -----------------------------------------------
  71851. $pkg = new PEAR_PackageFile($this->config, $this->debug);
  71852. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  71853. $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
  71854. PEAR::staticPopErrorHandling();
  71855. if (PEAR::isError($p)) {
  71856. if (is_array($p->getUserInfo())) {
  71857. foreach ($p->getUserInfo() as $err) {
  71858. $loglevel = $err['level'] == 'error' ? 0 : 1;
  71859. if (!isset($this->_options['soft'])) {
  71860. $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
  71861. }
  71862. }
  71863. }
  71864. return $this->raiseError('Installation failed: invalid package file');
  71865. }
  71866. $descfile = $p->getPackageFile();
  71867. return $p;
  71868. }
  71869. // }}}
  71870. /**
  71871. * Set the list of PEAR_Downloader_Package objects to allow more sane
  71872. * dependency validation
  71873. * @param array
  71874. */
  71875. function setDownloadedPackages(&$pkgs)
  71876. {
  71877. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  71878. $err = $this->analyzeDependencies($pkgs);
  71879. PEAR::popErrorHandling();
  71880. if (PEAR::isError($err)) {
  71881. return $err;
  71882. }
  71883. $this->_downloadedPackages = &$pkgs;
  71884. }
  71885. /**
  71886. * Set the list of PEAR_Downloader_Package objects to allow more sane
  71887. * dependency validation
  71888. * @param array
  71889. */
  71890. function setUninstallPackages(&$pkgs)
  71891. {
  71892. $this->_downloadedPackages = &$pkgs;
  71893. }
  71894. function getInstallPackages()
  71895. {
  71896. return $this->_downloadedPackages;
  71897. }
  71898. // {{{ install()
  71899. /**
  71900. * Installs the files within the package file specified.
  71901. *
  71902. * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
  71903. * or a pre-initialized packagefile object
  71904. * @param array $options
  71905. * recognized options:
  71906. * - installroot : optional prefix directory for installation
  71907. * - force : force installation
  71908. * - register-only : update registry but don't install files
  71909. * - upgrade : upgrade existing install
  71910. * - soft : fail silently
  71911. * - nodeps : ignore dependency conflicts/missing dependencies
  71912. * - alldeps : install all dependencies
  71913. * - onlyreqdeps : install only required dependencies
  71914. *
  71915. * @return array|PEAR_Error package info if successful
  71916. */
  71917. function install($pkgfile, $options = array())
  71918. {
  71919. $this->_options = $options;
  71920. $this->_registry = &$this->config->getRegistry();
  71921. if (is_object($pkgfile)) {
  71922. $dlpkg = &$pkgfile;
  71923. $pkg = $pkgfile->getPackageFile();
  71924. $pkgfile = $pkg->getArchiveFile();
  71925. $descfile = $pkg->getPackageFile();
  71926. } else {
  71927. $descfile = $pkgfile;
  71928. $pkg = $this->_parsePackageXml($descfile);
  71929. if (PEAR::isError($pkg)) {
  71930. return $pkg;
  71931. }
  71932. }
  71933. $tmpdir = dirname($descfile);
  71934. if (realpath($descfile) != realpath($pkgfile)) {
  71935. // Use the temp_dir since $descfile can contain the download dir path
  71936. $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net');
  71937. $tmpdir = System::mktemp('-d -t "' . $tmpdir . '"');
  71938. $tar = new Archive_Tar($pkgfile);
  71939. if (!$tar->extract($tmpdir)) {
  71940. return $this->raiseError("unable to unpack $pkgfile");
  71941. }
  71942. }
  71943. $pkgname = $pkg->getName();
  71944. $channel = $pkg->getChannel();
  71945. if (isset($options['installroot'])) {
  71946. $this->config->setInstallRoot($options['installroot']);
  71947. $this->_registry = &$this->config->getRegistry();
  71948. $installregistry = &$this->_registry;
  71949. $this->installroot = ''; // all done automagically now
  71950. $php_dir = $this->config->get('php_dir', null, $channel);
  71951. } else {
  71952. $this->config->setInstallRoot(false);
  71953. $this->_registry = &$this->config->getRegistry();
  71954. if (isset($this->_options['packagingroot'])) {
  71955. $regdir = $this->_prependPath(
  71956. $this->config->get('php_dir', null, 'pear.php.net'),
  71957. $this->_options['packagingroot']);
  71958. $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
  71959. if ($metadata_dir) {
  71960. $metadata_dir = $this->_prependPath(
  71961. $metadata_dir,
  71962. $this->_options['packagingroot']);
  71963. }
  71964. $packrootphp_dir = $this->_prependPath(
  71965. $this->config->get('php_dir', null, $channel),
  71966. $this->_options['packagingroot']);
  71967. $installregistry = new PEAR_Registry($regdir, false, false, $metadata_dir);
  71968. if (!$installregistry->channelExists($channel, true)) {
  71969. // we need to fake a channel-discover of this channel
  71970. $chanobj = $this->_registry->getChannel($channel, true);
  71971. $installregistry->addChannel($chanobj);
  71972. }
  71973. $php_dir = $packrootphp_dir;
  71974. } else {
  71975. $installregistry = &$this->_registry;
  71976. $php_dir = $this->config->get('php_dir', null, $channel);
  71977. }
  71978. $this->installroot = '';
  71979. }
  71980. // {{{ checks to do when not in "force" mode
  71981. if (empty($options['force']) &&
  71982. (file_exists($this->config->get('php_dir')) &&
  71983. is_dir($this->config->get('php_dir')))) {
  71984. $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
  71985. $instfilelist = $pkg->getInstallationFileList(true);
  71986. if (PEAR::isError($instfilelist)) {
  71987. return $instfilelist;
  71988. }
  71989. // ensure we have the most accurate registry
  71990. $installregistry->flushFileMap();
  71991. $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1');
  71992. if (PEAR::isError($test)) {
  71993. return $test;
  71994. }
  71995. if (sizeof($test)) {
  71996. $pkgs = $this->getInstallPackages();
  71997. $found = false;
  71998. foreach ($pkgs as $param) {
  71999. if ($pkg->isSubpackageOf($param)) {
  72000. $found = true;
  72001. break;
  72002. }
  72003. }
  72004. if ($found) {
  72005. // subpackages can conflict with earlier versions of parent packages
  72006. $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel());
  72007. $tmp = $test;
  72008. foreach ($tmp as $file => $info) {
  72009. if (is_array($info)) {
  72010. if (strtolower($info[1]) == strtolower($param->getPackage()) &&
  72011. strtolower($info[0]) == strtolower($param->getChannel())
  72012. ) {
  72013. if (isset($parentreg['filelist'][$file])) {
  72014. unset($parentreg['filelist'][$file]);
  72015. } else{
  72016. $pos = strpos($file, '/');
  72017. $basedir = substr($file, 0, $pos);
  72018. $file2 = substr($file, $pos + 1);
  72019. if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
  72020. && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
  72021. ) {
  72022. unset($parentreg['filelist'][$file2]);
  72023. }
  72024. }
  72025. unset($test[$file]);
  72026. }
  72027. } else {
  72028. if (strtolower($param->getChannel()) != 'pear.php.net') {
  72029. continue;
  72030. }
  72031. if (strtolower($info) == strtolower($param->getPackage())) {
  72032. if (isset($parentreg['filelist'][$file])) {
  72033. unset($parentreg['filelist'][$file]);
  72034. } else{
  72035. $pos = strpos($file, '/');
  72036. $basedir = substr($file, 0, $pos);
  72037. $file2 = substr($file, $pos + 1);
  72038. if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
  72039. && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
  72040. ) {
  72041. unset($parentreg['filelist'][$file2]);
  72042. }
  72043. }
  72044. unset($test[$file]);
  72045. }
  72046. }
  72047. }
  72048. $pfk = new PEAR_PackageFile($this->config);
  72049. $parentpkg = &$pfk->fromArray($parentreg);
  72050. $installregistry->updatePackage2($parentpkg);
  72051. }
  72052. if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) {
  72053. $tmp = $test;
  72054. foreach ($tmp as $file => $info) {
  72055. if (is_string($info)) {
  72056. // pear.php.net packages are always stored as strings
  72057. if (strtolower($info) == strtolower($param->getPackage())) {
  72058. // upgrading existing package
  72059. unset($test[$file]);
  72060. }
  72061. }
  72062. }
  72063. }
  72064. if (count($test)) {
  72065. $msg = "$channel/$pkgname: conflicting files found:\n";
  72066. $longest = max(array_map("strlen", array_keys($test)));
  72067. $fmt = "%${longest}s (%s)\n";
  72068. foreach ($test as $file => $info) {
  72069. if (!is_array($info)) {
  72070. $info = array('pear.php.net', $info);
  72071. }
  72072. $info = $info[0] . '/' . $info[1];
  72073. $msg .= sprintf($fmt, $file, $info);
  72074. }
  72075. if (!isset($options['ignore-errors'])) {
  72076. return $this->raiseError($msg);
  72077. }
  72078. if (!isset($options['soft'])) {
  72079. $this->log(0, "WARNING: $msg");
  72080. }
  72081. }
  72082. }
  72083. }
  72084. // }}}
  72085. $this->startFileTransaction();
  72086. $usechannel = $channel;
  72087. if ($channel == 'pecl.php.net') {
  72088. $test = $installregistry->packageExists($pkgname, $channel);
  72089. if (!$test) {
  72090. $test = $installregistry->packageExists($pkgname, 'pear.php.net');
  72091. $usechannel = 'pear.php.net';
  72092. }
  72093. } else {
  72094. $test = $installregistry->packageExists($pkgname, $channel);
  72095. }
  72096. if (empty($options['upgrade']) && empty($options['soft'])) {
  72097. // checks to do only when installing new packages
  72098. if (empty($options['force']) && $test) {
  72099. return $this->raiseError("$channel/$pkgname is already installed");
  72100. }
  72101. } else {
  72102. // Upgrade
  72103. if ($test) {
  72104. $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel);
  72105. $v2 = $pkg->getVersion();
  72106. $cmp = version_compare("$v1", "$v2", 'gt');
  72107. if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
  72108. return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
  72109. }
  72110. }
  72111. }
  72112. // Do cleanups for upgrade and install, remove old release's files first
  72113. if ($test && empty($options['register-only'])) {
  72114. // when upgrading, remove old release's files first:
  72115. if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel,
  72116. true))) {
  72117. if (!isset($options['ignore-errors'])) {
  72118. return $this->raiseError($err);
  72119. }
  72120. if (!isset($options['soft'])) {
  72121. $this->log(0, 'WARNING: ' . $err->getMessage());
  72122. }
  72123. } else {
  72124. $backedup = $err;
  72125. }
  72126. }
  72127. // {{{ Copy files to dest dir ---------------------------------------
  72128. // info from the package it self we want to access from _installFile
  72129. $this->pkginfo = &$pkg;
  72130. // used to determine whether we should build any C code
  72131. $this->source_files = 0;
  72132. $savechannel = $this->config->get('default_channel');
  72133. if (empty($options['register-only']) && !is_dir($php_dir)) {
  72134. if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) {
  72135. return $this->raiseError("no installation destination directory '$php_dir'\n");
  72136. }
  72137. }
  72138. if (substr($pkgfile, -4) != '.xml') {
  72139. $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion();
  72140. }
  72141. $this->configSet('default_channel', $channel);
  72142. // {{{ install files
  72143. $ver = $pkg->getPackagexmlVersion();
  72144. if (version_compare($ver, '2.0', '>=')) {
  72145. $filelist = $pkg->getInstallationFilelist();
  72146. } else {
  72147. $filelist = $pkg->getFileList();
  72148. }
  72149. if (PEAR::isError($filelist)) {
  72150. return $filelist;
  72151. }
  72152. $p = &$installregistry->getPackage($pkgname, $channel);
  72153. $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false;
  72154. $pkg->resetFilelist();
  72155. $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(),
  72156. 'version', $pkg->getChannel()));
  72157. foreach ($filelist as $file => $atts) {
  72158. $this->expectError(PEAR_INSTALLER_FAILED);
  72159. if ($pkg->getPackagexmlVersion() == '1.0') {
  72160. $res = $this->_installFile($file, $atts, $tmpdir, $options);
  72161. } else {
  72162. $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options);
  72163. }
  72164. $this->popExpect();
  72165. if (PEAR::isError($res)) {
  72166. if (empty($options['ignore-errors'])) {
  72167. $this->rollbackFileTransaction();
  72168. if ($res->getMessage() == "file does not exist") {
  72169. $this->raiseError("file $file in package.xml does not exist");
  72170. }
  72171. return $this->raiseError($res);
  72172. }
  72173. if (!isset($options['soft'])) {
  72174. $this->log(0, "Warning: " . $res->getMessage());
  72175. }
  72176. }
  72177. $real = isset($atts['attribs']) ? $atts['attribs'] : $atts;
  72178. if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') {
  72179. // Register files that were installed
  72180. $pkg->installedFile($file, $atts);
  72181. }
  72182. }
  72183. // }}}
  72184. // {{{ compile and install source files
  72185. if ($this->source_files > 0 && empty($options['nobuild'])) {
  72186. $configureoptions = empty($options['configureoptions']) ? '' : $options['configureoptions'];
  72187. if (PEAR::isError($err =
  72188. $this->_compileSourceFiles($savechannel, $pkg, $configureoptions))) {
  72189. return $err;
  72190. }
  72191. }
  72192. // }}}
  72193. if (isset($backedup)) {
  72194. $this->_removeBackups($backedup);
  72195. }
  72196. if (!$this->commitFileTransaction()) {
  72197. $this->rollbackFileTransaction();
  72198. $this->configSet('default_channel', $savechannel);
  72199. return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
  72200. }
  72201. // }}}
  72202. $ret = false;
  72203. $installphase = 'install';
  72204. $oldversion = false;
  72205. // {{{ Register that the package is installed -----------------------
  72206. if (empty($options['upgrade'])) {
  72207. // if 'force' is used, replace the info in registry
  72208. $usechannel = $channel;
  72209. if ($channel == 'pecl.php.net') {
  72210. $test = $installregistry->packageExists($pkgname, $channel);
  72211. if (!$test) {
  72212. $test = $installregistry->packageExists($pkgname, 'pear.php.net');
  72213. $usechannel = 'pear.php.net';
  72214. }
  72215. } else {
  72216. $test = $installregistry->packageExists($pkgname, $channel);
  72217. }
  72218. if (!empty($options['force']) && $test) {
  72219. $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel);
  72220. $installregistry->deletePackage($pkgname, $usechannel);
  72221. }
  72222. $ret = $installregistry->addPackage2($pkg);
  72223. } else {
  72224. if ($dirtree) {
  72225. $this->startFileTransaction();
  72226. // attempt to delete empty directories
  72227. uksort($dirtree, array($this, '_sortDirs'));
  72228. foreach($dirtree as $dir => $notused) {
  72229. $this->addFileOperation('rmdir', array($dir));
  72230. }
  72231. $this->commitFileTransaction();
  72232. }
  72233. $usechannel = $channel;
  72234. if ($channel == 'pecl.php.net') {
  72235. $test = $installregistry->packageExists($pkgname, $channel);
  72236. if (!$test) {
  72237. $test = $installregistry->packageExists($pkgname, 'pear.php.net');
  72238. $usechannel = 'pear.php.net';
  72239. }
  72240. } else {
  72241. $test = $installregistry->packageExists($pkgname, $channel);
  72242. }
  72243. // new: upgrade installs a package if it isn't installed
  72244. if (!$test) {
  72245. $ret = $installregistry->addPackage2($pkg);
  72246. } else {
  72247. if ($usechannel != $channel) {
  72248. $installregistry->deletePackage($pkgname, $usechannel);
  72249. $ret = $installregistry->addPackage2($pkg);
  72250. } else {
  72251. $ret = $installregistry->updatePackage2($pkg);
  72252. }
  72253. $installphase = 'upgrade';
  72254. }
  72255. }
  72256. if (!$ret) {
  72257. $this->configSet('default_channel', $savechannel);
  72258. return $this->raiseError("Adding package $channel/$pkgname to registry failed");
  72259. }
  72260. // }}}
  72261. $this->configSet('default_channel', $savechannel);
  72262. if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist
  72263. if (PEAR_Task_Common::hasPostinstallTasks()) {
  72264. PEAR_Task_Common::runPostinstallTasks($installphase);
  72265. }
  72266. }
  72267. return $pkg->toArray(true);
  72268. }
  72269. // }}}
  72270. // {{{ _compileSourceFiles()
  72271. /**
  72272. * @param string
  72273. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  72274. * @param mixed[] $configureoptions
  72275. */
  72276. function _compileSourceFiles($savechannel, &$filelist, $configureoptions)
  72277. {
  72278. require_once 'phar://go-pear.phar/' . 'PEAR/Builder.php';
  72279. $this->log(1, "$this->source_files source files, building");
  72280. $bob = new PEAR_Builder($configureoptions, $this->ui);
  72281. $bob->debug = $this->debug;
  72282. $built = $bob->build($filelist, array(&$this, '_buildCallback'));
  72283. if (PEAR::isError($built)) {
  72284. $this->rollbackFileTransaction();
  72285. $this->configSet('default_channel', $savechannel);
  72286. return $built;
  72287. }
  72288. $this->log(1, "\nBuild process completed successfully");
  72289. foreach ($built as $ext) {
  72290. $bn = basename($ext['file']);
  72291. list($_ext_name, $_ext_suff) = explode('.', $bn);
  72292. if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
  72293. if (extension_loaded($_ext_name)) {
  72294. $this->raiseError("Extension '$_ext_name' already loaded. " .
  72295. 'Please unload it in your php.ini file ' .
  72296. 'prior to install or upgrade');
  72297. }
  72298. $role = 'ext';
  72299. } else {
  72300. $role = 'src';
  72301. }
  72302. $dest = $ext['dest'];
  72303. $packagingroot = '';
  72304. if (isset($this->_options['packagingroot'])) {
  72305. $packagingroot = $this->_options['packagingroot'];
  72306. }
  72307. $copyto = $this->_prependPath($dest, $packagingroot);
  72308. $extra = $copyto != $dest ? " as '$copyto'" : '';
  72309. $this->log(1, "Installing '$dest'$extra");
  72310. $copydir = dirname($copyto);
  72311. // pretty much nothing happens if we are only registering the install
  72312. if (empty($this->_options['register-only'])) {
  72313. if (!file_exists($copydir) || !is_dir($copydir)) {
  72314. if (!$this->mkDirHier($copydir)) {
  72315. return $this->raiseError("failed to mkdir $copydir",
  72316. PEAR_INSTALLER_FAILED);
  72317. }
  72318. $this->log(3, "+ mkdir $copydir");
  72319. }
  72320. if (!@copy($ext['file'], $copyto)) {
  72321. return $this->raiseError(
  72322. "failed to write $copyto (" . error_get_last()["message"] . ")",
  72323. PEAR_INSTALLER_FAILED);
  72324. }
  72325. $this->log(3, "+ cp $ext[file] $copyto");
  72326. $this->addFileOperation('rename', array($ext['file'], $copyto));
  72327. if (!OS_WINDOWS) {
  72328. $mode = 0666 & ~(int)octdec($this->config->get('umask'));
  72329. $this->addFileOperation('chmod', array($mode, $copyto));
  72330. if (!@chmod($copyto, $mode)) {
  72331. $this->log(0, "failed to change mode of $copyto (" .
  72332. error_get_last()["message"] . ")");
  72333. }
  72334. }
  72335. }
  72336. $data = array(
  72337. 'role' => $role,
  72338. 'name' => $bn,
  72339. 'installed_as' => $dest,
  72340. 'php_api' => $ext['php_api'],
  72341. 'zend_mod_api' => $ext['zend_mod_api'],
  72342. 'zend_ext_api' => $ext['zend_ext_api'],
  72343. );
  72344. if ($filelist->getPackageXmlVersion() == '1.0') {
  72345. $filelist->installedFile($bn, $data);
  72346. } else {
  72347. $filelist->installedFile($bn, array('attribs' => $data));
  72348. }
  72349. }
  72350. }
  72351. // }}}
  72352. function &getUninstallPackages()
  72353. {
  72354. return $this->_downloadedPackages;
  72355. }
  72356. // {{{ uninstall()
  72357. /**
  72358. * Uninstall a package
  72359. *
  72360. * This method removes all files installed by the application, and then
  72361. * removes any empty directories.
  72362. * @param string package name
  72363. * @param array Command-line options. Possibilities include:
  72364. *
  72365. * - installroot: base installation dir, if not the default
  72366. * - register-only : update registry but don't remove files
  72367. * - nodeps: do not process dependencies of other packages to ensure
  72368. * uninstallation does not break things
  72369. */
  72370. function uninstall($package, $options = array())
  72371. {
  72372. $installRoot = isset($options['installroot']) ? $options['installroot'] : '';
  72373. $this->config->setInstallRoot($installRoot);
  72374. $this->installroot = '';
  72375. $this->_registry = &$this->config->getRegistry();
  72376. if (is_object($package)) {
  72377. $channel = $package->getChannel();
  72378. $pkg = $package;
  72379. $package = $pkg->getPackage();
  72380. } else {
  72381. $pkg = false;
  72382. $info = $this->_registry->parsePackageName($package,
  72383. $this->config->get('default_channel'));
  72384. $channel = $info['channel'];
  72385. $package = $info['package'];
  72386. }
  72387. $savechannel = $this->config->get('default_channel');
  72388. $this->configSet('default_channel', $channel);
  72389. if (!is_object($pkg)) {
  72390. $pkg = $this->_registry->getPackage($package, $channel);
  72391. }
  72392. if (!$pkg) {
  72393. $this->configSet('default_channel', $savechannel);
  72394. return $this->raiseError($this->_registry->parsedPackageNameToString(
  72395. array(
  72396. 'channel' => $channel,
  72397. 'package' => $package
  72398. ), true) . ' not installed');
  72399. }
  72400. if ($pkg->getInstalledBinary()) {
  72401. // this is just an alias for a binary package
  72402. return $this->_registry->deletePackage($package, $channel);
  72403. }
  72404. $filelist = $pkg->getFilelist();
  72405. PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  72406. if (!class_exists('PEAR_Dependency2')) {
  72407. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  72408. }
  72409. $depchecker = new PEAR_Dependency2($this->config, $options,
  72410. array('channel' => $channel, 'package' => $package),
  72411. PEAR_VALIDATE_UNINSTALLING);
  72412. $e = $depchecker->validatePackageUninstall($this);
  72413. PEAR::staticPopErrorHandling();
  72414. if (PEAR::isError($e)) {
  72415. if (!isset($options['ignore-errors'])) {
  72416. return $this->raiseError($e);
  72417. }
  72418. if (!isset($options['soft'])) {
  72419. $this->log(0, 'WARNING: ' . $e->getMessage());
  72420. }
  72421. } elseif (is_array($e)) {
  72422. if (!isset($options['soft'])) {
  72423. $this->log(0, $e[0]);
  72424. }
  72425. }
  72426. $this->pkginfo = &$pkg;
  72427. // pretty much nothing happens if we are only registering the uninstall
  72428. if (empty($options['register-only'])) {
  72429. // {{{ Delete the files
  72430. $this->startFileTransaction();
  72431. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  72432. if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) {
  72433. PEAR::popErrorHandling();
  72434. $this->rollbackFileTransaction();
  72435. $this->configSet('default_channel', $savechannel);
  72436. if (!isset($options['ignore-errors'])) {
  72437. return $this->raiseError($err);
  72438. }
  72439. if (!isset($options['soft'])) {
  72440. $this->log(0, 'WARNING: ' . $err->getMessage());
  72441. }
  72442. } else {
  72443. PEAR::popErrorHandling();
  72444. }
  72445. if (!$this->commitFileTransaction()) {
  72446. $this->rollbackFileTransaction();
  72447. if (!isset($options['ignore-errors'])) {
  72448. return $this->raiseError("uninstall failed");
  72449. }
  72450. if (!isset($options['soft'])) {
  72451. $this->log(0, 'WARNING: uninstall failed');
  72452. }
  72453. } else {
  72454. $this->startFileTransaction();
  72455. $dirtree = $pkg->getDirTree();
  72456. if ($dirtree === false) {
  72457. $this->configSet('default_channel', $savechannel);
  72458. return $this->_registry->deletePackage($package, $channel);
  72459. }
  72460. // attempt to delete empty directories
  72461. uksort($dirtree, array($this, '_sortDirs'));
  72462. foreach($dirtree as $dir => $notused) {
  72463. $this->addFileOperation('rmdir', array($dir));
  72464. }
  72465. if (!$this->commitFileTransaction()) {
  72466. $this->rollbackFileTransaction();
  72467. if (!isset($options['ignore-errors'])) {
  72468. return $this->raiseError("uninstall failed");
  72469. }
  72470. if (!isset($options['soft'])) {
  72471. $this->log(0, 'WARNING: uninstall failed');
  72472. }
  72473. }
  72474. }
  72475. // }}}
  72476. }
  72477. $this->configSet('default_channel', $savechannel);
  72478. // Register that the package is no longer installed
  72479. return $this->_registry->deletePackage($package, $channel);
  72480. }
  72481. /**
  72482. * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  72483. *
  72484. * It also removes duplicate dependencies
  72485. * @param array an array of PEAR_PackageFile_v[1/2] objects
  72486. * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
  72487. */
  72488. function sortPackagesForUninstall(&$packages)
  72489. {
  72490. $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config);
  72491. if (PEAR::isError($this->_dependencyDB)) {
  72492. return $this->_dependencyDB;
  72493. }
  72494. usort($packages, array(&$this, '_sortUninstall'));
  72495. }
  72496. function _sortUninstall($a, $b)
  72497. {
  72498. if (!$a->getDeps() && !$b->getDeps()) {
  72499. return 0; // neither package has dependencies, order is insignificant
  72500. }
  72501. if ($a->getDeps() && !$b->getDeps()) {
  72502. return -1; // $a must be installed after $b because $a has dependencies
  72503. }
  72504. if (!$a->getDeps() && $b->getDeps()) {
  72505. return 1; // $b must be installed after $a because $b has dependencies
  72506. }
  72507. // both packages have dependencies
  72508. if ($this->_dependencyDB->dependsOn($a, $b)) {
  72509. return -1;
  72510. }
  72511. if ($this->_dependencyDB->dependsOn($b, $a)) {
  72512. return 1;
  72513. }
  72514. return 0;
  72515. }
  72516. // }}}
  72517. // {{{ _sortDirs()
  72518. function _sortDirs($a, $b)
  72519. {
  72520. if (strnatcmp($a, $b) == -1) return 1;
  72521. if (strnatcmp($a, $b) == 1) return -1;
  72522. return 0;
  72523. }
  72524. // }}}
  72525. // {{{ _buildCallback()
  72526. function _buildCallback($what, $data)
  72527. {
  72528. if (($what == 'cmdoutput' && $this->debug > 1) ||
  72529. ($what == 'output' && $this->debug > 0)) {
  72530. $this->ui->outputData(rtrim($data), 'build');
  72531. }
  72532. }
  72533. // }}}
  72534. }
  72535. <?php
  72536. /**
  72537. * PEAR_Installer_Role
  72538. *
  72539. * PHP versions 4 and 5
  72540. *
  72541. * @category pear
  72542. * @package PEAR
  72543. * @author Greg Beaver <cellog@php.net>
  72544. * @copyright 1997-2009 The Authors
  72545. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72546. * @link http://pear.php.net/package/PEAR
  72547. * @since File available since Release 1.4.0a1
  72548. */
  72549. /**
  72550. * base class for installer roles
  72551. */
  72552. require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role/Common.php';
  72553. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  72554. /**
  72555. * @category pear
  72556. * @package PEAR
  72557. * @author Greg Beaver <cellog@php.net>
  72558. * @copyright 1997-2009 The Authors
  72559. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72560. * @version Release: 1.10.10
  72561. * @link http://pear.php.net/package/PEAR
  72562. * @since Class available since Release 1.4.0a1
  72563. */
  72564. class PEAR_Installer_Role
  72565. {
  72566. /**
  72567. * Set up any additional configuration variables that file roles require
  72568. *
  72569. * Never call this directly, it is called by the PEAR_Config constructor
  72570. * @param PEAR_Config
  72571. */
  72572. public static function initializeConfig(&$config)
  72573. {
  72574. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  72575. PEAR_Installer_Role::registerRoles();
  72576. }
  72577. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) {
  72578. if (!$info['config_vars']) {
  72579. continue;
  72580. }
  72581. $config->_addConfigVars($class, $info['config_vars']);
  72582. }
  72583. }
  72584. /**
  72585. * @param PEAR_PackageFile_v2
  72586. * @param string role name
  72587. * @param PEAR_Config
  72588. * @return PEAR_Installer_Role_Common
  72589. */
  72590. public static function &factory($pkg, $role, &$config)
  72591. {
  72592. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  72593. PEAR_Installer_Role::registerRoles();
  72594. }
  72595. if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
  72596. $a = false;
  72597. return $a;
  72598. }
  72599. $a = 'PEAR_Installer_Role_' . ucfirst($role);
  72600. if (!class_exists($a)) {
  72601. require_once 'phar://go-pear.phar/' . str_replace('_', '/', $a) . '.php';
  72602. }
  72603. $b = new $a($config);
  72604. return $b;
  72605. }
  72606. /**
  72607. * Get a list of file roles that are valid for the particular release type.
  72608. *
  72609. * For instance, src files serve no purpose in regular php releases.
  72610. * @param string
  72611. * @param bool clear cache
  72612. * @return array
  72613. */
  72614. public static function getValidRoles($release, $clear = false)
  72615. {
  72616. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  72617. PEAR_Installer_Role::registerRoles();
  72618. }
  72619. static $ret = array();
  72620. if ($clear) {
  72621. $ret = array();
  72622. }
  72623. if (isset($ret[$release])) {
  72624. return $ret[$release];
  72625. }
  72626. $ret[$release] = array();
  72627. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  72628. if (in_array($release, $okreleases['releasetypes'])) {
  72629. $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  72630. }
  72631. }
  72632. return $ret[$release];
  72633. }
  72634. /**
  72635. * Get a list of roles that require their files to be installed
  72636. *
  72637. * Most roles must be installed, but src and package roles, for instance
  72638. * are pseudo-roles. src files are compiled into a new extension. Package
  72639. * roles are actually fully bundled releases of a package
  72640. * @param bool clear cache
  72641. * @return array
  72642. */
  72643. public static function getInstallableRoles($clear = false)
  72644. {
  72645. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  72646. PEAR_Installer_Role::registerRoles();
  72647. }
  72648. static $ret;
  72649. if ($clear) {
  72650. unset($ret);
  72651. }
  72652. if (isset($ret)) {
  72653. return $ret;
  72654. }
  72655. $ret = array();
  72656. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  72657. if ($okreleases['installable']) {
  72658. $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  72659. }
  72660. }
  72661. return $ret;
  72662. }
  72663. /**
  72664. * Return an array of roles that are affected by the baseinstalldir attribute
  72665. *
  72666. * Most roles ignore this attribute, and instead install directly into:
  72667. * PackageName/filepath
  72668. * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php
  72669. * @param bool clear cache
  72670. * @return array
  72671. */
  72672. public static function getBaseinstallRoles($clear = false)
  72673. {
  72674. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  72675. PEAR_Installer_Role::registerRoles();
  72676. }
  72677. static $ret;
  72678. if ($clear) {
  72679. unset($ret);
  72680. }
  72681. if (isset($ret)) {
  72682. return $ret;
  72683. }
  72684. $ret = array();
  72685. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  72686. if ($okreleases['honorsbaseinstall']) {
  72687. $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  72688. }
  72689. }
  72690. return $ret;
  72691. }
  72692. /**
  72693. * Return an array of file roles that should be analyzed for PHP content at package time,
  72694. * like the "php" role.
  72695. * @param bool clear cache
  72696. * @return array
  72697. */
  72698. public static function getPhpRoles($clear = false)
  72699. {
  72700. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
  72701. PEAR_Installer_Role::registerRoles();
  72702. }
  72703. static $ret;
  72704. if ($clear) {
  72705. unset($ret);
  72706. }
  72707. if (isset($ret)) {
  72708. return $ret;
  72709. }
  72710. $ret = array();
  72711. foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
  72712. if ($okreleases['phpfile']) {
  72713. $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
  72714. }
  72715. }
  72716. return $ret;
  72717. }
  72718. /**
  72719. * Scan through the Command directory looking for classes
  72720. * and see what commands they implement.
  72721. * @param string which directory to look for classes, defaults to
  72722. * the Installer/Roles subdirectory of
  72723. * the directory from where this file (__FILE__) is
  72724. * included.
  72725. *
  72726. * @return bool TRUE on success, a PEAR error on failure
  72727. */
  72728. public static function registerRoles($dir = null)
  72729. {
  72730. $GLOBALS['_PEAR_INSTALLER_ROLES'] = array();
  72731. $parser = new PEAR_XMLParser;
  72732. if ($dir === null) {
  72733. $dir = dirname(__FILE__) . '/Role';
  72734. }
  72735. if (!file_exists($dir) || !is_dir($dir)) {
  72736. return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory");
  72737. }
  72738. $dp = @opendir($dir);
  72739. if (empty($dp)) {
  72740. return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg");
  72741. }
  72742. while ($entry = readdir($dp)) {
  72743. if ($entry[0] == '.' || substr($entry, -4) != '.xml') {
  72744. continue;
  72745. }
  72746. $class = "PEAR_Installer_Role_".substr($entry, 0, -4);
  72747. // List of roles
  72748. if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) {
  72749. $file = "$dir/$entry";
  72750. $parser->parse(file_get_contents($file));
  72751. $data = $parser->getData();
  72752. if (!is_array($data['releasetypes'])) {
  72753. $data['releasetypes'] = array($data['releasetypes']);
  72754. }
  72755. $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data;
  72756. }
  72757. }
  72758. closedir($dp);
  72759. ksort($GLOBALS['_PEAR_INSTALLER_ROLES']);
  72760. PEAR_Installer_Role::getBaseinstallRoles(true);
  72761. PEAR_Installer_Role::getInstallableRoles(true);
  72762. PEAR_Installer_Role::getPhpRoles(true);
  72763. PEAR_Installer_Role::getValidRoles('****', true);
  72764. return true;
  72765. }
  72766. }<?php
  72767. /**
  72768. * Base class for all installation roles.
  72769. *
  72770. * PHP versions 4 and 5
  72771. *
  72772. * @category pear
  72773. * @package PEAR
  72774. * @author Greg Beaver <cellog@php.net>
  72775. * @copyright 1997-2006 The PHP Group
  72776. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72777. * @link http://pear.php.net/package/PEAR
  72778. * @since File available since Release 1.4.0a1
  72779. */
  72780. /**
  72781. * Base class for all installation roles.
  72782. *
  72783. * This class allows extensibility of file roles. Packages with complex
  72784. * customization can now provide custom file roles along with the possibility of
  72785. * adding configuration values to match.
  72786. * @category pear
  72787. * @package PEAR
  72788. * @author Greg Beaver <cellog@php.net>
  72789. * @copyright 1997-2006 The PHP Group
  72790. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72791. * @version Release: 1.10.10
  72792. * @link http://pear.php.net/package/PEAR
  72793. * @since Class available since Release 1.4.0a1
  72794. */
  72795. class PEAR_Installer_Role_Common
  72796. {
  72797. /**
  72798. * @var PEAR_Config
  72799. * @access protected
  72800. */
  72801. var $config;
  72802. /**
  72803. * @param PEAR_Config
  72804. */
  72805. function __construct(&$config)
  72806. {
  72807. $this->config = $config;
  72808. }
  72809. /**
  72810. * Retrieve configuration information about a file role from its XML info
  72811. *
  72812. * @param string $role Role Classname, as in "PEAR_Installer_Role_Data"
  72813. * @return array
  72814. */
  72815. function getInfo($role)
  72816. {
  72817. if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) {
  72818. return PEAR::raiseError('Unknown Role class: "' . $role . '"');
  72819. }
  72820. return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role];
  72821. }
  72822. /**
  72823. * This is called for each file to set up the directories and files
  72824. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  72825. * @param array attributes from the <file> tag
  72826. * @param string file name
  72827. * @return array an array consisting of:
  72828. *
  72829. * 1 the original, pre-baseinstalldir installation directory
  72830. * 2 the final installation directory
  72831. * 3 the full path to the final location of the file
  72832. * 4 the location of the pre-installation file
  72833. */
  72834. function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
  72835. {
  72836. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  72837. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  72838. if (PEAR::isError($roleInfo)) {
  72839. return $roleInfo;
  72840. }
  72841. if (!$roleInfo['locationconfig']) {
  72842. return false;
  72843. }
  72844. if ($roleInfo['honorsbaseinstall']) {
  72845. $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer,
  72846. $pkg->getChannel());
  72847. if (!empty($atts['baseinstalldir'])) {
  72848. $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
  72849. }
  72850. } elseif ($roleInfo['unusualbaseinstall']) {
  72851. $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
  72852. $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
  72853. if (!empty($atts['baseinstalldir'])) {
  72854. $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
  72855. }
  72856. } else {
  72857. $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
  72858. $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
  72859. }
  72860. if (dirname($file) != '.' && empty($atts['install-as'])) {
  72861. $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
  72862. }
  72863. if (empty($atts['install-as'])) {
  72864. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
  72865. } else {
  72866. $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
  72867. }
  72868. $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
  72869. // Clean up the DIRECTORY_SEPARATOR mess
  72870. $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  72871. list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
  72872. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR,
  72873. DIRECTORY_SEPARATOR),
  72874. array($dest_dir, $dest_file, $orig_file));
  72875. return array($save_destdir, $dest_dir, $dest_file, $orig_file);
  72876. }
  72877. /**
  72878. * Get the name of the configuration variable that specifies the location of this file
  72879. * @return string|false
  72880. */
  72881. function getLocationConfig()
  72882. {
  72883. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  72884. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  72885. if (PEAR::isError($roleInfo)) {
  72886. return $roleInfo;
  72887. }
  72888. return $roleInfo['locationconfig'];
  72889. }
  72890. /**
  72891. * Do any unusual setup here
  72892. * @param PEAR_Installer
  72893. * @param PEAR_PackageFile_v2
  72894. * @param array file attributes
  72895. * @param string file name
  72896. */
  72897. function setup(&$installer, $pkg, $atts, $file)
  72898. {
  72899. }
  72900. function isExecutable()
  72901. {
  72902. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  72903. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  72904. if (PEAR::isError($roleInfo)) {
  72905. return $roleInfo;
  72906. }
  72907. return $roleInfo['executable'];
  72908. }
  72909. function isInstallable()
  72910. {
  72911. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  72912. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  72913. if (PEAR::isError($roleInfo)) {
  72914. return $roleInfo;
  72915. }
  72916. return $roleInfo['installable'];
  72917. }
  72918. function isExtension()
  72919. {
  72920. $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
  72921. ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
  72922. if (PEAR::isError($roleInfo)) {
  72923. return $roleInfo;
  72924. }
  72925. return $roleInfo['phpextension'];
  72926. }
  72927. }
  72928. ?>
  72929. <?php
  72930. /**
  72931. * PEAR_Installer_Role_Data
  72932. *
  72933. * PHP versions 4 and 5
  72934. *
  72935. * @category pear
  72936. * @package PEAR
  72937. * @author Greg Beaver <cellog@php.net>
  72938. * @copyright 1997-2009 The Authors
  72939. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72940. * @link http://pear.php.net/package/PEAR
  72941. * @since File available since Release 1.4.0a1
  72942. */
  72943. /**
  72944. * @category pear
  72945. * @package PEAR
  72946. * @author Greg Beaver <cellog@php.net>
  72947. * @copyright 1997-2009 The Authors
  72948. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72949. * @version Release: 1.10.10
  72950. * @link http://pear.php.net/package/PEAR
  72951. * @since Class available since Release 1.4.0a1
  72952. */
  72953. class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {}
  72954. ?><role version="1.0">
  72955. <releasetypes>php</releasetypes>
  72956. <releasetypes>extsrc</releasetypes>
  72957. <releasetypes>extbin</releasetypes>
  72958. <releasetypes>zendextsrc</releasetypes>
  72959. <releasetypes>zendextbin</releasetypes>
  72960. <installable>1</installable>
  72961. <locationconfig>data_dir</locationconfig>
  72962. <honorsbaseinstall />
  72963. <unusualbaseinstall />
  72964. <phpfile />
  72965. <executable />
  72966. <phpextension />
  72967. <config_vars />
  72968. </role><?php
  72969. /**
  72970. * PEAR_Installer_Role_Doc
  72971. *
  72972. * PHP versions 4 and 5
  72973. *
  72974. * @category pear
  72975. * @package PEAR
  72976. * @author Greg Beaver <cellog@php.net>
  72977. * @copyright 1997-2009 The Authors
  72978. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72979. * @link http://pear.php.net/package/PEAR
  72980. * @since File available since Release 1.4.0a1
  72981. */
  72982. /**
  72983. * @category pear
  72984. * @package PEAR
  72985. * @author Greg Beaver <cellog@php.net>
  72986. * @copyright 1997-2009 The Authors
  72987. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  72988. * @version Release: 1.10.10
  72989. * @link http://pear.php.net/package/PEAR
  72990. * @since Class available since Release 1.4.0a1
  72991. */
  72992. class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {}
  72993. ?><role version="1.0">
  72994. <releasetypes>php</releasetypes>
  72995. <releasetypes>extsrc</releasetypes>
  72996. <releasetypes>extbin</releasetypes>
  72997. <releasetypes>zendextsrc</releasetypes>
  72998. <releasetypes>zendextbin</releasetypes>
  72999. <installable>1</installable>
  73000. <locationconfig>doc_dir</locationconfig>
  73001. <honorsbaseinstall />
  73002. <unusualbaseinstall />
  73003. <phpfile />
  73004. <executable />
  73005. <phpextension />
  73006. <config_vars />
  73007. </role><?php
  73008. /**
  73009. * PEAR_Installer_Role_Php
  73010. *
  73011. * PHP versions 4 and 5
  73012. *
  73013. * @category pear
  73014. * @package PEAR
  73015. * @author Greg Beaver <cellog@php.net>
  73016. * @copyright 1997-2009 The Authors
  73017. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73018. * @link http://pear.php.net/package/PEAR
  73019. * @since File available since Release 1.4.0a1
  73020. */
  73021. /**
  73022. * @category pear
  73023. * @package PEAR
  73024. * @author Greg Beaver <cellog@php.net>
  73025. * @copyright 1997-2009 The Authors
  73026. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73027. * @version Release: 1.10.10
  73028. * @link http://pear.php.net/package/PEAR
  73029. * @since Class available since Release 1.4.0a1
  73030. */
  73031. class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {}
  73032. ?><role version="1.0">
  73033. <releasetypes>php</releasetypes>
  73034. <releasetypes>extsrc</releasetypes>
  73035. <releasetypes>extbin</releasetypes>
  73036. <releasetypes>zendextsrc</releasetypes>
  73037. <releasetypes>zendextbin</releasetypes>
  73038. <installable>1</installable>
  73039. <locationconfig>php_dir</locationconfig>
  73040. <honorsbaseinstall>1</honorsbaseinstall>
  73041. <unusualbaseinstall />
  73042. <phpfile>1</phpfile>
  73043. <executable />
  73044. <phpextension />
  73045. <config_vars />
  73046. </role><?php
  73047. /**
  73048. * PEAR_Installer_Role_Script
  73049. *
  73050. * PHP versions 4 and 5
  73051. *
  73052. * @category pear
  73053. * @package PEAR
  73054. * @author Greg Beaver <cellog@php.net>
  73055. * @copyright 1997-2009 The Authors
  73056. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73057. * @link http://pear.php.net/package/PEAR
  73058. * @since File available since Release 1.4.0a1
  73059. */
  73060. /**
  73061. * @category pear
  73062. * @package PEAR
  73063. * @author Greg Beaver <cellog@php.net>
  73064. * @copyright 1997-2009 The Authors
  73065. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73066. * @version Release: 1.10.10
  73067. * @link http://pear.php.net/package/PEAR
  73068. * @since Class available since Release 1.4.0a1
  73069. */
  73070. class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {}
  73071. ?><role version="1.0">
  73072. <releasetypes>php</releasetypes>
  73073. <releasetypes>extsrc</releasetypes>
  73074. <releasetypes>extbin</releasetypes>
  73075. <releasetypes>zendextsrc</releasetypes>
  73076. <releasetypes>zendextbin</releasetypes>
  73077. <installable>1</installable>
  73078. <locationconfig>bin_dir</locationconfig>
  73079. <honorsbaseinstall>1</honorsbaseinstall>
  73080. <unusualbaseinstall />
  73081. <phpfile />
  73082. <executable>1</executable>
  73083. <phpextension />
  73084. <config_vars />
  73085. </role><?php
  73086. /**
  73087. * PEAR_Installer_Role_Test
  73088. *
  73089. * PHP versions 4 and 5
  73090. *
  73091. * @category pear
  73092. * @package PEAR
  73093. * @author Greg Beaver <cellog@php.net>
  73094. * @copyright 1997-2009 The Authors
  73095. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73096. * @link http://pear.php.net/package/PEAR
  73097. * @since File available since Release 1.4.0a1
  73098. */
  73099. /**
  73100. * @category pear
  73101. * @package PEAR
  73102. * @author Greg Beaver <cellog@php.net>
  73103. * @copyright 1997-2009 The Authors
  73104. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73105. * @version Release: 1.10.10
  73106. * @link http://pear.php.net/package/PEAR
  73107. * @since Class available since Release 1.4.0a1
  73108. */
  73109. class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {}
  73110. ?><role version="1.0">
  73111. <releasetypes>php</releasetypes>
  73112. <releasetypes>extsrc</releasetypes>
  73113. <releasetypes>extbin</releasetypes>
  73114. <releasetypes>zendextsrc</releasetypes>
  73115. <releasetypes>zendextbin</releasetypes>
  73116. <installable>1</installable>
  73117. <locationconfig>test_dir</locationconfig>
  73118. <honorsbaseinstall />
  73119. <unusualbaseinstall />
  73120. <phpfile />
  73121. <executable />
  73122. <phpextension />
  73123. <config_vars />
  73124. </role><?php
  73125. /**
  73126. * PEAR_PackageFile, package.xml parsing utility class
  73127. *
  73128. * PHP versions 4 and 5
  73129. *
  73130. * @category pear
  73131. * @package PEAR
  73132. * @author Greg Beaver <cellog@php.net>
  73133. * @copyright 1997-2009 The Authors
  73134. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73135. * @link http://pear.php.net/package/PEAR
  73136. * @since File available since Release 1.4.0a1
  73137. */
  73138. /**
  73139. * needed for PEAR_VALIDATE_* constants
  73140. */
  73141. require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  73142. /**
  73143. * Error code if the package.xml <package> tag does not contain a valid version
  73144. */
  73145. define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1);
  73146. /**
  73147. * Error code if the package.xml <package> tag version is not supported (version 1.0 and 1.1 are the only supported versions,
  73148. * currently
  73149. */
  73150. define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2);
  73151. /**
  73152. * Abstraction for the package.xml package description file
  73153. *
  73154. * @category pear
  73155. * @package PEAR
  73156. * @author Greg Beaver <cellog@php.net>
  73157. * @copyright 1997-2009 The Authors
  73158. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73159. * @version Release: 1.10.10
  73160. * @link http://pear.php.net/package/PEAR
  73161. * @since Class available since Release 1.4.0a1
  73162. */
  73163. class PEAR_PackageFile
  73164. {
  73165. /**
  73166. * @var PEAR_Config
  73167. */
  73168. var $_config;
  73169. var $_debug;
  73170. var $_logger = false;
  73171. /**
  73172. * @var boolean
  73173. */
  73174. var $_rawReturn = false;
  73175. /**
  73176. * helper for extracting Archive_Tar errors
  73177. * @var array
  73178. * @access private
  73179. */
  73180. var $_extractErrors = array();
  73181. /**
  73182. *
  73183. * @param PEAR_Config $config
  73184. * @param ? $debug
  73185. * @param string @tmpdir Optional temporary directory for uncompressing
  73186. * files
  73187. */
  73188. function __construct(&$config, $debug = false)
  73189. {
  73190. $this->_config = $config;
  73191. $this->_debug = $debug;
  73192. }
  73193. /**
  73194. * Turn off validation - return a parsed package.xml without checking it
  73195. *
  73196. * This is used by the package-validate command
  73197. */
  73198. function rawReturn()
  73199. {
  73200. $this->_rawReturn = true;
  73201. }
  73202. function setLogger(&$l)
  73203. {
  73204. $this->_logger = &$l;
  73205. }
  73206. /**
  73207. * Create a PEAR_PackageFile_Parser_v* of a given version.
  73208. * @param int $version
  73209. * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1
  73210. */
  73211. function &parserFactory($version)
  73212. {
  73213. if (!in_array($version[0], array('1', '2'))) {
  73214. $a = false;
  73215. return $a;
  73216. }
  73217. include_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Parser/v' . $version[0] . '.php';
  73218. $version = $version[0];
  73219. $class = "PEAR_PackageFile_Parser_v$version";
  73220. $a = new $class;
  73221. return $a;
  73222. }
  73223. /**
  73224. * For simpler unit-testing
  73225. * @return string
  73226. */
  73227. function getClassPrefix()
  73228. {
  73229. return 'PEAR_PackageFile_v';
  73230. }
  73231. /**
  73232. * Create a PEAR_PackageFile_v* of a given version.
  73233. * @param int $version
  73234. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1
  73235. */
  73236. function &factory($version)
  73237. {
  73238. if (!in_array($version[0], array('1', '2'))) {
  73239. $a = false;
  73240. return $a;
  73241. }
  73242. include_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v' . $version[0] . '.php';
  73243. $version = $version[0];
  73244. $class = $this->getClassPrefix() . $version;
  73245. $a = new $class;
  73246. return $a;
  73247. }
  73248. /**
  73249. * Create a PEAR_PackageFile_v* from its toArray() method
  73250. *
  73251. * WARNING: no validation is performed, the array is assumed to be valid,
  73252. * always parse from xml if you want validation.
  73253. * @param array $arr
  73254. * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2
  73255. * @uses factory() to construct the returned object.
  73256. */
  73257. function &fromArray($arr)
  73258. {
  73259. if (isset($arr['xsdversion'])) {
  73260. $obj = &$this->factory($arr['xsdversion']);
  73261. if ($this->_logger) {
  73262. $obj->setLogger($this->_logger);
  73263. }
  73264. $obj->setConfig($this->_config);
  73265. $obj->fromArray($arr);
  73266. return $obj;
  73267. }
  73268. if (isset($arr['package']['attribs']['version'])) {
  73269. $obj = &$this->factory($arr['package']['attribs']['version']);
  73270. } else {
  73271. $obj = &$this->factory('1.0');
  73272. }
  73273. if ($this->_logger) {
  73274. $obj->setLogger($this->_logger);
  73275. }
  73276. $obj->setConfig($this->_config);
  73277. $obj->fromArray($arr);
  73278. return $obj;
  73279. }
  73280. /**
  73281. * Create a PEAR_PackageFile_v* from an XML string.
  73282. * @access public
  73283. * @param string $data contents of package.xml file
  73284. * @param int $state package state (one of PEAR_VALIDATE_* constants)
  73285. * @param string $file full path to the package.xml file (and the files
  73286. * it references)
  73287. * @param string $archive optional name of the archive that the XML was
  73288. * extracted from, if any
  73289. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  73290. * @uses parserFactory() to construct a parser to load the package.
  73291. */
  73292. function &fromXmlString($data, $state, $file, $archive = false)
  73293. {
  73294. if (preg_match('/<package[^>]+version=[\'"]([0-9]+\.[0-9]+)[\'"]/', $data, $packageversion)) {
  73295. if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) {
  73296. return PEAR::raiseError('package.xml version "' . $packageversion[1] .
  73297. '" is not supported, only 1.0, 2.0, and 2.1 are supported.');
  73298. }
  73299. $object = &$this->parserFactory($packageversion[1]);
  73300. if ($this->_logger) {
  73301. $object->setLogger($this->_logger);
  73302. }
  73303. $object->setConfig($this->_config);
  73304. $pf = $object->parse($data, $file, $archive);
  73305. if (PEAR::isError($pf)) {
  73306. return $pf;
  73307. }
  73308. if ($this->_rawReturn) {
  73309. return $pf;
  73310. }
  73311. if (!$pf->validate($state)) {;
  73312. if ($this->_config->get('verbose') > 0
  73313. && $this->_logger && $pf->getValidationWarnings(false)
  73314. ) {
  73315. foreach ($pf->getValidationWarnings(false) as $warning) {
  73316. $this->_logger->log(0, 'ERROR: ' . $warning['message']);
  73317. }
  73318. }
  73319. $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
  73320. 2, null, null, $pf->getValidationWarnings());
  73321. return $a;
  73322. }
  73323. if ($this->_logger && $pf->getValidationWarnings(false)) {
  73324. foreach ($pf->getValidationWarnings() as $warning) {
  73325. $this->_logger->log(0, 'WARNING: ' . $warning['message']);
  73326. }
  73327. }
  73328. if (method_exists($pf, 'flattenFilelist')) {
  73329. $pf->flattenFilelist(); // for v2
  73330. }
  73331. return $pf;
  73332. } elseif (preg_match('/<package[^>]+version=[\'"]([^"\']+)[\'"]/', $data, $packageversion)) {
  73333. $a = PEAR::raiseError('package.xml file "' . $file .
  73334. '" has unsupported package.xml <package> version "' . $packageversion[1] . '"');
  73335. return $a;
  73336. } else {
  73337. if (!class_exists('PEAR_ErrorStack')) {
  73338. require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php';
  73339. }
  73340. PEAR_ErrorStack::staticPush('PEAR_PackageFile',
  73341. PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION,
  73342. 'warning', array('xml' => $data), 'package.xml "' . $file .
  73343. '" has no package.xml <package> version');
  73344. $object = &$this->parserFactory('1.0');
  73345. $object->setConfig($this->_config);
  73346. $pf = $object->parse($data, $file, $archive);
  73347. if (PEAR::isError($pf)) {
  73348. return $pf;
  73349. }
  73350. if ($this->_rawReturn) {
  73351. return $pf;
  73352. }
  73353. if (!$pf->validate($state)) {
  73354. $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
  73355. 2, null, null, $pf->getValidationWarnings());
  73356. return $a;
  73357. }
  73358. if ($this->_logger && $pf->getValidationWarnings(false)) {
  73359. foreach ($pf->getValidationWarnings() as $warning) {
  73360. $this->_logger->log(0, 'WARNING: ' . $warning['message']);
  73361. }
  73362. }
  73363. if (method_exists($pf, 'flattenFilelist')) {
  73364. $pf->flattenFilelist(); // for v2
  73365. }
  73366. return $pf;
  73367. }
  73368. }
  73369. /**
  73370. * Register a temporary file or directory. When the destructor is
  73371. * executed, all registered temporary files and directories are
  73372. * removed.
  73373. *
  73374. * @param string $file name of file or directory
  73375. * @return void
  73376. */
  73377. static function addTempFile($file)
  73378. {
  73379. $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  73380. }
  73381. /**
  73382. * Create a PEAR_PackageFile_v* from a compressed Tar or Tgz file.
  73383. * @access public
  73384. * @param string contents of package.xml file
  73385. * @param int package state (one of PEAR_VALIDATE_* constants)
  73386. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  73387. * @using Archive_Tar to extract the files
  73388. * @using fromPackageFile() to load the package after the package.xml
  73389. * file is extracted.
  73390. */
  73391. function &fromTgzFile($file, $state)
  73392. {
  73393. if (!class_exists('Archive_Tar')) {
  73394. require_once 'phar://go-pear.phar/' . 'Archive/Tar.php';
  73395. }
  73396. $tar = new Archive_Tar($file);
  73397. if ($this->_debug <= 1) {
  73398. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  73399. }
  73400. $content = $tar->listContent();
  73401. if ($this->_debug <= 1) {
  73402. $tar->popErrorHandling();
  73403. }
  73404. if (!is_array($content)) {
  73405. if (is_string($file) && strlen($file) < 255 &&
  73406. (!file_exists($file) || !@is_file($file))) {
  73407. $ret = PEAR::raiseError("could not open file \"$file\"");
  73408. return $ret;
  73409. }
  73410. $file = realpath($file);
  73411. $ret = PEAR::raiseError("Could not get contents of package \"$file\"".
  73412. '. Invalid tgz file.');
  73413. return $ret;
  73414. }
  73415. if (!count($content) && !@is_file($file)) {
  73416. $ret = PEAR::raiseError("could not open file \"$file\"");
  73417. return $ret;
  73418. }
  73419. $xml = null;
  73420. $origfile = $file;
  73421. foreach ($content as $file) {
  73422. $name = $file['filename'];
  73423. if ($name == 'package2.xml') { // allow a .tgz to distribute both versions
  73424. $xml = $name;
  73425. break;
  73426. }
  73427. if ($name == 'package.xml') {
  73428. $xml = $name;
  73429. break;
  73430. } elseif (preg_match('/package.xml$/', $name, $match)) {
  73431. $xml = $name;
  73432. break;
  73433. }
  73434. }
  73435. $tmpdir = System::mktemp('-t "' . $this->_config->get('temp_dir') . '" -d pear');
  73436. if ($tmpdir === false) {
  73437. $ret = PEAR::raiseError("there was a problem with getting the configured temp directory");
  73438. return $ret;
  73439. }
  73440. PEAR_PackageFile::addTempFile($tmpdir);
  73441. $this->_extractErrors();
  73442. PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors'));
  73443. if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
  73444. $extra = implode("\n", $this->_extractErrors());
  73445. if ($extra) {
  73446. $extra = ' ' . $extra;
  73447. }
  73448. PEAR::staticPopErrorHandling();
  73449. $ret = PEAR::raiseError('could not extract the package.xml file from "' .
  73450. $origfile . '"' . $extra);
  73451. return $ret;
  73452. }
  73453. PEAR::staticPopErrorHandling();
  73454. $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
  73455. return $ret;
  73456. }
  73457. /**
  73458. * helper callback for extracting Archive_Tar errors
  73459. *
  73460. * @param PEAR_Error|null $err
  73461. * @return array
  73462. * @access private
  73463. */
  73464. function _extractErrors($err = null)
  73465. {
  73466. static $errors = array();
  73467. if ($err === null) {
  73468. $e = $errors;
  73469. $errors = array();
  73470. return $e;
  73471. }
  73472. $errors[] = $err->getMessage();
  73473. }
  73474. /**
  73475. * Create a PEAR_PackageFile_v* from a package.xml file.
  73476. *
  73477. * @access public
  73478. * @param string $descfile name of package xml file
  73479. * @param int $state package state (one of PEAR_VALIDATE_* constants)
  73480. * @param string|false $archive name of the archive this package.xml came
  73481. * from, if any
  73482. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  73483. * @uses PEAR_PackageFile::fromXmlString to create the oject after the
  73484. * XML is loaded from the package.xml file.
  73485. */
  73486. function &fromPackageFile($descfile, $state, $archive = false)
  73487. {
  73488. $fp = false;
  73489. if (is_string($descfile) && strlen($descfile) < 255 &&
  73490. (
  73491. !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile)
  73492. || (!$fp = @fopen($descfile, 'r'))
  73493. )
  73494. ) {
  73495. $a = PEAR::raiseError("Unable to open $descfile");
  73496. return $a;
  73497. }
  73498. // read the whole thing so we only get one cdata callback
  73499. // for each block of cdata
  73500. fclose($fp);
  73501. $data = file_get_contents($descfile);
  73502. $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive);
  73503. return $ret;
  73504. }
  73505. /**
  73506. * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file.
  73507. *
  73508. * This method is able to extract information about a package from a .tgz
  73509. * archive or from a XML package definition file.
  73510. *
  73511. * @access public
  73512. * @param string $info file name
  73513. * @param int $state package state (one of PEAR_VALIDATE_* constants)
  73514. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
  73515. * @uses fromPackageFile() if the file appears to be XML
  73516. * @uses fromTgzFile() to load all non-XML files
  73517. */
  73518. function &fromAnyFile($info, $state)
  73519. {
  73520. if (is_dir($info)) {
  73521. $dir_name = realpath($info);
  73522. if (file_exists($dir_name . '/package.xml')) {
  73523. $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state);
  73524. } elseif (file_exists($dir_name . '/package2.xml')) {
  73525. $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state);
  73526. } else {
  73527. $info = PEAR::raiseError("No package definition found in '$info' directory");
  73528. }
  73529. return $info;
  73530. }
  73531. $fp = false;
  73532. if (is_string($info) && strlen($info) < 255 &&
  73533. (file_exists($info) || ($fp = @fopen($info, 'r')))
  73534. ) {
  73535. if ($fp) {
  73536. fclose($fp);
  73537. }
  73538. $tmp = substr($info, -4);
  73539. if ($tmp == '.xml') {
  73540. $info = &PEAR_PackageFile::fromPackageFile($info, $state);
  73541. } elseif ($tmp == '.tar' || $tmp == '.tgz') {
  73542. $info = &PEAR_PackageFile::fromTgzFile($info, $state);
  73543. } else {
  73544. $fp = fopen($info, 'r');
  73545. $test = fread($fp, 5);
  73546. fclose($fp);
  73547. if ($test == '<?xml') {
  73548. $info = &PEAR_PackageFile::fromPackageFile($info, $state);
  73549. } else {
  73550. $info = &PEAR_PackageFile::fromTgzFile($info, $state);
  73551. }
  73552. }
  73553. return $info;
  73554. }
  73555. $info = PEAR::raiseError("Cannot open '$info' for parsing");
  73556. return $info;
  73557. }
  73558. }
  73559. <?php
  73560. /**
  73561. * package.xml generation class, package.xml version 1.0
  73562. *
  73563. * PHP versions 4 and 5
  73564. *
  73565. * @category pear
  73566. * @package PEAR
  73567. * @author Greg Beaver <cellog@php.net>
  73568. * @copyright 1997-2009 The Authors
  73569. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73570. * @link http://pear.php.net/package/PEAR
  73571. * @since File available since Release 1.4.0a1
  73572. */
  73573. /**
  73574. * needed for PEAR_VALIDATE_* constants
  73575. */
  73576. require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  73577. require_once 'phar://go-pear.phar/' . 'System.php';
  73578. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  73579. /**
  73580. * This class converts a PEAR_PackageFile_v1 object into any output format.
  73581. *
  73582. * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
  73583. * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
  73584. * @category pear
  73585. * @package PEAR
  73586. * @author Greg Beaver <cellog@php.net>
  73587. * @copyright 1997-2009 The Authors
  73588. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  73589. * @version Release: 1.10.10
  73590. * @link http://pear.php.net/package/PEAR
  73591. * @since Class available since Release 1.4.0a1
  73592. */
  73593. class PEAR_PackageFile_Generator_v1
  73594. {
  73595. /**
  73596. * @var PEAR_PackageFile_v1
  73597. */
  73598. var $_packagefile;
  73599. function __construct(&$packagefile)
  73600. {
  73601. $this->_packagefile = &$packagefile;
  73602. }
  73603. function getPackagerVersion()
  73604. {
  73605. return '1.10.10';
  73606. }
  73607. /**
  73608. * @param PEAR_Packager
  73609. * @param bool if true, a .tgz is written, otherwise a .tar is written
  73610. * @param string|null directory in which to save the .tgz
  73611. * @return string|PEAR_Error location of package or error object
  73612. */
  73613. function toTgz(&$packager, $compress = true, $where = null)
  73614. {
  73615. require_once 'phar://go-pear.phar/' . 'Archive/Tar.php';
  73616. if ($where === null) {
  73617. if (!($where = System::mktemp(array('-d')))) {
  73618. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
  73619. }
  73620. } elseif (!@System::mkDir(array('-p', $where))) {
  73621. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
  73622. ' not be created');
  73623. }
  73624. if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
  73625. !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
  73626. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
  73627. ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
  73628. }
  73629. if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
  73630. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
  73631. }
  73632. $pkginfo = $this->_packagefile->getArray();
  73633. $ext = $compress ? '.tgz' : '.tar';
  73634. $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
  73635. $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
  73636. if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
  73637. !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
  73638. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
  73639. getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
  73640. }
  73641. if ($pkgfile = $this->_packagefile->getPackageFile()) {
  73642. $pkgdir = dirname(realpath($pkgfile));
  73643. $pkgfile = basename($pkgfile);
  73644. } else {
  73645. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
  73646. 'be created from a real file');
  73647. }
  73648. // {{{ Create the package file list
  73649. $filelist = array();
  73650. $i = 0;
  73651. foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
  73652. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  73653. if (!file_exists($file)) {
  73654. return PEAR::raiseError("File does not exist: $fname");
  73655. } else {
  73656. $filelist[$i++] = $file;
  73657. if (!isset($atts['md5sum'])) {
  73658. $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
  73659. }
  73660. $packager->log(2, "Adding file $fname");
  73661. }
  73662. }
  73663. // }}}
  73664. $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
  73665. if ($packagexml) {
  73666. $tar = new Archive_Tar($dest_package, $compress);
  73667. $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
  73668. // ----- Creates with the package.xml file
  73669. $ok = $tar->createModify(array($packagexml), '', $where);
  73670. if (PEAR::isError($ok)) {
  73671. return $ok;
  73672. } elseif (!$ok) {
  73673. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
  73674. }
  73675. // ----- Add the content of the package
  73676. if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
  73677. return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
  73678. }
  73679. return $dest_package;
  73680. }
  73681. }
  73682. /**
  73683. * @param string|null directory to place the package.xml in, or null for a temporary dir
  73684. * @param int one of the PEAR_VALIDATE_* constants
  73685. * @param string name of the generated file
  73686. * @param bool if true, then no analysis will be performed on role="php" files
  73687. * @return string|PEAR_Error path to the created file on success
  73688. */
  73689. function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
  73690. $nofilechecking = false)
  73691. {
  73692. if (!$this->_packagefile->validate($state, $nofilechecking)) {
  73693. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
  73694. null, null, null, $this->_packagefile->getValidationWarnings());
  73695. }
  73696. if ($where === null) {
  73697. if (!($where = System::mktemp(array('-d')))) {
  73698. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
  73699. }
  73700. } elseif (!@System::mkDir(array('-p', $where))) {
  73701. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
  73702. ' not be created');
  73703. }
  73704. $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
  73705. $np = @fopen($newpkgfile, 'wb');
  73706. if (!$np) {
  73707. return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
  73708. "$name as $newpkgfile");
  73709. }
  73710. fwrite($np, $this->toXml($state, true));
  73711. fclose($np);
  73712. return $newpkgfile;
  73713. }
  73714. /**
  73715. * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
  73716. *
  73717. * @param string $string
  73718. * @return string
  73719. * @access private
  73720. */
  73721. function _fixXmlEncoding($string)
  73722. {
  73723. return strtr($string, array(
  73724. '&' => '&amp;',
  73725. '>' => '&gt;',
  73726. '<' => '&lt;',
  73727. '"' => '&quot;',
  73728. '\'' => '&apos;' ));
  73729. }
  73730. /**
  73731. * Return an XML document based on the package info (as returned
  73732. * by the PEAR_Common::infoFrom* methods).
  73733. *
  73734. * @return string XML data
  73735. */
  73736. function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
  73737. {
  73738. $this->_packagefile->setDate(date('Y-m-d'));
  73739. if (!$this->_packagefile->validate($state, $nofilevalidation)) {
  73740. return false;
  73741. }
  73742. $pkginfo = $this->_packagefile->getArray();
  73743. static $maint_map = array(
  73744. "handle" => "user",
  73745. "name" => "name",
  73746. "email" => "email",
  73747. "role" => "role",
  73748. );
  73749. $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
  73750. $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n";
  73751. $ret .= "<package version=\"1.0\" packagerversion=\"1.10.10\">\n" .
  73752. " <name>$pkginfo[package]</name>";
  73753. if (isset($pkginfo['extends'])) {
  73754. $ret .= "\n<extends>$pkginfo[extends]</extends>";
  73755. }
  73756. $ret .=
  73757. "\n <summary>".$this->_fixXmlEncoding($pkginfo['summary'])."</summary>\n" .
  73758. " <description>".trim($this->_fixXmlEncoding($pkginfo['description']))."\n </description>\n" .
  73759. " <maintainers>\n";
  73760. foreach ($pkginfo['maintainers'] as $maint) {
  73761. $ret .= " <maintainer>\n";
  73762. foreach ($maint_map as $idx => $elm) {
  73763. $ret .= " <$elm>";
  73764. $ret .= $this->_fixXmlEncoding($maint[$idx]);
  73765. $ret .= "</$elm>\n";
  73766. }
  73767. $ret .= " </maintainer>\n";
  73768. }
  73769. $ret .= " </maintainers>\n";
  73770. $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
  73771. if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
  73772. $ret .= " <changelog>\n";
  73773. foreach ($pkginfo['changelog'] as $oldrelease) {
  73774. $ret .= $this->_makeReleaseXml($oldrelease, true);
  73775. }
  73776. $ret .= " </changelog>\n";
  73777. }
  73778. $ret .= "</package>\n";
  73779. return $ret;
  73780. }
  73781. // }}}
  73782. // {{{ _makeReleaseXml()
  73783. /**
  73784. * Generate part of an XML description with release information.
  73785. *
  73786. * @param array $pkginfo array with release information
  73787. * @param bool $changelog whether the result will be in a changelog element
  73788. *
  73789. * @return string XML data
  73790. *
  73791. * @access private
  73792. */
  73793. function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
  73794. {
  73795. // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
  73796. $indent = $changelog ? " " : "";
  73797. $ret = "$indent <release>\n";
  73798. if (!empty($pkginfo['version'])) {
  73799. $ret .= "$indent <version>$pkginfo[version]</version>\n";
  73800. }
  73801. if (!empty($pkginfo['release_date'])) {
  73802. $ret .= "$indent <date>$pkginfo[release_date]</date>\n";
  73803. }
  73804. if (!empty($pkginfo['release_license'])) {
  73805. $ret .= "$indent <license>$pkginfo[release_license]</license>\n";
  73806. }
  73807. if (!empty($pkginfo['release_state'])) {
  73808. $ret .= "$indent <state>$pkginfo[release_state]</state>\n";
  73809. }
  73810. if (!empty($pkginfo['release_notes'])) {
  73811. $ret .= "$indent <notes>".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
  73812. ."\n$indent </notes>\n";
  73813. }
  73814. if (!empty($pkginfo['release_warnings'])) {
  73815. $ret .= "$indent <warnings>".$this->_fixXmlEncoding($pkginfo['release_warnings'])."</warnings>\n";
  73816. }
  73817. if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
  73818. $ret .= "$indent <deps>\n";
  73819. foreach ($pkginfo['release_deps'] as $dep) {
  73820. $ret .= "$indent <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
  73821. if (isset($dep['version'])) {
  73822. $ret .= " version=\"$dep[version]\"";
  73823. }
  73824. if (isset($dep['optional'])) {
  73825. $ret .= " optional=\"$dep[optional]\"";
  73826. }
  73827. if (isset($dep['name'])) {
  73828. $ret .= ">$dep[name]</dep>\n";
  73829. } else {
  73830. $ret .= "/>\n";
  73831. }
  73832. }
  73833. $ret .= "$indent </deps>\n";
  73834. }
  73835. if (isset($pkginfo['configure_options'])) {
  73836. $ret .= "$indent <configureoptions>\n";
  73837. foreach ($pkginfo['configure_options'] as $c) {
  73838. $ret .= "$indent <configureoption name=\"".
  73839. $this->_fixXmlEncoding($c['name']) . "\"";
  73840. if (isset($c['default'])) {
  73841. $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
  73842. }
  73843. $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
  73844. $ret .= "/>\n";
  73845. }
  73846. $ret .= "$indent </configureoptions>\n";
  73847. }
  73848. if (isset($pkginfo['provides'])) {
  73849. foreach ($pkginfo['provides'] as $key => $what) {
  73850. $ret .= "$indent <provides type=\"$what[type]\" ";
  73851. $ret .= "name=\"$what[name]\" ";
  73852. if (isset($what['extends'])) {
  73853. $ret .= "extends=\"$what[extends]\" ";
  73854. }
  73855. $ret .= "/>\n";
  73856. }
  73857. }
  73858. if (isset($pkginfo['filelist'])) {
  73859. $ret .= "$indent <filelist>\n";
  73860. if ($state ^ PEAR_VALIDATE_PACKAGING) {
  73861. $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']);
  73862. } else {
  73863. foreach ($pkginfo['filelist'] as $file => $fa) {
  73864. if (!isset($fa['role'])) {
  73865. $fa['role'] = '';
  73866. }
  73867. $ret .= "$indent <file role=\"$fa[role]\"";
  73868. if (isset($fa['baseinstalldir'])) {
  73869. $ret .= ' baseinstalldir="' .
  73870. $this->_fixXmlEncoding($fa['baseinstalldir']) . '"';
  73871. }
  73872. if (isset($fa['md5sum'])) {
  73873. $ret .= " md5sum=\"$fa[md5sum]\"";
  73874. }
  73875. if (isset($fa['platform'])) {
  73876. $ret .= " platform=\"$fa[platform]\"";
  73877. }
  73878. if (!empty($fa['install-as'])) {
  73879. $ret .= ' install-as="' .
  73880. $this->_fixXmlEncoding($fa['install-as']) . '"';
  73881. }
  73882. $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
  73883. if (empty($fa['replacements'])) {
  73884. $ret .= "/>\n";
  73885. } else {
  73886. $ret .= ">\n";
  73887. foreach ($fa['replacements'] as $r) {
  73888. $ret .= "$indent <replace";
  73889. foreach ($r as $k => $v) {
  73890. $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
  73891. }
  73892. $ret .= "/>\n";
  73893. }
  73894. $ret .= "$indent </file>\n";
  73895. }
  73896. }
  73897. }
  73898. $ret .= "$indent </filelist>\n";
  73899. }
  73900. $ret .= "$indent </release>\n";
  73901. return $ret;
  73902. }
  73903. /**
  73904. * @param array
  73905. * @access protected
  73906. */
  73907. function recursiveXmlFilelist($list)
  73908. {
  73909. $this->_dirs = array();
  73910. foreach ($list as $file => $attributes) {
  73911. $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
  73912. }
  73913. return $this->_formatDir($this->_dirs);
  73914. }
  73915. /**
  73916. * @param array
  73917. * @param array
  73918. * @param string|null
  73919. * @param array|null
  73920. * @access private
  73921. */
  73922. function _addDir(&$dirs, $dir, $file = null, $attributes = null)
  73923. {
  73924. if ($dir == array() || $dir == array('.')) {
  73925. $dirs['files'][basename($file)] = $attributes;
  73926. return;
  73927. }
  73928. $curdir = array_shift($dir);
  73929. if (!isset($dirs['dirs'][$curdir])) {
  73930. $dirs['dirs'][$curdir] = array();
  73931. }
  73932. $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
  73933. }
  73934. /**
  73935. * @param array
  73936. * @param string
  73937. * @param string
  73938. * @access private
  73939. */
  73940. function _formatDir($dirs, $indent = '', $curdir = '')
  73941. {
  73942. $ret = '';
  73943. if (!count($dirs)) {
  73944. return '';
  73945. }
  73946. if (isset($dirs['dirs'])) {
  73947. uksort($dirs['dirs'], 'strnatcasecmp');
  73948. foreach ($dirs['dirs'] as $dir => $contents) {
  73949. $usedir = "$curdir/$dir";
  73950. $ret .= "$indent <dir name=\"$dir\">\n";
  73951. $ret .= $this->_formatDir($contents, "$indent ", $usedir);
  73952. $ret .= "$indent </dir> <!-- $usedir -->\n";
  73953. }
  73954. }
  73955. if (isset($dirs['files'])) {
  73956. uksort($dirs['files'], 'strnatcasecmp');
  73957. foreach ($dirs['files'] as $file => $attribs) {
  73958. $ret .= $this->_formatFile($file, $attribs, $indent);
  73959. }
  73960. }
  73961. return $ret;
  73962. }
  73963. /**
  73964. * @param string
  73965. * @param array
  73966. * @param string
  73967. * @access private
  73968. */
  73969. function _formatFile($file, $attributes, $indent)
  73970. {
  73971. $ret = "$indent <file role=\"$attributes[role]\"";
  73972. if (isset($attributes['baseinstalldir'])) {
  73973. $ret .= ' baseinstalldir="' .
  73974. $this->_fixXmlEncoding($attributes['baseinstalldir']) . '"';
  73975. }
  73976. if (isset($attributes['md5sum'])) {
  73977. $ret .= " md5sum=\"$attributes[md5sum]\"";
  73978. }
  73979. if (isset($attributes['platform'])) {
  73980. $ret .= " platform=\"$attributes[platform]\"";
  73981. }
  73982. if (!empty($attributes['install-as'])) {
  73983. $ret .= ' install-as="' .
  73984. $this->_fixXmlEncoding($attributes['install-as']) . '"';
  73985. }
  73986. $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
  73987. if (empty($attributes['replacements'])) {
  73988. $ret .= "/>\n";
  73989. } else {
  73990. $ret .= ">\n";
  73991. foreach ($attributes['replacements'] as $r) {
  73992. $ret .= "$indent <replace";
  73993. foreach ($r as $k => $v) {
  73994. $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
  73995. }
  73996. $ret .= "/>\n";
  73997. }
  73998. $ret .= "$indent </file>\n";
  73999. }
  74000. return $ret;
  74001. }
  74002. // {{{ _unIndent()
  74003. /**
  74004. * Unindent given string (?)
  74005. *
  74006. * @param string $str The string that has to be unindented.
  74007. * @return string
  74008. * @access private
  74009. */
  74010. function _unIndent($str)
  74011. {
  74012. // remove leading newlines
  74013. $str = preg_replace('/^[\r\n]+/', '', $str);
  74014. // find whitespace at the beginning of the first line
  74015. $indent_len = strspn($str, " \t");
  74016. $indent = substr($str, 0, $indent_len);
  74017. $data = '';
  74018. // remove the same amount of whitespace from following lines
  74019. foreach (explode("\n", $str) as $line) {
  74020. if (substr($line, 0, $indent_len) == $indent) {
  74021. $data .= substr($line, $indent_len) . "\n";
  74022. }
  74023. }
  74024. return $data;
  74025. }
  74026. /**
  74027. * @return array
  74028. */
  74029. function dependenciesToV2()
  74030. {
  74031. $arr = array();
  74032. $this->_convertDependencies2_0($arr);
  74033. return $arr['dependencies'];
  74034. }
  74035. /**
  74036. * Convert a package.xml version 1.0 into version 2.0
  74037. *
  74038. * Note that this does a basic conversion, to allow more advanced
  74039. * features like bundles and multiple releases
  74040. * @param string the classname to instantiate and return. This must be
  74041. * PEAR_PackageFile_v2 or a descendant
  74042. * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
  74043. * strictest parameters will be converted
  74044. * @return PEAR_PackageFile_v2|PEAR_Error
  74045. */
  74046. function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
  74047. {
  74048. if ($strict) {
  74049. if (!$this->_packagefile->validate()) {
  74050. $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
  74051. ' to version 2.0', null, null, null,
  74052. $this->_packagefile->getValidationWarnings(true));
  74053. return $a;
  74054. }
  74055. }
  74056. $arr = array(
  74057. 'attribs' => array(
  74058. 'version' => '2.0',
  74059. 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
  74060. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  74061. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  74062. 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
  74063. "http://pear.php.net/dtd/tasks-1.0.xsd\n" .
  74064. "http://pear.php.net/dtd/package-2.0\n" .
  74065. 'http://pear.php.net/dtd/package-2.0.xsd',
  74066. ),
  74067. 'name' => $this->_packagefile->getPackage(),
  74068. 'channel' => 'pear.php.net',
  74069. );
  74070. $arr['summary'] = $this->_packagefile->getSummary();
  74071. $arr['description'] = $this->_packagefile->getDescription();
  74072. $maintainers = $this->_packagefile->getMaintainers();
  74073. foreach ($maintainers as $maintainer) {
  74074. if ($maintainer['role'] != 'lead') {
  74075. continue;
  74076. }
  74077. $new = array(
  74078. 'name' => $maintainer['name'],
  74079. 'user' => $maintainer['handle'],
  74080. 'email' => $maintainer['email'],
  74081. 'active' => 'yes',
  74082. );
  74083. $arr['lead'][] = $new;
  74084. }
  74085. if (!isset($arr['lead'])) { // some people... you know?
  74086. $arr['lead'] = array(
  74087. 'name' => 'unknown',
  74088. 'user' => 'unknown',
  74089. 'email' => 'noleadmaintainer@example.com',
  74090. 'active' => 'no',
  74091. );
  74092. }
  74093. if (count($arr['lead']) == 1) {
  74094. $arr['lead'] = $arr['lead'][0];
  74095. }
  74096. foreach ($maintainers as $maintainer) {
  74097. if ($maintainer['role'] == 'lead') {
  74098. continue;
  74099. }
  74100. $new = array(
  74101. 'name' => $maintainer['name'],
  74102. 'user' => $maintainer['handle'],
  74103. 'email' => $maintainer['email'],
  74104. 'active' => 'yes',
  74105. );
  74106. $arr[$maintainer['role']][] = $new;
  74107. }
  74108. if (isset($arr['developer']) && count($arr['developer']) == 1) {
  74109. $arr['developer'] = $arr['developer'][0];
  74110. }
  74111. if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
  74112. $arr['contributor'] = $arr['contributor'][0];
  74113. }
  74114. if (isset($arr['helper']) && count($arr['helper']) == 1) {
  74115. $arr['helper'] = $arr['helper'][0];
  74116. }
  74117. $arr['date'] = $this->_packagefile->getDate();
  74118. $arr['version'] =
  74119. array(
  74120. 'release' => $this->_packagefile->getVersion(),
  74121. 'api' => $this->_packagefile->getVersion(),
  74122. );
  74123. $arr['stability'] =
  74124. array(
  74125. 'release' => $this->_packagefile->getState(),
  74126. 'api' => $this->_packagefile->getState(),
  74127. );
  74128. $licensemap =
  74129. array(
  74130. 'php' => 'http://www.php.net/license',
  74131. 'php license' => 'http://www.php.net/license',
  74132. 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
  74133. 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
  74134. 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
  74135. 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
  74136. 'mit' => 'http://www.opensource.org/licenses/mit-license.php',
  74137. 'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
  74138. 'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
  74139. );
  74140. if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
  74141. $arr['license'] = array(
  74142. 'attribs' => array('uri' =>
  74143. $licensemap[strtolower($this->_packagefile->getLicense())]),
  74144. '_content' => $this->_packagefile->getLicense()
  74145. );
  74146. } else {
  74147. // don't use bogus uri
  74148. $arr['license'] = $this->_packagefile->getLicense();
  74149. }
  74150. $arr['notes'] = $this->_packagefile->getNotes();
  74151. $temp = array();
  74152. $arr['contents'] = $this->_convertFilelist2_0($temp);
  74153. $this->_convertDependencies2_0($arr);
  74154. $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
  74155. 'extsrcrelease' : 'phprelease';
  74156. if ($release == 'extsrcrelease') {
  74157. $arr['channel'] = 'pecl.php.net';
  74158. $arr['providesextension'] = $arr['name']; // assumption
  74159. }
  74160. $arr[$release] = array();
  74161. if ($this->_packagefile->getConfigureOptions()) {
  74162. $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
  74163. foreach ($arr[$release]['configureoption'] as $i => $opt) {
  74164. $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
  74165. }
  74166. if (count($arr[$release]['configureoption']) == 1) {
  74167. $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
  74168. }
  74169. }
  74170. $this->_convertRelease2_0($arr[$release], $temp);
  74171. if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
  74172. // multiple extsrcrelease tags added in PEAR 1.4.1
  74173. $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
  74174. }
  74175. if ($cl = $this->_packagefile->getChangelog()) {
  74176. foreach ($cl as $release) {
  74177. $rel = array();
  74178. $rel['version'] =
  74179. array(
  74180. 'release' => $release['version'],
  74181. 'api' => $release['version'],
  74182. );
  74183. if (!isset($release['release_state'])) {
  74184. $release['release_state'] = 'stable';
  74185. }
  74186. $rel['stability'] =
  74187. array(
  74188. 'release' => $release['release_state'],
  74189. 'api' => $release['release_state'],
  74190. );
  74191. if (isset($release['release_date'])) {
  74192. $rel['date'] = $release['release_date'];
  74193. } else {
  74194. $rel['date'] = date('Y-m-d');
  74195. }
  74196. if (isset($release['release_license'])) {
  74197. if (isset($licensemap[strtolower($release['release_license'])])) {
  74198. $uri = $licensemap[strtolower($release['release_license'])];
  74199. } else {
  74200. $uri = 'http://www.example.com';
  74201. }
  74202. $rel['license'] = array(
  74203. 'attribs' => array('uri' => $uri),
  74204. '_content' => $release['release_license']
  74205. );
  74206. } else {
  74207. $rel['license'] = $arr['license'];
  74208. }
  74209. if (!isset($release['release_notes'])) {
  74210. $release['release_notes'] = 'no release notes';
  74211. }
  74212. $rel['notes'] = $release['release_notes'];
  74213. $arr['changelog']['release'][] = $rel;
  74214. }
  74215. }
  74216. $ret = new $class;
  74217. $ret->setConfig($this->_packagefile->_config);
  74218. if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) {
  74219. $ret->setLogger($this->_packagefile->_logger);
  74220. }
  74221. $ret->fromArray($arr);
  74222. return $ret;
  74223. }
  74224. /**
  74225. * @param array
  74226. * @param bool
  74227. * @access private
  74228. */
  74229. function _convertDependencies2_0(&$release, $internal = false)
  74230. {
  74231. $peardep = array('pearinstaller' =>
  74232. array('min' => '1.4.0b1')); // this is a lot safer
  74233. $required = $optional = array();
  74234. $release['dependencies'] = array('required' => array());
  74235. if ($this->_packagefile->hasDeps()) {
  74236. foreach ($this->_packagefile->getDeps() as $dep) {
  74237. if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  74238. $required[] = $dep;
  74239. } else {
  74240. $optional[] = $dep;
  74241. }
  74242. }
  74243. foreach (array('required', 'optional') as $arr) {
  74244. $deps = array();
  74245. foreach ($$arr as $dep) {
  74246. // organize deps by dependency type and name
  74247. if (!isset($deps[$dep['type']])) {
  74248. $deps[$dep['type']] = array();
  74249. }
  74250. if (isset($dep['name'])) {
  74251. $deps[$dep['type']][$dep['name']][] = $dep;
  74252. } else {
  74253. $deps[$dep['type']][] = $dep;
  74254. }
  74255. }
  74256. do {
  74257. if (isset($deps['php'])) {
  74258. $php = array();
  74259. if (count($deps['php']) > 1) {
  74260. $php = $this->_processPhpDeps($deps['php']);
  74261. } else {
  74262. if (!isset($deps['php'][0])) {
  74263. // Buggy versions
  74264. $key = key($deps['php']);
  74265. $info = current($deps['php']);
  74266. $deps['php'] = array($info[0]);
  74267. }
  74268. $php = $this->_processDep($deps['php'][0]);
  74269. if (!$php) {
  74270. break; // poor mans throw
  74271. }
  74272. }
  74273. $release['dependencies'][$arr]['php'] = $php;
  74274. }
  74275. } while (false);
  74276. do {
  74277. if (isset($deps['pkg'])) {
  74278. $pkg = array();
  74279. $pkg = $this->_processMultipleDepsName($deps['pkg']);
  74280. if (!$pkg) {
  74281. break; // poor mans throw
  74282. }
  74283. $release['dependencies'][$arr]['package'] = $pkg;
  74284. }
  74285. } while (false);
  74286. do {
  74287. if (isset($deps['ext'])) {
  74288. $pkg = array();
  74289. $pkg = $this->_processMultipleDepsName($deps['ext']);
  74290. $release['dependencies'][$arr]['extension'] = $pkg;
  74291. }
  74292. } while (false);
  74293. // skip sapi - it's not supported so nobody will have used it
  74294. // skip os - it's not supported in 1.0
  74295. }
  74296. }
  74297. if (isset($release['dependencies']['required'])) {
  74298. $release['dependencies']['required'] =
  74299. array_merge($peardep, $release['dependencies']['required']);
  74300. } else {
  74301. $release['dependencies']['required'] = $peardep;
  74302. }
  74303. if (!isset($release['dependencies']['required']['php'])) {
  74304. $release['dependencies']['required']['php'] =
  74305. array('min' => '4.0.0');
  74306. }
  74307. $order = array();
  74308. $bewm = $release['dependencies']['required'];
  74309. $order['php'] = $bewm['php'];
  74310. $order['pearinstaller'] = $bewm['pearinstaller'];
  74311. isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
  74312. isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
  74313. $release['dependencies']['required'] = $order;
  74314. }
  74315. /**
  74316. * @param array
  74317. * @access private
  74318. */
  74319. function _convertFilelist2_0(&$package)
  74320. {
  74321. $ret = array('dir' =>
  74322. array(
  74323. 'attribs' => array('name' => '/'),
  74324. 'file' => array()
  74325. )
  74326. );
  74327. $package['platform'] =
  74328. $package['install-as'] = array();
  74329. $this->_isExtension = false;
  74330. foreach ($this->_packagefile->getFilelist() as $name => $file) {
  74331. $file['name'] = $name;
  74332. if (isset($file['role']) && $file['role'] == 'src') {
  74333. $this->_isExtension = true;
  74334. }
  74335. if (isset($file['replacements'])) {
  74336. $repl = $file['replacements'];
  74337. unset($file['replacements']);
  74338. } else {
  74339. unset($repl);
  74340. }
  74341. if (isset($file['install-as'])) {
  74342. $package['install-as'][$name] = $file['install-as'];
  74343. unset($file['install-as']);
  74344. }
  74345. if (isset($file['platform'])) {
  74346. $package['platform'][$name] = $file['platform'];
  74347. unset($file['platform']);
  74348. }
  74349. $file = array('attribs' => $file);
  74350. if (isset($repl)) {
  74351. foreach ($repl as $replace ) {
  74352. $file['tasks:replace'][] = array('attribs' => $replace);
  74353. }
  74354. if (count($repl) == 1) {
  74355. $file['tasks:replace'] = $file['tasks:replace'][0];
  74356. }
  74357. }
  74358. $ret['dir']['file'][] = $file;
  74359. }
  74360. return $ret;
  74361. }
  74362. /**
  74363. * Post-process special files with install-as/platform attributes and
  74364. * make the release tag.
  74365. *
  74366. * This complex method follows this work-flow to create the release tags:
  74367. *
  74368. * <pre>
  74369. * - if any install-as/platform exist, create a generic release and fill it with
  74370. * o <install as=..> tags for <file name=... install-as=...>
  74371. * o <install as=..> tags for <file name=... platform=!... install-as=..>
  74372. * o <ignore> tags for <file name=... platform=...>
  74373. * o <ignore> tags for <file name=... platform=... install-as=..>
  74374. * - create a release for each platform encountered and fill with
  74375. * o <install as..> tags for <file name=... install-as=...>
  74376. * o <install as..> tags for <file name=... platform=this platform install-as=..>
  74377. * o <install as..> tags for <file name=... platform=!other platform install-as=..>
  74378. * o <ignore> tags for <file name=... platform=!this platform>
  74379. * o <ignore> tags for <file name=... platform=other platform>
  74380. * o <ignore> tags for <file name=... platform=other platform install-as=..>
  74381. * o <ignore> tags for <file name=... platform=!this platform install-as=..>
  74382. * </pre>
  74383. *
  74384. * It does this by accessing the $package parameter, which contains an array with
  74385. * indices:
  74386. *
  74387. * - platform: mapping of file => OS the file should be installed on
  74388. * - install-as: mapping of file => installed name
  74389. * - osmap: mapping of OS => list of files that should be installed
  74390. * on that OS
  74391. * - notosmap: mapping of OS => list of files that should not be
  74392. * installed on that OS
  74393. *
  74394. * @param array
  74395. * @param array
  74396. * @access private
  74397. */
  74398. function _convertRelease2_0(&$release, $package)
  74399. {
  74400. //- if any install-as/platform exist, create a generic release and fill it with
  74401. if (count($package['platform']) || count($package['install-as'])) {
  74402. $generic = array();
  74403. $genericIgnore = array();
  74404. foreach ($package['install-as'] as $file => $as) {
  74405. //o <install as=..> tags for <file name=... install-as=...>
  74406. if (!isset($package['platform'][$file])) {
  74407. $generic[] = $file;
  74408. continue;
  74409. }
  74410. //o <install as=..> tags for <file name=... platform=!... install-as=..>
  74411. if (isset($package['platform'][$file]) &&
  74412. $package['platform'][$file][0] == '!') {
  74413. $generic[] = $file;
  74414. continue;
  74415. }
  74416. //o <ignore> tags for <file name=... platform=... install-as=..>
  74417. if (isset($package['platform'][$file]) &&
  74418. $package['platform'][$file][0] != '!') {
  74419. $genericIgnore[] = $file;
  74420. continue;
  74421. }
  74422. }
  74423. foreach ($package['platform'] as $file => $platform) {
  74424. if (isset($package['install-as'][$file])) {
  74425. continue;
  74426. }
  74427. if ($platform[0] != '!') {
  74428. //o <ignore> tags for <file name=... platform=...>
  74429. $genericIgnore[] = $file;
  74430. }
  74431. }
  74432. if (count($package['platform'])) {
  74433. $oses = $notplatform = $platform = array();
  74434. foreach ($package['platform'] as $file => $os) {
  74435. // get a list of oses
  74436. if ($os[0] == '!') {
  74437. if (isset($oses[substr($os, 1)])) {
  74438. continue;
  74439. }
  74440. $oses[substr($os, 1)] = count($oses);
  74441. } else {
  74442. if (isset($oses[$os])) {
  74443. continue;
  74444. }
  74445. $oses[$os] = count($oses);
  74446. }
  74447. }
  74448. //- create a release for each platform encountered and fill with
  74449. foreach ($oses as $os => $releaseNum) {
  74450. $release[$releaseNum]['installconditions']['os']['name'] = $os;
  74451. $release[$releaseNum]['filelist'] = array('install' => array(),
  74452. 'ignore' => array());
  74453. foreach ($package['install-as'] as $file => $as) {
  74454. //o <install as=..> tags for <file name=... install-as=...>
  74455. if (!isset($package['platform'][$file])) {
  74456. $release[$releaseNum]['filelist']['install'][] =
  74457. array(
  74458. 'attribs' => array(
  74459. 'name' => $file,
  74460. 'as' => $as,
  74461. ),
  74462. );
  74463. continue;
  74464. }
  74465. //o <install as..> tags for
  74466. // <file name=... platform=this platform install-as=..>
  74467. if (isset($package['platform'][$file]) &&
  74468. $package['platform'][$file] == $os) {
  74469. $release[$releaseNum]['filelist']['install'][] =
  74470. array(
  74471. 'attribs' => array(
  74472. 'name' => $file,
  74473. 'as' => $as,
  74474. ),
  74475. );
  74476. continue;
  74477. }
  74478. //o <install as..> tags for
  74479. // <file name=... platform=!other platform install-as=..>
  74480. if (isset($package['platform'][$file]) &&
  74481. $package['platform'][$file] != "!$os" &&
  74482. $package['platform'][$file][0] == '!') {
  74483. $release[$releaseNum]['filelist']['install'][] =
  74484. array(
  74485. 'attribs' => array(
  74486. 'name' => $file,
  74487. 'as' => $as,
  74488. ),
  74489. );
  74490. continue;
  74491. }
  74492. //o <ignore> tags for
  74493. // <file name=... platform=!this platform install-as=..>
  74494. if (isset($package['platform'][$file]) &&
  74495. $package['platform'][$file] == "!$os") {
  74496. $release[$releaseNum]['filelist']['ignore'][] =
  74497. array(
  74498. 'attribs' => array(
  74499. 'name' => $file,
  74500. ),
  74501. );
  74502. continue;
  74503. }
  74504. //o <ignore> tags for
  74505. // <file name=... platform=other platform install-as=..>
  74506. if (isset($package['platform'][$file]) &&
  74507. $package['platform'][$file][0] != '!' &&
  74508. $package['platform'][$file] != $os) {
  74509. $release[$releaseNum]['filelist']['ignore'][] =
  74510. array(
  74511. 'attribs' => array(
  74512. 'name' => $file,
  74513. ),
  74514. );
  74515. continue;
  74516. }
  74517. }
  74518. foreach ($package['platform'] as $file => $platform) {
  74519. if (isset($package['install-as'][$file])) {
  74520. continue;
  74521. }
  74522. //o <ignore> tags for <file name=... platform=!this platform>
  74523. if ($platform == "!$os") {
  74524. $release[$releaseNum]['filelist']['ignore'][] =
  74525. array(
  74526. 'attribs' => array(
  74527. 'name' => $file,
  74528. ),
  74529. );
  74530. continue;
  74531. }
  74532. //o <ignore> tags for <file name=... platform=other platform>
  74533. if ($platform[0] != '!' && $platform != $os) {
  74534. $release[$releaseNum]['filelist']['ignore'][] =
  74535. array(
  74536. 'attribs' => array(
  74537. 'name' => $file,
  74538. ),
  74539. );
  74540. }
  74541. }
  74542. if (!count($release[$releaseNum]['filelist']['install'])) {
  74543. unset($release[$releaseNum]['filelist']['install']);
  74544. }
  74545. if (!count($release[$releaseNum]['filelist']['ignore'])) {
  74546. unset($release[$releaseNum]['filelist']['ignore']);
  74547. }
  74548. }
  74549. if (count($generic) || count($genericIgnore)) {
  74550. $release[count($oses)] = array();
  74551. if (count($generic)) {
  74552. foreach ($generic as $file) {
  74553. if (isset($package['install-as'][$file])) {
  74554. $installas = $package['install-as'][$file];
  74555. } else {
  74556. $installas = $file;
  74557. }
  74558. $release[count($oses)]['filelist']['install'][] =
  74559. array(
  74560. 'attribs' => array(
  74561. 'name' => $file,
  74562. 'as' => $installas,
  74563. )
  74564. );
  74565. }
  74566. }
  74567. if (count($genericIgnore)) {
  74568. foreach ($genericIgnore as $file) {
  74569. $release[count($oses)]['filelist']['ignore'][] =
  74570. array(
  74571. 'attribs' => array(
  74572. 'name' => $file,
  74573. )
  74574. );
  74575. }
  74576. }
  74577. }
  74578. // cleanup
  74579. foreach ($release as $i => $rel) {
  74580. if (isset($rel['filelist']['install']) &&
  74581. count($rel['filelist']['install']) == 1) {
  74582. $release[$i]['filelist']['install'] =
  74583. $release[$i]['filelist']['install'][0];
  74584. }
  74585. if (isset($rel['filelist']['ignore']) &&
  74586. count($rel['filelist']['ignore']) == 1) {
  74587. $release[$i]['filelist']['ignore'] =
  74588. $release[$i]['filelist']['ignore'][0];
  74589. }
  74590. }
  74591. if (count($release) == 1) {
  74592. $release = $release[0];
  74593. }
  74594. } else {
  74595. // no platform atts, but some install-as atts
  74596. foreach ($package['install-as'] as $file => $value) {
  74597. $release['filelist']['install'][] =
  74598. array(
  74599. 'attribs' => array(
  74600. 'name' => $file,
  74601. 'as' => $value
  74602. )
  74603. );
  74604. }
  74605. if (count($release['filelist']['install']) == 1) {
  74606. $release['filelist']['install'] = $release['filelist']['install'][0];
  74607. }
  74608. }
  74609. }
  74610. }
  74611. /**
  74612. * @param array
  74613. * @return array
  74614. * @access private
  74615. */
  74616. function _processDep($dep)
  74617. {
  74618. if ($dep['type'] == 'php') {
  74619. if ($dep['rel'] == 'has') {
  74620. // come on - everyone has php!
  74621. return false;
  74622. }
  74623. }
  74624. $php = array();
  74625. if ($dep['type'] != 'php') {
  74626. $php['name'] = $dep['name'];
  74627. if ($dep['type'] == 'pkg') {
  74628. $php['channel'] = 'pear.php.net';
  74629. }
  74630. }
  74631. switch ($dep['rel']) {
  74632. case 'gt' :
  74633. $php['min'] = $dep['version'];
  74634. $php['exclude'] = $dep['version'];
  74635. break;
  74636. case 'ge' :
  74637. if (!isset($dep['version'])) {
  74638. if ($dep['type'] == 'php') {
  74639. if (isset($dep['name'])) {
  74640. $dep['version'] = $dep['name'];
  74641. }
  74642. }
  74643. }
  74644. $php['min'] = $dep['version'];
  74645. break;
  74646. case 'lt' :
  74647. $php['max'] = $dep['version'];
  74648. $php['exclude'] = $dep['version'];
  74649. break;
  74650. case 'le' :
  74651. $php['max'] = $dep['version'];
  74652. break;
  74653. case 'eq' :
  74654. $php['min'] = $dep['version'];
  74655. $php['max'] = $dep['version'];
  74656. break;
  74657. case 'ne' :
  74658. $php['exclude'] = $dep['version'];
  74659. break;
  74660. case 'not' :
  74661. $php['conflicts'] = 'yes';
  74662. break;
  74663. }
  74664. return $php;
  74665. }
  74666. /**
  74667. * @param array
  74668. * @return array
  74669. */
  74670. function _processPhpDeps($deps)
  74671. {
  74672. $test = array();
  74673. foreach ($deps as $dep) {
  74674. $test[] = $this->_processDep($dep);
  74675. }
  74676. $min = array();
  74677. $max = array();
  74678. foreach ($test as $dep) {
  74679. if (!$dep) {
  74680. continue;
  74681. }
  74682. if (isset($dep['min'])) {
  74683. $min[$dep['min']] = count($min);
  74684. }
  74685. if (isset($dep['max'])) {
  74686. $max[$dep['max']] = count($max);
  74687. }
  74688. }
  74689. if (count($min) > 0) {
  74690. uksort($min, 'version_compare');
  74691. }
  74692. if (count($max) > 0) {
  74693. uksort($max, 'version_compare');
  74694. }
  74695. if (count($min)) {
  74696. // get the highest minimum
  74697. $a = array_flip($min);
  74698. $min = array_pop($a);
  74699. } else {
  74700. $min = false;
  74701. }
  74702. if (count($max)) {
  74703. // get the lowest maximum
  74704. $a = array_flip($max);
  74705. $max = array_shift($a);
  74706. } else {
  74707. $max = false;
  74708. }
  74709. if ($min) {
  74710. $php['min'] = $min;
  74711. }
  74712. if ($max) {
  74713. $php['max'] = $max;
  74714. }
  74715. $exclude = array();
  74716. foreach ($test as $dep) {
  74717. if (!isset($dep['exclude'])) {
  74718. continue;
  74719. }
  74720. $exclude[] = $dep['exclude'];
  74721. }
  74722. if (count($exclude)) {
  74723. $php['exclude'] = $exclude;
  74724. }
  74725. return $php;
  74726. }
  74727. /**
  74728. * process multiple dependencies that have a name, like package deps
  74729. * @param array
  74730. * @return array
  74731. * @access private
  74732. */
  74733. function _processMultipleDepsName($deps)
  74734. {
  74735. $ret = $tests = array();
  74736. foreach ($deps as $name => $dep) {
  74737. foreach ($dep as $d) {
  74738. $tests[$name][] = $this->_processDep($d);
  74739. }
  74740. }
  74741. foreach ($tests as $name => $test) {
  74742. $max = $min = $php = array();
  74743. $php['name'] = $name;
  74744. foreach ($test as $dep) {
  74745. if (!$dep) {
  74746. continue;
  74747. }
  74748. if (isset($dep['channel'])) {
  74749. $php['channel'] = 'pear.php.net';
  74750. }
  74751. if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
  74752. $php['conflicts'] = 'yes';
  74753. }
  74754. if (isset($dep['min'])) {
  74755. $min[$dep['min']] = count($min);
  74756. }
  74757. if (isset($dep['max'])) {
  74758. $max[$dep['max']] = count($max);
  74759. }
  74760. }
  74761. if (count($min) > 0) {
  74762. uksort($min, 'version_compare');
  74763. }
  74764. if (count($max) > 0) {
  74765. uksort($max, 'version_compare');
  74766. }
  74767. if (count($min)) {
  74768. // get the highest minimum
  74769. $a = array_flip($min);
  74770. $min = array_pop($a);
  74771. } else {
  74772. $min = false;
  74773. }
  74774. if (count($max)) {
  74775. // get the lowest maximum
  74776. $a = array_flip($max);
  74777. $max = array_shift($a);
  74778. } else {
  74779. $max = false;
  74780. }
  74781. if ($min) {
  74782. $php['min'] = $min;
  74783. }
  74784. if ($max) {
  74785. $php['max'] = $max;
  74786. }
  74787. $exclude = array();
  74788. foreach ($test as $dep) {
  74789. if (!isset($dep['exclude'])) {
  74790. continue;
  74791. }
  74792. $exclude[] = $dep['exclude'];
  74793. }
  74794. if (count($exclude)) {
  74795. $php['exclude'] = $exclude;
  74796. }
  74797. $ret[] = $php;
  74798. }
  74799. return $ret;
  74800. }
  74801. }
  74802. ?>
  74803. <?php
  74804. /**
  74805. * package.xml generation class, package.xml version 2.0
  74806. *
  74807. * PHP versions 4 and 5
  74808. *
  74809. * @category pear
  74810. * @package PEAR
  74811. * @author Greg Beaver <cellog@php.net>
  74812. * @author Stephan Schmidt (original XML_Serializer code)
  74813. * @copyright 1997-2009 The Authors
  74814. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  74815. * @link http://pear.php.net/package/PEAR
  74816. * @since File available since Release 1.4.0a1
  74817. */
  74818. /**
  74819. * file/dir manipulation routines
  74820. */
  74821. require_once 'phar://go-pear.phar/' . 'System.php';
  74822. require_once 'phar://go-pear.phar/' . 'XML/Util.php';
  74823. /**
  74824. * This class converts a PEAR_PackageFile_v2 object into any output format.
  74825. *
  74826. * Supported output formats include array, XML string (using S. Schmidt's
  74827. * XML_Serializer, slightly customized)
  74828. * @category pear
  74829. * @package PEAR
  74830. * @author Greg Beaver <cellog@php.net>
  74831. * @author Stephan Schmidt (original XML_Serializer code)
  74832. * @copyright 1997-2009 The Authors
  74833. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  74834. * @version Release: 1.10.10
  74835. * @link http://pear.php.net/package/PEAR
  74836. * @since Class available since Release 1.4.0a1
  74837. */
  74838. class PEAR_PackageFile_Generator_v2
  74839. {
  74840. /**
  74841. * default options for the serialization
  74842. * @access private
  74843. * @var array $_defaultOptions
  74844. */
  74845. var $_defaultOptions = array(
  74846. 'indent' => ' ', // string used for indentation
  74847. 'linebreak' => "\n", // string used for newlines
  74848. 'typeHints' => false, // automatically add type hin attributes
  74849. 'addDecl' => true, // add an XML declaration
  74850. 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
  74851. 'classAsTagName' => false, // use classname for objects in indexed arrays
  74852. 'keyAttribute' => '_originalKey', // attribute where original key is stored
  74853. 'typeAttribute' => '_type', // attribute for type (only if typeHints => true)
  74854. 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true)
  74855. 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute
  74856. 'prependAttributes' => '', // prepend string for attributes
  74857. 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
  74858. 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array
  74859. 'addDoctype' => false, // add a doctype declaration
  74860. 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
  74861. 'rootName' => 'package', // name of the root tag
  74862. 'rootAttributes' => array(
  74863. 'version' => '2.0',
  74864. 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
  74865. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  74866. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  74867. 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
  74868. http://pear.php.net/dtd/tasks-1.0.xsd
  74869. http://pear.php.net/dtd/package-2.0
  74870. http://pear.php.net/dtd/package-2.0.xsd',
  74871. ), // attributes of the root tag
  74872. 'attributesArray' => 'attribs', // all values in this key will be treated as attributes
  74873. 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjunction with attributesArray
  74874. 'beautifyFilelist' => false,
  74875. 'encoding' => 'UTF-8',
  74876. );
  74877. /**
  74878. * options for the serialization
  74879. * @access private
  74880. * @var array $options
  74881. */
  74882. var $options = array();
  74883. /**
  74884. * current tag depth
  74885. * @var integer $_tagDepth
  74886. */
  74887. var $_tagDepth = 0;
  74888. /**
  74889. * serilialized representation of the data
  74890. * @var string $_serializedData
  74891. */
  74892. var $_serializedData = null;
  74893. /**
  74894. * @var PEAR_PackageFile_v2
  74895. */
  74896. var $_packagefile;
  74897. /**
  74898. * @param PEAR_PackageFile_v2
  74899. */
  74900. function __construct(&$packagefile)
  74901. {
  74902. $this->_packagefile = &$packagefile;
  74903. if (isset($this->_packagefile->encoding)) {
  74904. $this->_defaultOptions['encoding'] = $this->_packagefile->encoding;
  74905. }
  74906. }
  74907. /**
  74908. * @return string
  74909. */
  74910. function getPackagerVersion()
  74911. {
  74912. return '1.10.10';
  74913. }
  74914. /**
  74915. * @param PEAR_Packager
  74916. * @param bool generate a .tgz or a .tar
  74917. * @param string|null temporary directory to package in
  74918. */
  74919. function toTgz(&$packager, $compress = true, $where = null)
  74920. {
  74921. $a = null;
  74922. return $this->toTgz2($packager, $a, $compress, $where);
  74923. }
  74924. /**
  74925. * Package up both a package.xml and package2.xml for the same release
  74926. * @param PEAR_Packager
  74927. * @param PEAR_PackageFile_v1
  74928. * @param bool generate a .tgz or a .tar
  74929. * @param string|null temporary directory to package in
  74930. */
  74931. function toTgz2(&$packager, &$pf1, $compress = true, $where = null)
  74932. {
  74933. require_once 'phar://go-pear.phar/' . 'Archive/Tar.php';
  74934. if (!$this->_packagefile->isEquivalent($pf1)) {
  74935. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' .
  74936. basename($pf1->getPackageFile()) .
  74937. '" is not equivalent to "' . basename($this->_packagefile->getPackageFile())
  74938. . '"');
  74939. }
  74940. if ($where === null) {
  74941. if (!($where = System::mktemp(array('-d')))) {
  74942. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed');
  74943. }
  74944. } elseif (!@System::mkDir(array('-p', $where))) {
  74945. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
  74946. ' not be created');
  74947. }
  74948. $file = $where . DIRECTORY_SEPARATOR . 'package.xml';
  74949. if (file_exists($file) && !is_file($file)) {
  74950. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
  74951. ' "' . $file .'"');
  74952. }
  74953. if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
  74954. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
  74955. }
  74956. $ext = $compress ? '.tgz' : '.tar';
  74957. $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion();
  74958. $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
  74959. if (file_exists($dest_package) && !is_file($dest_package)) {
  74960. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
  74961. $dest_package . '"');
  74962. }
  74963. $pkgfile = $this->_packagefile->getPackageFile();
  74964. if (!$pkgfile) {
  74965. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
  74966. 'be created from a real file');
  74967. }
  74968. $pkgdir = dirname(realpath($pkgfile));
  74969. $pkgfile = basename($pkgfile);
  74970. // {{{ Create the package file list
  74971. $filelist = array();
  74972. $i = 0;
  74973. $this->_packagefile->flattenFilelist();
  74974. $contents = $this->_packagefile->getContents();
  74975. if (isset($contents['bundledpackage'])) { // bundles of packages
  74976. $contents = $contents['bundledpackage'];
  74977. if (!isset($contents[0])) {
  74978. $contents = array($contents);
  74979. }
  74980. $packageDir = $where;
  74981. foreach ($contents as $i => $package) {
  74982. $fname = $package;
  74983. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  74984. if (!file_exists($file)) {
  74985. return $packager->raiseError("File does not exist: $fname");
  74986. }
  74987. $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
  74988. System::mkdir(array('-p', dirname($tfile)));
  74989. copy($file, $tfile);
  74990. $filelist[$i++] = $tfile;
  74991. $packager->log(2, "Adding package $fname");
  74992. }
  74993. } else { // normal packages
  74994. $contents = $contents['dir']['file'];
  74995. if (!isset($contents[0])) {
  74996. $contents = array($contents);
  74997. }
  74998. $packageDir = $where;
  74999. foreach ($contents as $i => $file) {
  75000. $fname = $file['attribs']['name'];
  75001. $atts = $file['attribs'];
  75002. $orig = $file;
  75003. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  75004. if (!file_exists($file)) {
  75005. return $packager->raiseError("File does not exist: $fname");
  75006. }
  75007. $origperms = fileperms($file);
  75008. $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
  75009. unset($orig['attribs']);
  75010. if (count($orig)) { // file with tasks
  75011. // run any package-time tasks
  75012. $contents = file_get_contents($file);
  75013. foreach ($orig as $tag => $raw) {
  75014. $tag = str_replace(
  75015. array($this->_packagefile->getTasksNs() . ':', '-'),
  75016. array('', '_'), $tag);
  75017. $task = "PEAR_Task_$tag";
  75018. $task = new $task($this->_packagefile->_config,
  75019. $this->_packagefile->_logger,
  75020. PEAR_TASK_PACKAGE);
  75021. $task->init($raw, $atts, null);
  75022. $res = $task->startSession($this->_packagefile, $contents, $tfile);
  75023. if (!$res) {
  75024. continue; // skip this task
  75025. }
  75026. if (PEAR::isError($res)) {
  75027. return $res;
  75028. }
  75029. $contents = $res; // save changes
  75030. System::mkdir(array('-p', dirname($tfile)));
  75031. $wp = fopen($tfile, "wb");
  75032. fwrite($wp, $contents);
  75033. fclose($wp);
  75034. }
  75035. }
  75036. if (!file_exists($tfile)) {
  75037. System::mkdir(array('-p', dirname($tfile)));
  75038. copy($file, $tfile);
  75039. }
  75040. chmod($tfile, $origperms);
  75041. $filelist[$i++] = $tfile;
  75042. $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1);
  75043. $packager->log(2, "Adding file $fname");
  75044. }
  75045. }
  75046. // }}}
  75047. $name = $pf1 !== null ? 'package2.xml' : 'package.xml';
  75048. $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name);
  75049. if ($packagexml) {
  75050. $tar = new Archive_Tar($dest_package, $compress);
  75051. $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
  75052. // ----- Creates with the package.xml file
  75053. $ok = $tar->createModify(array($packagexml), '', $where);
  75054. if (PEAR::isError($ok)) {
  75055. return $packager->raiseError($ok);
  75056. } elseif (!$ok) {
  75057. return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
  75058. ' failed');
  75059. }
  75060. // ----- Add the content of the package
  75061. if (!$tar->addModify($filelist, $pkgver, $where)) {
  75062. return $packager->raiseError(
  75063. 'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
  75064. }
  75065. // add the package.xml version 1.0
  75066. if ($pf1 !== null) {
  75067. $pfgen = &$pf1->getDefaultGenerator();
  75068. $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
  75069. if (!$tar->addModify(array($packagexml1), '', $where)) {
  75070. return $packager->raiseError(
  75071. 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
  75072. }
  75073. }
  75074. return $dest_package;
  75075. }
  75076. }
  75077. function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml')
  75078. {
  75079. if (!$this->_packagefile->validate($state)) {
  75080. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
  75081. null, null, null, $this->_packagefile->getValidationWarnings());
  75082. }
  75083. if ($where === null) {
  75084. if (!($where = System::mktemp(array('-d')))) {
  75085. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
  75086. }
  75087. } elseif (!@System::mkDir(array('-p', $where))) {
  75088. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
  75089. ' not be created');
  75090. }
  75091. $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
  75092. $np = @fopen($newpkgfile, 'wb');
  75093. if (!$np) {
  75094. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
  75095. "$name as $newpkgfile");
  75096. }
  75097. fwrite($np, $this->toXml($state));
  75098. fclose($np);
  75099. return $newpkgfile;
  75100. }
  75101. function &toV2()
  75102. {
  75103. return $this->_packagefile;
  75104. }
  75105. /**
  75106. * Return an XML document based on the package info (as returned
  75107. * by the PEAR_Common::infoFrom* methods).
  75108. *
  75109. * @return string XML data
  75110. */
  75111. function toXml($state = PEAR_VALIDATE_NORMAL, $options = array())
  75112. {
  75113. $this->_packagefile->setDate(date('Y-m-d'));
  75114. $this->_packagefile->setTime(date('H:i:s'));
  75115. if (!$this->_packagefile->validate($state)) {
  75116. return false;
  75117. }
  75118. if (is_array($options)) {
  75119. $this->options = array_merge($this->_defaultOptions, $options);
  75120. } else {
  75121. $this->options = $this->_defaultOptions;
  75122. }
  75123. $arr = $this->_packagefile->getArray();
  75124. if (isset($arr['filelist'])) {
  75125. unset($arr['filelist']);
  75126. }
  75127. if (isset($arr['_lastversion'])) {
  75128. unset($arr['_lastversion']);
  75129. }
  75130. // Fix the notes a little bit
  75131. if (isset($arr['notes'])) {
  75132. // This trims out the indenting, needs fixing
  75133. $arr['notes'] = "\n" . trim($arr['notes']) . "\n";
  75134. }
  75135. if (isset($arr['changelog']) && !empty($arr['changelog'])) {
  75136. // Fix for inconsistency how the array is filled depending on the changelog release amount
  75137. if (!isset($arr['changelog']['release'][0])) {
  75138. $release = $arr['changelog']['release'];
  75139. unset($arr['changelog']['release']);
  75140. $arr['changelog']['release'] = array();
  75141. $arr['changelog']['release'][0] = $release;
  75142. }
  75143. foreach (array_keys($arr['changelog']['release']) as $key) {
  75144. $c =& $arr['changelog']['release'][$key];
  75145. if (isset($c['notes'])) {
  75146. // This trims out the indenting, needs fixing
  75147. $c['notes'] = "\n" . trim($c['notes']) . "\n";
  75148. }
  75149. }
  75150. }
  75151. if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) {
  75152. $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']);
  75153. unset($arr['contents']['dir']['file']);
  75154. if (isset($use['dir'])) {
  75155. $arr['contents']['dir']['dir'] = $use['dir'];
  75156. }
  75157. if (isset($use['file'])) {
  75158. $arr['contents']['dir']['file'] = $use['file'];
  75159. }
  75160. $this->options['beautifyFilelist'] = true;
  75161. }
  75162. $arr['attribs']['packagerversion'] = '1.10.10';
  75163. if ($this->serialize($arr, $options)) {
  75164. return $this->_serializedData . "\n";
  75165. }
  75166. return false;
  75167. }
  75168. function _recursiveXmlFilelist($list)
  75169. {
  75170. $dirs = array();
  75171. if (isset($list['attribs'])) {
  75172. $file = $list['attribs']['name'];
  75173. unset($list['attribs']['name']);
  75174. $attributes = $list['attribs'];
  75175. $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes);
  75176. } else {
  75177. foreach ($list as $a) {
  75178. $file = $a['attribs']['name'];
  75179. $attributes = $a['attribs'];
  75180. unset($a['attribs']);
  75181. $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a);
  75182. }
  75183. }
  75184. $this->_formatDir($dirs);
  75185. $this->_deFormat($dirs);
  75186. return $dirs;
  75187. }
  75188. function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null)
  75189. {
  75190. if (!$tasks) {
  75191. $tasks = array();
  75192. }
  75193. if ($dir == array() || $dir == array('.')) {
  75194. $dirs['file'][basename($file)] = $tasks;
  75195. $attributes['name'] = basename($file);
  75196. $dirs['file'][basename($file)]['attribs'] = $attributes;
  75197. return;
  75198. }
  75199. $curdir = array_shift($dir);
  75200. if (!isset($dirs['dir'][$curdir])) {
  75201. $dirs['dir'][$curdir] = array();
  75202. }
  75203. $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks);
  75204. }
  75205. function _formatDir(&$dirs)
  75206. {
  75207. if (!count($dirs)) {
  75208. return array();
  75209. }
  75210. $newdirs = array();
  75211. if (isset($dirs['dir'])) {
  75212. $newdirs['dir'] = $dirs['dir'];
  75213. }
  75214. if (isset($dirs['file'])) {
  75215. $newdirs['file'] = $dirs['file'];
  75216. }
  75217. $dirs = $newdirs;
  75218. if (isset($dirs['dir'])) {
  75219. uksort($dirs['dir'], 'strnatcasecmp');
  75220. foreach ($dirs['dir'] as $dir => $contents) {
  75221. $this->_formatDir($dirs['dir'][$dir]);
  75222. }
  75223. }
  75224. if (isset($dirs['file'])) {
  75225. uksort($dirs['file'], 'strnatcasecmp');
  75226. };
  75227. }
  75228. function _deFormat(&$dirs)
  75229. {
  75230. if (!count($dirs)) {
  75231. return array();
  75232. }
  75233. $newdirs = array();
  75234. if (isset($dirs['dir'])) {
  75235. foreach ($dirs['dir'] as $dir => $contents) {
  75236. $newdir = array();
  75237. $newdir['attribs']['name'] = $dir;
  75238. $this->_deFormat($contents);
  75239. foreach ($contents as $tag => $val) {
  75240. $newdir[$tag] = $val;
  75241. }
  75242. $newdirs['dir'][] = $newdir;
  75243. }
  75244. if (count($newdirs['dir']) == 1) {
  75245. $newdirs['dir'] = $newdirs['dir'][0];
  75246. }
  75247. }
  75248. if (isset($dirs['file'])) {
  75249. foreach ($dirs['file'] as $name => $file) {
  75250. $newdirs['file'][] = $file;
  75251. }
  75252. if (count($newdirs['file']) == 1) {
  75253. $newdirs['file'] = $newdirs['file'][0];
  75254. }
  75255. }
  75256. $dirs = $newdirs;
  75257. }
  75258. /**
  75259. * reset all options to default options
  75260. *
  75261. * @access public
  75262. * @see setOption(), XML_Unserializer()
  75263. */
  75264. function resetOptions()
  75265. {
  75266. $this->options = $this->_defaultOptions;
  75267. }
  75268. /**
  75269. * set an option
  75270. *
  75271. * You can use this method if you do not want to set all options in the constructor
  75272. *
  75273. * @access public
  75274. * @see resetOption(), XML_Serializer()
  75275. */
  75276. function setOption($name, $value)
  75277. {
  75278. $this->options[$name] = $value;
  75279. }
  75280. /**
  75281. * sets several options at once
  75282. *
  75283. * You can use this method if you do not want to set all options in the constructor
  75284. *
  75285. * @access public
  75286. * @see resetOption(), XML_Unserializer(), setOption()
  75287. */
  75288. function setOptions($options)
  75289. {
  75290. $this->options = array_merge($this->options, $options);
  75291. }
  75292. /**
  75293. * serialize data
  75294. *
  75295. * @access public
  75296. * @param mixed $data data to serialize
  75297. * @return boolean true on success, pear error on failure
  75298. */
  75299. function serialize($data, $options = null)
  75300. {
  75301. // if options have been specified, use them instead
  75302. // of the previously defined ones
  75303. if (is_array($options)) {
  75304. $optionsBak = $this->options;
  75305. if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
  75306. $this->options = array_merge($this->_defaultOptions, $options);
  75307. } else {
  75308. $this->options = array_merge($this->options, $options);
  75309. }
  75310. } else {
  75311. $optionsBak = null;
  75312. }
  75313. // start depth is zero
  75314. $this->_tagDepth = 0;
  75315. $this->_serializedData = '';
  75316. // serialize an array
  75317. if (is_array($data)) {
  75318. $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array';
  75319. $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']);
  75320. }
  75321. // add doctype declaration
  75322. if ($this->options['addDoctype'] === true) {
  75323. $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype'])
  75324. . $this->options['linebreak']
  75325. . $this->_serializedData;
  75326. }
  75327. // build xml declaration
  75328. if ($this->options['addDecl']) {
  75329. $atts = array();
  75330. $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null;
  75331. $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding)
  75332. . $this->options['linebreak']
  75333. . $this->_serializedData;
  75334. }
  75335. if ($optionsBak !== null) {
  75336. $this->options = $optionsBak;
  75337. }
  75338. return true;
  75339. }
  75340. /**
  75341. * get the result of the serialization
  75342. *
  75343. * @access public
  75344. * @return string serialized XML
  75345. */
  75346. function getSerializedData()
  75347. {
  75348. if ($this->_serializedData === null) {
  75349. return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
  75350. }
  75351. return $this->_serializedData;
  75352. }
  75353. /**
  75354. * serialize any value
  75355. *
  75356. * This method checks for the type of the value and calls the appropriate method
  75357. *
  75358. * @access private
  75359. * @param mixed $value
  75360. * @param string $tagName
  75361. * @param array $attributes
  75362. * @return string
  75363. */
  75364. function _serializeValue($value, $tagName = null, $attributes = array())
  75365. {
  75366. if (is_array($value)) {
  75367. $xml = $this->_serializeArray($value, $tagName, $attributes);
  75368. } elseif (is_object($value)) {
  75369. $xml = $this->_serializeObject($value, $tagName);
  75370. } else {
  75371. $tag = array(
  75372. 'qname' => $tagName,
  75373. 'attributes' => $attributes,
  75374. 'content' => $value
  75375. );
  75376. $xml = $this->_createXMLTag($tag);
  75377. }
  75378. return $xml;
  75379. }
  75380. /**
  75381. * serialize an array
  75382. *
  75383. * @access private
  75384. * @param array $array array to serialize
  75385. * @param string $tagName name of the root tag
  75386. * @param array $attributes attributes for the root tag
  75387. * @return string $string serialized data
  75388. * @uses XML_Util::isValidName() to check, whether key has to be substituted
  75389. */
  75390. function _serializeArray(&$array, $tagName = null, $attributes = array())
  75391. {
  75392. $_content = null;
  75393. /**
  75394. * check for special attributes
  75395. */
  75396. if ($this->options['attributesArray'] !== null) {
  75397. if (isset($array[$this->options['attributesArray']])) {
  75398. $attributes = $array[$this->options['attributesArray']];
  75399. unset($array[$this->options['attributesArray']]);
  75400. }
  75401. /**
  75402. * check for special content
  75403. */
  75404. if ($this->options['contentName'] !== null) {
  75405. if (isset($array[$this->options['contentName']])) {
  75406. $_content = $array[$this->options['contentName']];
  75407. unset($array[$this->options['contentName']]);
  75408. }
  75409. }
  75410. }
  75411. /*
  75412. * if mode is set to simpleXML, check whether
  75413. * the array is associative or indexed
  75414. */
  75415. if (is_array($array) && $this->options['mode'] == 'simplexml') {
  75416. $indexed = true;
  75417. if (!count($array)) {
  75418. $indexed = false;
  75419. }
  75420. foreach ($array as $key => $val) {
  75421. if (!is_int($key)) {
  75422. $indexed = false;
  75423. break;
  75424. }
  75425. }
  75426. if ($indexed && $this->options['mode'] == 'simplexml') {
  75427. $string = '';
  75428. foreach ($array as $key => $val) {
  75429. if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
  75430. if (!isset($this->_curdir)) {
  75431. $this->_curdir = '';
  75432. }
  75433. $savedir = $this->_curdir;
  75434. if (isset($val['attribs'])) {
  75435. if ($val['attribs']['name'] == '/') {
  75436. $this->_curdir = '/';
  75437. } else {
  75438. if ($this->_curdir == '/') {
  75439. $this->_curdir = '';
  75440. }
  75441. $this->_curdir .= '/' . $val['attribs']['name'];
  75442. }
  75443. }
  75444. }
  75445. $string .= $this->_serializeValue( $val, $tagName, $attributes);
  75446. if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
  75447. $string .= ' <!-- ' . $this->_curdir . ' -->';
  75448. if (empty($savedir)) {
  75449. unset($this->_curdir);
  75450. } else {
  75451. $this->_curdir = $savedir;
  75452. }
  75453. }
  75454. $string .= $this->options['linebreak'];
  75455. // do indentation
  75456. if ($this->options['indent'] !== null && $this->_tagDepth > 0) {
  75457. $string .= str_repeat($this->options['indent'], $this->_tagDepth);
  75458. }
  75459. }
  75460. return rtrim($string);
  75461. }
  75462. }
  75463. if ($this->options['scalarAsAttributes'] === true) {
  75464. foreach ($array as $key => $value) {
  75465. if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
  75466. unset($array[$key]);
  75467. $attributes[$this->options['prependAttributes'].$key] = $value;
  75468. }
  75469. }
  75470. }
  75471. // check for empty array => create empty tag
  75472. if (empty($array)) {
  75473. $tag = array(
  75474. 'qname' => $tagName,
  75475. 'content' => $_content,
  75476. 'attributes' => $attributes
  75477. );
  75478. } else {
  75479. $this->_tagDepth++;
  75480. $tmp = $this->options['linebreak'];
  75481. foreach ($array as $key => $value) {
  75482. // do indentation
  75483. if ($this->options['indent'] !== null && $this->_tagDepth > 0) {
  75484. $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
  75485. }
  75486. // copy key
  75487. $origKey = $key;
  75488. // key cannot be used as tagname => use default tag
  75489. $valid = XML_Util::isValidName($key);
  75490. if (PEAR::isError($valid)) {
  75491. if ($this->options['classAsTagName'] && is_object($value)) {
  75492. $key = get_class($value);
  75493. } else {
  75494. $key = $this->options['defaultTagName'];
  75495. }
  75496. }
  75497. $atts = array();
  75498. if ($this->options['typeHints'] === true) {
  75499. $atts[$this->options['typeAttribute']] = gettype($value);
  75500. if ($key !== $origKey) {
  75501. $atts[$this->options['keyAttribute']] = (string)$origKey;
  75502. }
  75503. }
  75504. if ($this->options['beautifyFilelist'] && $key == 'dir') {
  75505. if (!isset($this->_curdir)) {
  75506. $this->_curdir = '';
  75507. }
  75508. $savedir = $this->_curdir;
  75509. if (isset($value['attribs'])) {
  75510. if ($value['attribs']['name'] == '/') {
  75511. $this->_curdir = '/';
  75512. } else {
  75513. $this->_curdir .= '/' . $value['attribs']['name'];
  75514. }
  75515. }
  75516. }
  75517. if (is_string($value) && $value && ($value[strlen($value) - 1] == "\n")) {
  75518. $value .= str_repeat($this->options['indent'], $this->_tagDepth);
  75519. }
  75520. $tmp .= $this->_createXMLTag(array(
  75521. 'qname' => $key,
  75522. 'attributes' => $atts,
  75523. 'content' => $value )
  75524. );
  75525. if ($this->options['beautifyFilelist'] && $key == 'dir') {
  75526. if (isset($value['attribs'])) {
  75527. $tmp .= ' <!-- ' . $this->_curdir . ' -->';
  75528. if (empty($savedir)) {
  75529. unset($this->_curdir);
  75530. } else {
  75531. $this->_curdir = $savedir;
  75532. }
  75533. }
  75534. }
  75535. $tmp .= $this->options['linebreak'];
  75536. }
  75537. $this->_tagDepth--;
  75538. if ($this->options['indent']!==null && $this->_tagDepth>0) {
  75539. $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
  75540. }
  75541. if (trim($tmp) === '') {
  75542. $tmp = null;
  75543. }
  75544. $tag = array(
  75545. 'qname' => $tagName,
  75546. 'content' => $tmp,
  75547. 'attributes' => $attributes
  75548. );
  75549. }
  75550. if ($this->options['typeHints'] === true) {
  75551. if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
  75552. $tag['attributes'][$this->options['typeAttribute']] = 'array';
  75553. }
  75554. }
  75555. $string = $this->_createXMLTag($tag, false);
  75556. return $string;
  75557. }
  75558. /**
  75559. * create a tag from an array
  75560. * this method awaits an array in the following format
  75561. * array(
  75562. * 'qname' => $tagName,
  75563. * 'attributes' => array(),
  75564. * 'content' => $content, // optional
  75565. * 'namespace' => $namespace // optional
  75566. * 'namespaceUri' => $namespaceUri // optional
  75567. * )
  75568. *
  75569. * @access private
  75570. * @param array $tag tag definition
  75571. * @param boolean $replaceEntities whether to replace XML entities in content or not
  75572. * @return string $string XML tag
  75573. */
  75574. function _createXMLTag($tag, $replaceEntities = true)
  75575. {
  75576. if ($this->options['indentAttributes'] !== false) {
  75577. $multiline = true;
  75578. $indent = str_repeat($this->options['indent'], $this->_tagDepth);
  75579. if ($this->options['indentAttributes'] == '_auto') {
  75580. $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
  75581. } else {
  75582. $indent .= $this->options['indentAttributes'];
  75583. }
  75584. } else {
  75585. $indent = $multiline = false;
  75586. }
  75587. if (is_array($tag['content'])) {
  75588. if (empty($tag['content'])) {
  75589. $tag['content'] = '';
  75590. }
  75591. } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
  75592. $tag['content'] = '';
  75593. }
  75594. if (is_scalar($tag['content']) || is_null($tag['content'])) {
  75595. if ($replaceEntities === true) {
  75596. $replaceEntities = XML_UTIL_ENTITIES_XML;
  75597. }
  75598. $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']);
  75599. } elseif (is_array($tag['content'])) {
  75600. $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
  75601. } elseif (is_object($tag['content'])) {
  75602. $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
  75603. } elseif (is_resource($tag['content'])) {
  75604. settype($tag['content'], 'string');
  75605. $tag = XML_Util::createTagFromArray($tag, $replaceEntities);
  75606. }
  75607. return $tag;
  75608. }
  75609. }
  75610. <?php
  75611. /**
  75612. * package.xml parsing class, package.xml version 1.0
  75613. *
  75614. * PHP versions 4 and 5
  75615. *
  75616. * @category pear
  75617. * @package PEAR
  75618. * @author Greg Beaver <cellog@php.net>
  75619. * @copyright 1997-2009 The Authors
  75620. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  75621. * @link http://pear.php.net/package/PEAR
  75622. * @since File available since Release 1.4.0a1
  75623. */
  75624. /**
  75625. * package.xml abstraction class
  75626. */
  75627. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  75628. /**
  75629. * Parser for package.xml version 1.0
  75630. * @category pear
  75631. * @package PEAR
  75632. * @author Greg Beaver <cellog@php.net>
  75633. * @copyright 1997-2009 The Authors
  75634. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  75635. * @version Release: 1.10.10
  75636. * @link http://pear.php.net/package/PEAR
  75637. * @since Class available since Release 1.4.0a1
  75638. */
  75639. class PEAR_PackageFile_Parser_v1
  75640. {
  75641. var $_registry;
  75642. var $_config;
  75643. var $_logger;
  75644. /**
  75645. * BC hack to allow PEAR_Common::infoFromString() to sort of
  75646. * work with the version 2.0 format - there's no filelist though
  75647. * @param PEAR_PackageFile_v2
  75648. */
  75649. function fromV2($packagefile)
  75650. {
  75651. $info = $packagefile->getArray(true);
  75652. $ret = new PEAR_PackageFile_v1;
  75653. $ret->fromArray($info['old']);
  75654. }
  75655. function setConfig(&$c)
  75656. {
  75657. $this->_config = &$c;
  75658. $this->_registry = &$c->getRegistry();
  75659. }
  75660. function setLogger(&$l)
  75661. {
  75662. $this->_logger = &$l;
  75663. }
  75664. /**
  75665. * @param string contents of package.xml file, version 1.0
  75666. * @return bool success of parsing
  75667. */
  75668. function &parse($data, $file, $archive = false)
  75669. {
  75670. if (!extension_loaded('xml')) {
  75671. return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension');
  75672. }
  75673. $xp = xml_parser_create();
  75674. if (!$xp) {
  75675. $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml');
  75676. return $a;
  75677. }
  75678. xml_set_object($xp, $this);
  75679. xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0');
  75680. xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0');
  75681. xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
  75682. $this->element_stack = array();
  75683. $this->_packageInfo = array('provides' => array());
  75684. $this->current_element = false;
  75685. unset($this->dir_install);
  75686. $this->_packageInfo['filelist'] = array();
  75687. $this->filelist =& $this->_packageInfo['filelist'];
  75688. $this->dir_names = array();
  75689. $this->in_changelog = false;
  75690. $this->d_i = 0;
  75691. $this->cdata = '';
  75692. $this->_isValid = true;
  75693. if (!xml_parse($xp, $data, 1)) {
  75694. $code = xml_get_error_code($xp);
  75695. $line = xml_get_current_line_number($xp);
  75696. xml_parser_free($xp);
  75697. $a = PEAR::raiseError(sprintf("XML error: %s at line %d",
  75698. $str = xml_error_string($code), $line), 2);
  75699. return $a;
  75700. }
  75701. xml_parser_free($xp);
  75702. $pf = new PEAR_PackageFile_v1;
  75703. $pf->setConfig($this->_config);
  75704. if (isset($this->_logger)) {
  75705. $pf->setLogger($this->_logger);
  75706. }
  75707. $pf->setPackagefile($file, $archive);
  75708. $pf->fromArray($this->_packageInfo);
  75709. return $pf;
  75710. }
  75711. // {{{ _unIndent()
  75712. /**
  75713. * Unindent given string
  75714. *
  75715. * @param string $str The string that has to be unindented.
  75716. * @return string
  75717. * @access private
  75718. */
  75719. function _unIndent($str)
  75720. {
  75721. // remove leading newlines
  75722. $str = preg_replace('/^[\r\n]+/', '', $str);
  75723. // find whitespace at the beginning of the first line
  75724. $indent_len = strspn($str, " \t");
  75725. $indent = substr($str, 0, $indent_len);
  75726. $data = '';
  75727. // remove the same amount of whitespace from following lines
  75728. foreach (explode("\n", $str) as $line) {
  75729. if (substr($line, 0, $indent_len) == $indent) {
  75730. $data .= substr($line, $indent_len) . "\n";
  75731. } elseif (trim(substr($line, 0, $indent_len))) {
  75732. $data .= ltrim($line);
  75733. }
  75734. }
  75735. return $data;
  75736. }
  75737. // Support for package DTD v1.0:
  75738. // {{{ _element_start_1_0()
  75739. /**
  75740. * XML parser callback for ending elements. Used for version 1.0
  75741. * packages.
  75742. *
  75743. * @param resource $xp XML parser resource
  75744. * @param string $name name of ending element
  75745. *
  75746. * @return void
  75747. *
  75748. * @access private
  75749. */
  75750. function _element_start_1_0($xp, $name, $attribs)
  75751. {
  75752. array_push($this->element_stack, $name);
  75753. $this->current_element = $name;
  75754. $spos = sizeof($this->element_stack) - 2;
  75755. $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
  75756. $this->current_attributes = $attribs;
  75757. $this->cdata = '';
  75758. switch ($name) {
  75759. case 'dir':
  75760. if ($this->in_changelog) {
  75761. break;
  75762. }
  75763. if (array_key_exists('name', $attribs) && $attribs['name'] != '/') {
  75764. $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
  75765. $attribs['name']);
  75766. if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) {
  75767. $attribs['name'] = substr($attribs['name'], 0,
  75768. strlen($attribs['name']) - 1);
  75769. }
  75770. if (strpos($attribs['name'], '/') === 0) {
  75771. $attribs['name'] = substr($attribs['name'], 1);
  75772. }
  75773. $this->dir_names[] = $attribs['name'];
  75774. }
  75775. if (isset($attribs['baseinstalldir'])) {
  75776. $this->dir_install = $attribs['baseinstalldir'];
  75777. }
  75778. if (isset($attribs['role'])) {
  75779. $this->dir_role = $attribs['role'];
  75780. }
  75781. break;
  75782. case 'file':
  75783. if ($this->in_changelog) {
  75784. break;
  75785. }
  75786. if (isset($attribs['name'])) {
  75787. $path = '';
  75788. if (count($this->dir_names)) {
  75789. foreach ($this->dir_names as $dir) {
  75790. $path .= $dir . '/';
  75791. }
  75792. }
  75793. $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
  75794. $attribs['name']);
  75795. unset($attribs['name']);
  75796. $this->current_path = $path;
  75797. $this->filelist[$path] = $attribs;
  75798. // Set the baseinstalldir only if the file don't have this attrib
  75799. if (!isset($this->filelist[$path]['baseinstalldir']) &&
  75800. isset($this->dir_install))
  75801. {
  75802. $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
  75803. }
  75804. // Set the Role
  75805. if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
  75806. $this->filelist[$path]['role'] = $this->dir_role;
  75807. }
  75808. }
  75809. break;
  75810. case 'replace':
  75811. if (!$this->in_changelog) {
  75812. $this->filelist[$this->current_path]['replacements'][] = $attribs;
  75813. }
  75814. break;
  75815. case 'maintainers':
  75816. $this->_packageInfo['maintainers'] = array();
  75817. $this->m_i = 0; // maintainers array index
  75818. break;
  75819. case 'maintainer':
  75820. // compatibility check
  75821. if (!isset($this->_packageInfo['maintainers'])) {
  75822. $this->_packageInfo['maintainers'] = array();
  75823. $this->m_i = 0;
  75824. }
  75825. $this->_packageInfo['maintainers'][$this->m_i] = array();
  75826. $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i];
  75827. break;
  75828. case 'changelog':
  75829. $this->_packageInfo['changelog'] = array();
  75830. $this->c_i = 0; // changelog array index
  75831. $this->in_changelog = true;
  75832. break;
  75833. case 'release':
  75834. if ($this->in_changelog) {
  75835. $this->_packageInfo['changelog'][$this->c_i] = array();
  75836. $this->current_release = &$this->_packageInfo['changelog'][$this->c_i];
  75837. } else {
  75838. $this->current_release = &$this->_packageInfo;
  75839. }
  75840. break;
  75841. case 'deps':
  75842. if (!$this->in_changelog) {
  75843. $this->_packageInfo['release_deps'] = array();
  75844. }
  75845. break;
  75846. case 'dep':
  75847. // dependencies array index
  75848. if (!$this->in_changelog) {
  75849. $this->d_i++;
  75850. isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false;
  75851. $this->_packageInfo['release_deps'][$this->d_i] = $attribs;
  75852. }
  75853. break;
  75854. case 'configureoptions':
  75855. if (!$this->in_changelog) {
  75856. $this->_packageInfo['configure_options'] = array();
  75857. }
  75858. break;
  75859. case 'configureoption':
  75860. if (!$this->in_changelog) {
  75861. $this->_packageInfo['configure_options'][] = $attribs;
  75862. }
  75863. break;
  75864. case 'provides':
  75865. if (empty($attribs['type']) || empty($attribs['name'])) {
  75866. break;
  75867. }
  75868. $attribs['explicit'] = true;
  75869. $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs;
  75870. break;
  75871. case 'package' :
  75872. if (isset($attribs['version'])) {
  75873. $this->_packageInfo['xsdversion'] = trim($attribs['version']);
  75874. } else {
  75875. $this->_packageInfo['xsdversion'] = '1.0';
  75876. }
  75877. if (isset($attribs['packagerversion'])) {
  75878. $this->_packageInfo['packagerversion'] = $attribs['packagerversion'];
  75879. }
  75880. break;
  75881. }
  75882. }
  75883. // }}}
  75884. // {{{ _element_end_1_0()
  75885. /**
  75886. * XML parser callback for ending elements. Used for version 1.0
  75887. * packages.
  75888. *
  75889. * @param resource $xp XML parser resource
  75890. * @param string $name name of ending element
  75891. *
  75892. * @return void
  75893. *
  75894. * @access private
  75895. */
  75896. function _element_end_1_0($xp, $name)
  75897. {
  75898. $data = trim($this->cdata);
  75899. switch ($name) {
  75900. case 'name':
  75901. switch ($this->prev_element) {
  75902. case 'package':
  75903. $this->_packageInfo['package'] = $data;
  75904. break;
  75905. case 'maintainer':
  75906. $this->current_maintainer['name'] = $data;
  75907. break;
  75908. }
  75909. break;
  75910. case 'extends' :
  75911. $this->_packageInfo['extends'] = $data;
  75912. break;
  75913. case 'summary':
  75914. $this->_packageInfo['summary'] = $data;
  75915. break;
  75916. case 'description':
  75917. $data = $this->_unIndent($this->cdata);
  75918. $this->_packageInfo['description'] = $data;
  75919. break;
  75920. case 'user':
  75921. $this->current_maintainer['handle'] = $data;
  75922. break;
  75923. case 'email':
  75924. $this->current_maintainer['email'] = $data;
  75925. break;
  75926. case 'role':
  75927. $this->current_maintainer['role'] = $data;
  75928. break;
  75929. case 'version':
  75930. if ($this->in_changelog) {
  75931. $this->current_release['version'] = $data;
  75932. } else {
  75933. $this->_packageInfo['version'] = $data;
  75934. }
  75935. break;
  75936. case 'date':
  75937. if ($this->in_changelog) {
  75938. $this->current_release['release_date'] = $data;
  75939. } else {
  75940. $this->_packageInfo['release_date'] = $data;
  75941. }
  75942. break;
  75943. case 'notes':
  75944. // try to "de-indent" release notes in case someone
  75945. // has been over-indenting their xml ;-)
  75946. // Trim only on the right side
  75947. $data = rtrim($this->_unIndent($this->cdata));
  75948. if ($this->in_changelog) {
  75949. $this->current_release['release_notes'] = $data;
  75950. } else {
  75951. $this->_packageInfo['release_notes'] = $data;
  75952. }
  75953. break;
  75954. case 'warnings':
  75955. if ($this->in_changelog) {
  75956. $this->current_release['release_warnings'] = $data;
  75957. } else {
  75958. $this->_packageInfo['release_warnings'] = $data;
  75959. }
  75960. break;
  75961. case 'state':
  75962. if ($this->in_changelog) {
  75963. $this->current_release['release_state'] = $data;
  75964. } else {
  75965. $this->_packageInfo['release_state'] = $data;
  75966. }
  75967. break;
  75968. case 'license':
  75969. if ($this->in_changelog) {
  75970. $this->current_release['release_license'] = $data;
  75971. } else {
  75972. $this->_packageInfo['release_license'] = $data;
  75973. }
  75974. break;
  75975. case 'dep':
  75976. if ($data && !$this->in_changelog) {
  75977. $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data;
  75978. }
  75979. break;
  75980. case 'dir':
  75981. if ($this->in_changelog) {
  75982. break;
  75983. }
  75984. array_pop($this->dir_names);
  75985. break;
  75986. case 'file':
  75987. if ($this->in_changelog) {
  75988. break;
  75989. }
  75990. if ($data) {
  75991. $path = '';
  75992. if (count($this->dir_names)) {
  75993. foreach ($this->dir_names as $dir) {
  75994. $path .= $dir . '/';
  75995. }
  75996. }
  75997. $path .= $data;
  75998. $this->filelist[$path] = $this->current_attributes;
  75999. // Set the baseinstalldir only if the file don't have this attrib
  76000. if (!isset($this->filelist[$path]['baseinstalldir']) &&
  76001. isset($this->dir_install))
  76002. {
  76003. $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
  76004. }
  76005. // Set the Role
  76006. if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
  76007. $this->filelist[$path]['role'] = $this->dir_role;
  76008. }
  76009. }
  76010. break;
  76011. case 'maintainer':
  76012. if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) {
  76013. $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead';
  76014. }
  76015. $this->m_i++;
  76016. break;
  76017. case 'release':
  76018. if ($this->in_changelog) {
  76019. $this->c_i++;
  76020. }
  76021. break;
  76022. case 'changelog':
  76023. $this->in_changelog = false;
  76024. break;
  76025. }
  76026. array_pop($this->element_stack);
  76027. $spos = sizeof($this->element_stack) - 1;
  76028. $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : '';
  76029. $this->cdata = '';
  76030. }
  76031. // }}}
  76032. // {{{ _pkginfo_cdata_1_0()
  76033. /**
  76034. * XML parser callback for character data. Used for version 1.0
  76035. * packages.
  76036. *
  76037. * @param resource $xp XML parser resource
  76038. * @param string $name character data
  76039. *
  76040. * @return void
  76041. *
  76042. * @access private
  76043. */
  76044. function _pkginfo_cdata_1_0($xp, $data)
  76045. {
  76046. if (isset($this->cdata)) {
  76047. $this->cdata .= $data;
  76048. }
  76049. }
  76050. // }}}
  76051. }
  76052. ?><?php
  76053. /**
  76054. * package.xml parsing class, package.xml version 2.0
  76055. *
  76056. * PHP versions 4 and 5
  76057. *
  76058. * @category pear
  76059. * @package PEAR
  76060. * @author Greg Beaver <cellog@php.net>
  76061. * @copyright 1997-2009 The Authors
  76062. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  76063. * @link http://pear.php.net/package/PEAR
  76064. * @since File available since Release 1.4.0a1
  76065. */
  76066. /**
  76067. * base xml parser class
  76068. */
  76069. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  76070. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  76071. /**
  76072. * Parser for package.xml version 2.0
  76073. * @category pear
  76074. * @package PEAR
  76075. * @author Greg Beaver <cellog@php.net>
  76076. * @copyright 1997-2009 The Authors
  76077. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  76078. * @version Release: 1.10.10
  76079. * @link http://pear.php.net/package/PEAR
  76080. * @since Class available since Release 1.4.0a1
  76081. */
  76082. class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser
  76083. {
  76084. var $_config;
  76085. var $_logger;
  76086. var $_registry;
  76087. function setConfig(&$c)
  76088. {
  76089. $this->_config = &$c;
  76090. $this->_registry = &$c->getRegistry();
  76091. }
  76092. function setLogger(&$l)
  76093. {
  76094. $this->_logger = &$l;
  76095. }
  76096. /**
  76097. * Unindent given string
  76098. *
  76099. * @param string $str The string that has to be unindented.
  76100. * @return string
  76101. * @access private
  76102. */
  76103. function _unIndent($str)
  76104. {
  76105. // remove leading newlines
  76106. $str = preg_replace('/^[\r\n]+/', '', $str);
  76107. // find whitespace at the beginning of the first line
  76108. $indent_len = strspn($str, " \t");
  76109. $indent = substr($str, 0, $indent_len);
  76110. $data = '';
  76111. // remove the same amount of whitespace from following lines
  76112. foreach (explode("\n", $str) as $line) {
  76113. if (substr($line, 0, $indent_len) == $indent) {
  76114. $data .= substr($line, $indent_len) . "\n";
  76115. } else {
  76116. $data .= $line . "\n";
  76117. }
  76118. }
  76119. return $data;
  76120. }
  76121. /**
  76122. * post-process data
  76123. *
  76124. * @param string $data
  76125. * @param string $element element name
  76126. */
  76127. function postProcess($data, $element)
  76128. {
  76129. if ($element == 'notes') {
  76130. return trim($this->_unIndent($data));
  76131. }
  76132. return trim($data);
  76133. }
  76134. /**
  76135. * @param string
  76136. * @param string file name of the package.xml
  76137. * @param string|false name of the archive this package.xml came from, if any
  76138. * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or
  76139. * a subclass
  76140. * @return PEAR_PackageFile_v2
  76141. */
  76142. function parse($data, $file = null, $archive = false, $class = 'PEAR_PackageFile_v2')
  76143. {
  76144. if (PEAR::isError($err = parent::parse($data))) {
  76145. return $err;
  76146. }
  76147. $ret = new $class;
  76148. $ret->encoding = $this->encoding;
  76149. $ret->setConfig($this->_config);
  76150. if (isset($this->_logger)) {
  76151. $ret->setLogger($this->_logger);
  76152. }
  76153. $ret->fromArray($this->_unserializedData);
  76154. $ret->setPackagefile($file, $archive);
  76155. return $ret;
  76156. }
  76157. }<?php
  76158. /**
  76159. * PEAR_PackageFile_v1, package.xml version 1.0
  76160. *
  76161. * PHP versions 4 and 5
  76162. *
  76163. * @category pear
  76164. * @package PEAR
  76165. * @author Greg Beaver <cellog@php.net>
  76166. * @copyright 1997-2009 The Authors
  76167. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  76168. * @link http://pear.php.net/package/PEAR
  76169. * @since File available since Release 1.4.0a1
  76170. */
  76171. /**
  76172. * For error handling
  76173. */
  76174. require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php';
  76175. /**
  76176. * Error code if parsing is attempted with no xml extension
  76177. */
  76178. define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
  76179. /**
  76180. * Error code if creating the xml parser resource fails
  76181. */
  76182. define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
  76183. /**
  76184. * Error code used for all sax xml parsing errors
  76185. */
  76186. define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
  76187. /**
  76188. * Error code used when there is no name
  76189. */
  76190. define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
  76191. /**
  76192. * Error code when a package name is not valid
  76193. */
  76194. define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
  76195. /**
  76196. * Error code used when no summary is parsed
  76197. */
  76198. define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
  76199. /**
  76200. * Error code for summaries that are more than 1 line
  76201. */
  76202. define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
  76203. /**
  76204. * Error code used when no description is present
  76205. */
  76206. define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
  76207. /**
  76208. * Error code used when no license is present
  76209. */
  76210. define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
  76211. /**
  76212. * Error code used when a <version> version number is not present
  76213. */
  76214. define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
  76215. /**
  76216. * Error code used when a <version> version number is invalid
  76217. */
  76218. define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
  76219. /**
  76220. * Error code when release state is missing
  76221. */
  76222. define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
  76223. /**
  76224. * Error code when release state is invalid
  76225. */
  76226. define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
  76227. /**
  76228. * Error code when release state is missing
  76229. */
  76230. define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
  76231. /**
  76232. * Error code when release state is invalid
  76233. */
  76234. define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
  76235. /**
  76236. * Error code when no release notes are found
  76237. */
  76238. define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
  76239. /**
  76240. * Error code when no maintainers are found
  76241. */
  76242. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
  76243. /**
  76244. * Error code when a maintainer has no handle
  76245. */
  76246. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
  76247. /**
  76248. * Error code when a maintainer has no handle
  76249. */
  76250. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
  76251. /**
  76252. * Error code when a maintainer has no name
  76253. */
  76254. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
  76255. /**
  76256. * Error code when a maintainer has no email
  76257. */
  76258. define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
  76259. /**
  76260. * Error code when a maintainer has no handle
  76261. */
  76262. define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
  76263. /**
  76264. * Error code when a dependency is not a PHP dependency, but has no name
  76265. */
  76266. define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
  76267. /**
  76268. * Error code when a dependency has no type (pkg, php, etc.)
  76269. */
  76270. define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
  76271. /**
  76272. * Error code when a dependency has no relation (lt, ge, has, etc.)
  76273. */
  76274. define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
  76275. /**
  76276. * Error code when a dependency is not a 'has' relation, but has no version
  76277. */
  76278. define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
  76279. /**
  76280. * Error code when a dependency has an invalid relation
  76281. */
  76282. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
  76283. /**
  76284. * Error code when a dependency has an invalid type
  76285. */
  76286. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
  76287. /**
  76288. * Error code when a dependency has an invalid optional option
  76289. */
  76290. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
  76291. /**
  76292. * Error code when a dependency is a pkg dependency, and has an invalid package name
  76293. */
  76294. define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
  76295. /**
  76296. * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
  76297. */
  76298. define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
  76299. /**
  76300. * Error code when rel="has" and version attribute is present.
  76301. */
  76302. define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
  76303. /**
  76304. * Error code when type="php" and dependency name is present
  76305. */
  76306. define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
  76307. /**
  76308. * Error code when a configure option has no name
  76309. */
  76310. define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
  76311. /**
  76312. * Error code when a configure option has no name
  76313. */
  76314. define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
  76315. /**
  76316. * Error code when a file in the filelist has an invalid role
  76317. */
  76318. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
  76319. /**
  76320. * Error code when a file in the filelist has no role
  76321. */
  76322. define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
  76323. /**
  76324. * Error code when analyzing a php source file that has parse errors
  76325. */
  76326. define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
  76327. /**
  76328. * Error code when analyzing a php source file reveals a source element
  76329. * without a package name prefix
  76330. */
  76331. define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
  76332. /**
  76333. * Error code when an unknown channel is specified
  76334. */
  76335. define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
  76336. /**
  76337. * Error code when no files are found in the filelist
  76338. */
  76339. define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
  76340. /**
  76341. * Error code when a file is not valid php according to _analyzeSourceCode()
  76342. */
  76343. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
  76344. /**
  76345. * Error code when the channel validator returns an error or warning
  76346. */
  76347. define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
  76348. /**
  76349. * Error code when a php5 package is packaged in php4 (analysis doesn't work)
  76350. */
  76351. define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
  76352. /**
  76353. * Error code when a file is listed in package.xml but does not exist
  76354. */
  76355. define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
  76356. /**
  76357. * Error code when a <dep type="php" rel="not"... is encountered (use rel="ne")
  76358. */
  76359. define('PEAR_PACKAGEFILE_PHP_NO_NOT', 48);
  76360. /**
  76361. * Error code when a package.xml contains non-ISO-8859-1 characters
  76362. */
  76363. define('PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS', 49);
  76364. /**
  76365. * Error code when a dependency is not a 'has' relation, but has no version
  76366. */
  76367. define('PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION', 50);
  76368. /**
  76369. * Error code when a package has no lead developer
  76370. */
  76371. define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51);
  76372. /**
  76373. * Error code when a filename begins with "."
  76374. */
  76375. define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52);
  76376. /**
  76377. * package.xml encapsulator
  76378. * @category pear
  76379. * @package PEAR
  76380. * @author Greg Beaver <cellog@php.net>
  76381. * @copyright 1997-2009 The Authors
  76382. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  76383. * @version Release: 1.10.10
  76384. * @link http://pear.php.net/package/PEAR
  76385. * @since Class available since Release 1.4.0a1
  76386. */
  76387. class PEAR_PackageFile_v1
  76388. {
  76389. /**
  76390. * @access private
  76391. * @var PEAR_ErrorStack
  76392. * @access private
  76393. */
  76394. var $_stack;
  76395. /**
  76396. * A registry object, used to access the package name validation regex for non-standard channels
  76397. * @var PEAR_Registry
  76398. * @access private
  76399. */
  76400. var $_registry;
  76401. /**
  76402. * An object that contains a log method that matches PEAR_Common::log's signature
  76403. * @var object
  76404. * @access private
  76405. */
  76406. var $_logger;
  76407. /**
  76408. * Parsed package information
  76409. * @var array
  76410. * @access private
  76411. */
  76412. var $_packageInfo;
  76413. /**
  76414. * path to package.xml
  76415. * @var string
  76416. * @access private
  76417. */
  76418. var $_packageFile;
  76419. /**
  76420. * path to package .tgz or false if this is a local/extracted package.xml
  76421. * @var string
  76422. * @access private
  76423. */
  76424. var $_archiveFile;
  76425. /**
  76426. * @var int
  76427. * @access private
  76428. */
  76429. var $_isValid = 0;
  76430. /**
  76431. * Determines whether this packagefile was initialized only with partial package info
  76432. *
  76433. * If this package file was constructed via parsing REST, it will only contain
  76434. *
  76435. * - package name
  76436. * - channel name
  76437. * - dependencies
  76438. * @var boolean
  76439. * @access private
  76440. */
  76441. var $_incomplete = true;
  76442. /**
  76443. * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
  76444. * @param string Name of Error Stack class to use.
  76445. */
  76446. function __construct()
  76447. {
  76448. $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v1');
  76449. $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  76450. $this->_isValid = 0;
  76451. }
  76452. function installBinary($installer)
  76453. {
  76454. return false;
  76455. }
  76456. function isExtension($name)
  76457. {
  76458. return false;
  76459. }
  76460. function setConfig(&$config)
  76461. {
  76462. $this->_config = &$config;
  76463. $this->_registry = &$config->getRegistry();
  76464. }
  76465. function setRequestedGroup()
  76466. {
  76467. // placeholder
  76468. }
  76469. /**
  76470. * For saving in the registry.
  76471. *
  76472. * Set the last version that was installed
  76473. * @param string
  76474. */
  76475. function setLastInstalledVersion($version)
  76476. {
  76477. $this->_packageInfo['_lastversion'] = $version;
  76478. }
  76479. /**
  76480. * @return string|false
  76481. */
  76482. function getLastInstalledVersion()
  76483. {
  76484. if (isset($this->_packageInfo['_lastversion'])) {
  76485. return $this->_packageInfo['_lastversion'];
  76486. }
  76487. return false;
  76488. }
  76489. function getInstalledBinary()
  76490. {
  76491. return false;
  76492. }
  76493. function listPostinstallScripts()
  76494. {
  76495. return false;
  76496. }
  76497. function initPostinstallScripts()
  76498. {
  76499. return false;
  76500. }
  76501. function setLogger(&$logger)
  76502. {
  76503. if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
  76504. return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
  76505. }
  76506. $this->_logger = &$logger;
  76507. }
  76508. function setPackagefile($file, $archive = false)
  76509. {
  76510. $this->_packageFile = $file;
  76511. $this->_archiveFile = $archive ? $archive : $file;
  76512. }
  76513. function getPackageFile()
  76514. {
  76515. return isset($this->_packageFile) ? $this->_packageFile : false;
  76516. }
  76517. function getPackageType()
  76518. {
  76519. return 'php';
  76520. }
  76521. function getArchiveFile()
  76522. {
  76523. return $this->_archiveFile;
  76524. }
  76525. function packageInfo($field)
  76526. {
  76527. if (!is_string($field) || empty($field) ||
  76528. !isset($this->_packageInfo[$field])) {
  76529. return false;
  76530. }
  76531. return $this->_packageInfo[$field];
  76532. }
  76533. function setDirtree($path)
  76534. {
  76535. if (!isset($this->_packageInfo['dirtree'])) {
  76536. $this->_packageInfo['dirtree'] = array();
  76537. }
  76538. $this->_packageInfo['dirtree'][$path] = true;
  76539. }
  76540. function getDirtree()
  76541. {
  76542. if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
  76543. return $this->_packageInfo['dirtree'];
  76544. }
  76545. return false;
  76546. }
  76547. function resetDirtree()
  76548. {
  76549. unset($this->_packageInfo['dirtree']);
  76550. }
  76551. function fromArray($pinfo)
  76552. {
  76553. $this->_incomplete = false;
  76554. $this->_packageInfo = $pinfo;
  76555. }
  76556. function isIncomplete()
  76557. {
  76558. return $this->_incomplete;
  76559. }
  76560. function getChannel()
  76561. {
  76562. return 'pear.php.net';
  76563. }
  76564. function getUri()
  76565. {
  76566. return false;
  76567. }
  76568. function getTime()
  76569. {
  76570. return false;
  76571. }
  76572. function getExtends()
  76573. {
  76574. if (isset($this->_packageInfo['extends'])) {
  76575. return $this->_packageInfo['extends'];
  76576. }
  76577. return false;
  76578. }
  76579. /**
  76580. * @return array
  76581. */
  76582. function toArray()
  76583. {
  76584. if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
  76585. return false;
  76586. }
  76587. return $this->getArray();
  76588. }
  76589. function getArray()
  76590. {
  76591. return $this->_packageInfo;
  76592. }
  76593. function getName()
  76594. {
  76595. return $this->getPackage();
  76596. }
  76597. function getPackage()
  76598. {
  76599. if (isset($this->_packageInfo['package'])) {
  76600. return $this->_packageInfo['package'];
  76601. }
  76602. return false;
  76603. }
  76604. /**
  76605. * WARNING - don't use this unless you know what you are doing
  76606. */
  76607. function setRawPackage($package)
  76608. {
  76609. $this->_packageInfo['package'] = $package;
  76610. }
  76611. function setPackage($package)
  76612. {
  76613. $this->_packageInfo['package'] = $package;
  76614. $this->_isValid = false;
  76615. }
  76616. function getVersion()
  76617. {
  76618. if (isset($this->_packageInfo['version'])) {
  76619. return $this->_packageInfo['version'];
  76620. }
  76621. return false;
  76622. }
  76623. function setVersion($version)
  76624. {
  76625. $this->_packageInfo['version'] = $version;
  76626. $this->_isValid = false;
  76627. }
  76628. function clearMaintainers()
  76629. {
  76630. unset($this->_packageInfo['maintainers']);
  76631. }
  76632. function getMaintainers()
  76633. {
  76634. if (isset($this->_packageInfo['maintainers'])) {
  76635. return $this->_packageInfo['maintainers'];
  76636. }
  76637. return false;
  76638. }
  76639. /**
  76640. * Adds a new maintainer - no checking of duplicates is performed, use
  76641. * updatemaintainer for that purpose.
  76642. */
  76643. function addMaintainer($role, $handle, $name, $email)
  76644. {
  76645. $this->_packageInfo['maintainers'][] =
  76646. array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
  76647. $this->_isValid = false;
  76648. }
  76649. function updateMaintainer($role, $handle, $name, $email)
  76650. {
  76651. $found = false;
  76652. if (!isset($this->_packageInfo['maintainers']) ||
  76653. !is_array($this->_packageInfo['maintainers'])) {
  76654. return $this->addMaintainer($role, $handle, $name, $email);
  76655. }
  76656. foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
  76657. if ($maintainer['handle'] == $handle) {
  76658. $found = $i;
  76659. break;
  76660. }
  76661. }
  76662. if ($found !== false) {
  76663. unset($this->_packageInfo['maintainers'][$found]);
  76664. $this->_packageInfo['maintainers'] =
  76665. array_values($this->_packageInfo['maintainers']);
  76666. }
  76667. $this->addMaintainer($role, $handle, $name, $email);
  76668. }
  76669. function deleteMaintainer($handle)
  76670. {
  76671. $found = false;
  76672. foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
  76673. if ($maintainer['handle'] == $handle) {
  76674. $found = $i;
  76675. break;
  76676. }
  76677. }
  76678. if ($found !== false) {
  76679. unset($this->_packageInfo['maintainers'][$found]);
  76680. $this->_packageInfo['maintainers'] =
  76681. array_values($this->_packageInfo['maintainers']);
  76682. return true;
  76683. }
  76684. return false;
  76685. }
  76686. function getState()
  76687. {
  76688. if (isset($this->_packageInfo['release_state'])) {
  76689. return $this->_packageInfo['release_state'];
  76690. }
  76691. return false;
  76692. }
  76693. function setRawState($state)
  76694. {
  76695. $this->_packageInfo['release_state'] = $state;
  76696. }
  76697. function setState($state)
  76698. {
  76699. $this->_packageInfo['release_state'] = $state;
  76700. $this->_isValid = false;
  76701. }
  76702. function getDate()
  76703. {
  76704. if (isset($this->_packageInfo['release_date'])) {
  76705. return $this->_packageInfo['release_date'];
  76706. }
  76707. return false;
  76708. }
  76709. function setDate($date)
  76710. {
  76711. $this->_packageInfo['release_date'] = $date;
  76712. $this->_isValid = false;
  76713. }
  76714. function getLicense()
  76715. {
  76716. if (isset($this->_packageInfo['release_license'])) {
  76717. return $this->_packageInfo['release_license'];
  76718. }
  76719. return false;
  76720. }
  76721. function setLicense($date)
  76722. {
  76723. $this->_packageInfo['release_license'] = $date;
  76724. $this->_isValid = false;
  76725. }
  76726. function getSummary()
  76727. {
  76728. if (isset($this->_packageInfo['summary'])) {
  76729. return $this->_packageInfo['summary'];
  76730. }
  76731. return false;
  76732. }
  76733. function setSummary($summary)
  76734. {
  76735. $this->_packageInfo['summary'] = $summary;
  76736. $this->_isValid = false;
  76737. }
  76738. function getDescription()
  76739. {
  76740. if (isset($this->_packageInfo['description'])) {
  76741. return $this->_packageInfo['description'];
  76742. }
  76743. return false;
  76744. }
  76745. function setDescription($desc)
  76746. {
  76747. $this->_packageInfo['description'] = $desc;
  76748. $this->_isValid = false;
  76749. }
  76750. function getNotes()
  76751. {
  76752. if (isset($this->_packageInfo['release_notes'])) {
  76753. return $this->_packageInfo['release_notes'];
  76754. }
  76755. return false;
  76756. }
  76757. function setNotes($notes)
  76758. {
  76759. $this->_packageInfo['release_notes'] = $notes;
  76760. $this->_isValid = false;
  76761. }
  76762. function getDeps()
  76763. {
  76764. if (isset($this->_packageInfo['release_deps'])) {
  76765. return $this->_packageInfo['release_deps'];
  76766. }
  76767. return false;
  76768. }
  76769. /**
  76770. * Reset dependencies prior to adding new ones
  76771. */
  76772. function clearDeps()
  76773. {
  76774. unset($this->_packageInfo['release_deps']);
  76775. }
  76776. function addPhpDep($version, $rel)
  76777. {
  76778. $this->_isValid = false;
  76779. $this->_packageInfo['release_deps'][] =
  76780. array('type' => 'php',
  76781. 'rel' => $rel,
  76782. 'version' => $version);
  76783. }
  76784. function addPackageDep($name, $version, $rel, $optional = 'no')
  76785. {
  76786. $this->_isValid = false;
  76787. $dep =
  76788. array('type' => 'pkg',
  76789. 'name' => $name,
  76790. 'rel' => $rel,
  76791. 'optional' => $optional);
  76792. if ($rel != 'has' && $rel != 'not') {
  76793. $dep['version'] = $version;
  76794. }
  76795. $this->_packageInfo['release_deps'][] = $dep;
  76796. }
  76797. function addExtensionDep($name, $version, $rel, $optional = 'no')
  76798. {
  76799. $this->_isValid = false;
  76800. $this->_packageInfo['release_deps'][] =
  76801. array('type' => 'ext',
  76802. 'name' => $name,
  76803. 'rel' => $rel,
  76804. 'version' => $version,
  76805. 'optional' => $optional);
  76806. }
  76807. /**
  76808. * WARNING - do not use this function directly unless you know what you're doing
  76809. */
  76810. function setDeps($deps)
  76811. {
  76812. $this->_packageInfo['release_deps'] = $deps;
  76813. }
  76814. function hasDeps()
  76815. {
  76816. return isset($this->_packageInfo['release_deps']) &&
  76817. count($this->_packageInfo['release_deps']);
  76818. }
  76819. function getDependencyGroup($group)
  76820. {
  76821. return false;
  76822. }
  76823. function isCompatible($pf)
  76824. {
  76825. return false;
  76826. }
  76827. function isSubpackageOf($p)
  76828. {
  76829. return $p->isSubpackage($this);
  76830. }
  76831. function isSubpackage($p)
  76832. {
  76833. return false;
  76834. }
  76835. function dependsOn($package, $channel)
  76836. {
  76837. if (strtolower($channel) != 'pear.php.net') {
  76838. return false;
  76839. }
  76840. if (!($deps = $this->getDeps())) {
  76841. return false;
  76842. }
  76843. foreach ($deps as $dep) {
  76844. if ($dep['type'] != 'pkg') {
  76845. continue;
  76846. }
  76847. if (strtolower($dep['name']) == strtolower($package)) {
  76848. return true;
  76849. }
  76850. }
  76851. return false;
  76852. }
  76853. function getConfigureOptions()
  76854. {
  76855. if (isset($this->_packageInfo['configure_options'])) {
  76856. return $this->_packageInfo['configure_options'];
  76857. }
  76858. return false;
  76859. }
  76860. function hasConfigureOptions()
  76861. {
  76862. return isset($this->_packageInfo['configure_options']) &&
  76863. count($this->_packageInfo['configure_options']);
  76864. }
  76865. function addConfigureOption($name, $prompt, $default = false)
  76866. {
  76867. $o = array('name' => $name, 'prompt' => $prompt);
  76868. if ($default !== false) {
  76869. $o['default'] = $default;
  76870. }
  76871. if (!isset($this->_packageInfo['configure_options'])) {
  76872. $this->_packageInfo['configure_options'] = array();
  76873. }
  76874. $this->_packageInfo['configure_options'][] = $o;
  76875. }
  76876. function clearConfigureOptions()
  76877. {
  76878. unset($this->_packageInfo['configure_options']);
  76879. }
  76880. function getProvides()
  76881. {
  76882. if (isset($this->_packageInfo['provides'])) {
  76883. return $this->_packageInfo['provides'];
  76884. }
  76885. return false;
  76886. }
  76887. function getProvidesExtension()
  76888. {
  76889. return false;
  76890. }
  76891. function addFile($dir, $file, $attrs)
  76892. {
  76893. $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
  76894. if ($dir == '/' || $dir == '') {
  76895. $dir = '';
  76896. } else {
  76897. $dir .= '/';
  76898. }
  76899. $file = $dir . $file;
  76900. $file = preg_replace('![\\/]+!', '/', $file);
  76901. $this->_packageInfo['filelist'][$file] = $attrs;
  76902. }
  76903. function getInstallationFilelist()
  76904. {
  76905. return $this->getFilelist();
  76906. }
  76907. function getFilelist()
  76908. {
  76909. if (isset($this->_packageInfo['filelist'])) {
  76910. return $this->_packageInfo['filelist'];
  76911. }
  76912. return false;
  76913. }
  76914. function setFileAttribute($file, $attr, $value)
  76915. {
  76916. $this->_packageInfo['filelist'][$file][$attr] = $value;
  76917. }
  76918. function resetFilelist()
  76919. {
  76920. $this->_packageInfo['filelist'] = array();
  76921. }
  76922. function setInstalledAs($file, $path)
  76923. {
  76924. if ($path) {
  76925. return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
  76926. }
  76927. unset($this->_packageInfo['filelist'][$file]['installed_as']);
  76928. }
  76929. function installedFile($file, $atts)
  76930. {
  76931. if (isset($this->_packageInfo['filelist'][$file])) {
  76932. $this->_packageInfo['filelist'][$file] =
  76933. array_merge($this->_packageInfo['filelist'][$file], $atts);
  76934. } else {
  76935. $this->_packageInfo['filelist'][$file] = $atts;
  76936. }
  76937. }
  76938. function getChangelog()
  76939. {
  76940. if (isset($this->_packageInfo['changelog'])) {
  76941. return $this->_packageInfo['changelog'];
  76942. }
  76943. return false;
  76944. }
  76945. function getPackagexmlVersion()
  76946. {
  76947. return '1.0';
  76948. }
  76949. /**
  76950. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  76951. * @param boolean determines whether to purge the error stack after retrieving
  76952. * @return array
  76953. */
  76954. function getValidationWarnings($purge = true)
  76955. {
  76956. return $this->_stack->getErrors($purge);
  76957. }
  76958. // }}}
  76959. /**
  76960. * Validation error. Also marks the object contents as invalid
  76961. * @param error code
  76962. * @param array error information
  76963. * @access private
  76964. */
  76965. function _validateError($code, $params = array())
  76966. {
  76967. $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
  76968. $this->_isValid = false;
  76969. }
  76970. /**
  76971. * Validation warning. Does not mark the object contents invalid.
  76972. * @param error code
  76973. * @param array error information
  76974. * @access private
  76975. */
  76976. function _validateWarning($code, $params = array())
  76977. {
  76978. $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
  76979. }
  76980. /**
  76981. * @param integer error code
  76982. * @access protected
  76983. */
  76984. function _getErrorMessage()
  76985. {
  76986. return array(
  76987. PEAR_PACKAGEFILE_ERROR_NO_NAME =>
  76988. 'Missing Package Name',
  76989. PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
  76990. 'No summary found',
  76991. PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
  76992. 'Summary should be on one line',
  76993. PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
  76994. 'Missing description',
  76995. PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
  76996. 'Missing license',
  76997. PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
  76998. 'No release version found',
  76999. PEAR_PACKAGEFILE_ERROR_NO_STATE =>
  77000. 'No release state found',
  77001. PEAR_PACKAGEFILE_ERROR_NO_DATE =>
  77002. 'No release date found',
  77003. PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
  77004. 'No release notes found',
  77005. PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
  77006. 'Package must have at least one lead maintainer',
  77007. PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
  77008. 'No maintainers found, at least one must be defined',
  77009. PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
  77010. 'Maintainer %index% has no handle (user ID at channel server)',
  77011. PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
  77012. 'Maintainer %index% has no role',
  77013. PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
  77014. 'Maintainer %index% has no name',
  77015. PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
  77016. 'Maintainer %index% has no email',
  77017. PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
  77018. 'Dependency %index% is not a php dependency, and has no name',
  77019. PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
  77020. 'Dependency %index% has no relation (rel)',
  77021. PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
  77022. 'Dependency %index% has no type',
  77023. PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
  77024. 'PHP Dependency %index% has a name attribute of "%name%" which will be' .
  77025. ' ignored!',
  77026. PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
  77027. 'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
  77028. 'and has no version',
  77029. PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
  77030. 'Dependency %index% is a type="php" dependency, ' .
  77031. 'and has no version',
  77032. PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
  77033. 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
  77034. PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
  77035. 'Dependency %index% has invalid optional value "%opt%", should be yes or no',
  77036. PEAR_PACKAGEFILE_PHP_NO_NOT =>
  77037. 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
  77038. ' to exclude specific versions',
  77039. PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
  77040. 'Configure Option %index% has no name',
  77041. PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
  77042. 'Configure Option %index% has no prompt',
  77043. PEAR_PACKAGEFILE_ERROR_NO_FILES =>
  77044. 'No files in <filelist> section of package.xml',
  77045. PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
  77046. 'File "%file%" has no role, expecting one of "%roles%"',
  77047. PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
  77048. 'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
  77049. PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
  77050. 'File "%file%" cannot start with ".", cannot package or install',
  77051. PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
  77052. 'Parser error: invalid PHP found in file "%file%"',
  77053. PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
  77054. 'in %file%: %type% "%name%" not prefixed with package name "%package%"',
  77055. PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
  77056. 'Parser error: invalid PHP file "%file%"',
  77057. PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
  77058. 'Channel validator error: field "%field%" - %reason%',
  77059. PEAR_PACKAGEFILE_ERROR_PHP5 =>
  77060. 'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
  77061. PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
  77062. 'File "%file%" in package.xml does not exist',
  77063. PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
  77064. 'Package.xml contains non-ISO-8859-1 characters, and may not validate',
  77065. );
  77066. }
  77067. /**
  77068. * Validate XML package definition file.
  77069. *
  77070. * @access public
  77071. * @return boolean
  77072. */
  77073. function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
  77074. {
  77075. if (($this->_isValid & $state) == $state) {
  77076. return true;
  77077. }
  77078. $this->_isValid = true;
  77079. $info = $this->_packageInfo;
  77080. if (empty($info['package'])) {
  77081. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
  77082. $this->_packageName = $pn = 'unknown';
  77083. } else {
  77084. $this->_packageName = $pn = $info['package'];
  77085. }
  77086. if (empty($info['summary'])) {
  77087. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
  77088. } elseif (strpos(trim($info['summary']), "\n") !== false) {
  77089. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
  77090. array('summary' => $info['summary']));
  77091. }
  77092. if (empty($info['description'])) {
  77093. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
  77094. }
  77095. if (empty($info['release_license'])) {
  77096. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
  77097. }
  77098. if (empty($info['version'])) {
  77099. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
  77100. }
  77101. if (empty($info['release_state'])) {
  77102. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
  77103. }
  77104. if (empty($info['release_date'])) {
  77105. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
  77106. }
  77107. if (empty($info['release_notes'])) {
  77108. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
  77109. }
  77110. if (empty($info['maintainers'])) {
  77111. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
  77112. } else {
  77113. $haslead = false;
  77114. $i = 1;
  77115. foreach ($info['maintainers'] as $m) {
  77116. if (empty($m['handle'])) {
  77117. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
  77118. array('index' => $i));
  77119. }
  77120. if (empty($m['role'])) {
  77121. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
  77122. array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
  77123. } elseif ($m['role'] == 'lead') {
  77124. $haslead = true;
  77125. }
  77126. if (empty($m['name'])) {
  77127. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
  77128. array('index' => $i));
  77129. }
  77130. if (empty($m['email'])) {
  77131. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
  77132. array('index' => $i));
  77133. }
  77134. $i++;
  77135. }
  77136. if (!$haslead) {
  77137. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
  77138. }
  77139. }
  77140. if (!empty($info['release_deps'])) {
  77141. $i = 1;
  77142. foreach ($info['release_deps'] as $d) {
  77143. if (!isset($d['type']) || empty($d['type'])) {
  77144. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
  77145. array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
  77146. continue;
  77147. }
  77148. if (!isset($d['rel']) || empty($d['rel'])) {
  77149. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
  77150. array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
  77151. continue;
  77152. }
  77153. if (!empty($d['optional'])) {
  77154. if (!in_array($d['optional'], array('yes', 'no'))) {
  77155. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
  77156. array('index' => $i, 'opt' => $d['optional']));
  77157. }
  77158. }
  77159. if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
  77160. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
  77161. array('index' => $i));
  77162. } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
  77163. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
  77164. array('index' => $i, 'rel' => $d['rel']));
  77165. }
  77166. if ($d['type'] == 'php' && !empty($d['name'])) {
  77167. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
  77168. array('index' => $i, 'name' => $d['name']));
  77169. } elseif ($d['type'] != 'php' && empty($d['name'])) {
  77170. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
  77171. array('index' => $i));
  77172. }
  77173. if ($d['type'] == 'php' && empty($d['version'])) {
  77174. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
  77175. array('index' => $i));
  77176. }
  77177. if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
  77178. $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
  77179. array('index' => $i));
  77180. }
  77181. $i++;
  77182. }
  77183. }
  77184. if (!empty($info['configure_options'])) {
  77185. $i = 1;
  77186. foreach ($info['configure_options'] as $c) {
  77187. if (empty($c['name'])) {
  77188. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
  77189. array('index' => $i));
  77190. }
  77191. if (empty($c['prompt'])) {
  77192. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
  77193. array('index' => $i));
  77194. }
  77195. $i++;
  77196. }
  77197. }
  77198. if (empty($info['filelist'])) {
  77199. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
  77200. $errors[] = 'no files';
  77201. } else {
  77202. foreach ($info['filelist'] as $file => $fa) {
  77203. if (empty($fa['role'])) {
  77204. $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
  77205. array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
  77206. continue;
  77207. } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
  77208. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
  77209. array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
  77210. }
  77211. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) {
  77212. // file contains .. parent directory or . cur directory references
  77213. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  77214. array('file' => $file));
  77215. }
  77216. if (isset($fa['install-as']) &&
  77217. preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  77218. str_replace('\\', '/', $fa['install-as']))) {
  77219. // install-as contains .. parent directory or . cur directory references
  77220. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  77221. array('file' => $file . ' [installed as ' . $fa['install-as'] . ']'));
  77222. }
  77223. if (isset($fa['baseinstalldir']) &&
  77224. preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  77225. str_replace('\\', '/', $fa['baseinstalldir']))) {
  77226. // install-as contains .. parent directory or . cur directory references
  77227. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
  77228. array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']'));
  77229. }
  77230. }
  77231. }
  77232. if (isset($this->_registry) && $this->_isValid) {
  77233. $chan = $this->_registry->getChannel('pear.php.net');
  77234. if (PEAR::isError($chan)) {
  77235. $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage());
  77236. return $this->_isValid = 0;
  77237. }
  77238. $validator = $chan->getValidationObject();
  77239. $validator->setPackageFile($this);
  77240. $validator->validate($state);
  77241. $failures = $validator->getFailures();
  77242. foreach ($failures['errors'] as $error) {
  77243. $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
  77244. }
  77245. foreach ($failures['warnings'] as $warning) {
  77246. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
  77247. }
  77248. }
  77249. if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
  77250. if ($this->_analyzePhpFiles()) {
  77251. $this->_isValid = true;
  77252. }
  77253. }
  77254. if ($this->_isValid) {
  77255. return $this->_isValid = $state;
  77256. }
  77257. return $this->_isValid = 0;
  77258. }
  77259. function _analyzePhpFiles()
  77260. {
  77261. if (!$this->_isValid) {
  77262. return false;
  77263. }
  77264. if (!isset($this->_packageFile)) {
  77265. return false;
  77266. }
  77267. $dir_prefix = dirname($this->_packageFile);
  77268. $common = new PEAR_Common;
  77269. $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
  77270. array($common, 'log');
  77271. $info = $this->getFilelist();
  77272. foreach ($info as $file => $fa) {
  77273. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
  77274. $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
  77275. array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
  77276. continue;
  77277. }
  77278. if ($fa['role'] == 'php' && $dir_prefix) {
  77279. call_user_func_array($log, array(1, "Analyzing $file"));
  77280. $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
  77281. if ($srcinfo) {
  77282. $this->_buildProvidesArray($srcinfo);
  77283. }
  77284. }
  77285. }
  77286. $this->_packageName = $pn = $this->getPackage();
  77287. $pnl = strlen($pn);
  77288. if (isset($this->_packageInfo['provides'])) {
  77289. foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
  77290. if (isset($what['explicit'])) {
  77291. // skip conformance checks if the provides entry is
  77292. // specified in the package.xml file
  77293. continue;
  77294. }
  77295. extract($what);
  77296. if ($type == 'class') {
  77297. if (!strncasecmp($name, $pn, $pnl)) {
  77298. continue;
  77299. }
  77300. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
  77301. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
  77302. } elseif ($type == 'function') {
  77303. if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
  77304. continue;
  77305. }
  77306. $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
  77307. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
  77308. }
  77309. }
  77310. }
  77311. return $this->_isValid;
  77312. }
  77313. /**
  77314. * Get the default xml generator object
  77315. *
  77316. * @return PEAR_PackageFile_Generator_v1
  77317. */
  77318. function &getDefaultGenerator()
  77319. {
  77320. if (!class_exists('PEAR_PackageFile_Generator_v1')) {
  77321. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v1.php';
  77322. }
  77323. $a = new PEAR_PackageFile_Generator_v1($this);
  77324. return $a;
  77325. }
  77326. /**
  77327. * Get the contents of a file listed within the package.xml
  77328. * @param string
  77329. * @return string
  77330. */
  77331. function getFileContents($file)
  77332. {
  77333. if ($this->_archiveFile == $this->_packageFile) { // unpacked
  77334. $dir = dirname($this->_packageFile);
  77335. $file = $dir . DIRECTORY_SEPARATOR . $file;
  77336. $file = str_replace(array('/', '\\'),
  77337. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
  77338. if (file_exists($file) && is_readable($file)) {
  77339. return implode('', file($file));
  77340. }
  77341. } else { // tgz
  77342. if (!class_exists('Archive_Tar')) {
  77343. require_once 'phar://go-pear.phar/' . 'Archive/Tar.php';
  77344. }
  77345. $tar = new Archive_Tar($this->_archiveFile);
  77346. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  77347. if ($file != 'package.xml' && $file != 'package2.xml') {
  77348. $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
  77349. }
  77350. $file = $tar->extractInString($file);
  77351. $tar->popErrorHandling();
  77352. if (PEAR::isError($file)) {
  77353. return PEAR::raiseError("Cannot locate file '$file' in archive");
  77354. }
  77355. return $file;
  77356. }
  77357. }
  77358. // {{{ analyzeSourceCode()
  77359. /**
  77360. * Analyze the source code of the given PHP file
  77361. *
  77362. * @param string Filename of the PHP file
  77363. * @return mixed
  77364. * @access private
  77365. */
  77366. function _analyzeSourceCode($file)
  77367. {
  77368. if (!function_exists("token_get_all")) {
  77369. return false;
  77370. }
  77371. if (!defined('T_DOC_COMMENT')) {
  77372. define('T_DOC_COMMENT', T_COMMENT);
  77373. }
  77374. if (!defined('T_INTERFACE')) {
  77375. define('T_INTERFACE', -1);
  77376. }
  77377. if (!defined('T_IMPLEMENTS')) {
  77378. define('T_IMPLEMENTS', -1);
  77379. }
  77380. if (!$fp = @fopen($file, "r")) {
  77381. return false;
  77382. }
  77383. fclose($fp);
  77384. $contents = file_get_contents($file);
  77385. $tokens = token_get_all($contents);
  77386. /*
  77387. for ($i = 0; $i < sizeof($tokens); $i++) {
  77388. @list($token, $data) = $tokens[$i];
  77389. if (is_string($token)) {
  77390. var_dump($token);
  77391. } else {
  77392. print token_name($token) . ' ';
  77393. var_dump(rtrim($data));
  77394. }
  77395. }
  77396. */
  77397. $look_for = 0;
  77398. $paren_level = 0;
  77399. $bracket_level = 0;
  77400. $brace_level = 0;
  77401. $lastphpdoc = '';
  77402. $current_class = '';
  77403. $current_interface = '';
  77404. $current_class_level = -1;
  77405. $current_function = '';
  77406. $current_function_level = -1;
  77407. $declared_classes = array();
  77408. $declared_interfaces = array();
  77409. $declared_functions = array();
  77410. $declared_methods = array();
  77411. $used_classes = array();
  77412. $used_functions = array();
  77413. $extends = array();
  77414. $implements = array();
  77415. $nodeps = array();
  77416. $inquote = false;
  77417. $interface = false;
  77418. for ($i = 0; $i < sizeof($tokens); $i++) {
  77419. if (is_array($tokens[$i])) {
  77420. list($token, $data) = $tokens[$i];
  77421. } else {
  77422. $token = $tokens[$i];
  77423. $data = '';
  77424. }
  77425. if ($inquote) {
  77426. if ($token != '"' && $token != T_END_HEREDOC) {
  77427. continue;
  77428. } else {
  77429. $inquote = false;
  77430. continue;
  77431. }
  77432. }
  77433. switch ($token) {
  77434. case T_WHITESPACE:
  77435. break;
  77436. case ';':
  77437. if ($interface) {
  77438. $current_function = '';
  77439. $current_function_level = -1;
  77440. }
  77441. break;
  77442. case '"':
  77443. case T_START_HEREDOC:
  77444. $inquote = true;
  77445. break;
  77446. case T_CURLY_OPEN:
  77447. case T_DOLLAR_OPEN_CURLY_BRACES:
  77448. case '{': $brace_level++; continue 2;
  77449. case '}':
  77450. $brace_level--;
  77451. if ($current_class_level == $brace_level) {
  77452. $current_class = '';
  77453. $current_class_level = -1;
  77454. }
  77455. if ($current_function_level == $brace_level) {
  77456. $current_function = '';
  77457. $current_function_level = -1;
  77458. }
  77459. continue 2;
  77460. case '[': $bracket_level++; continue 2;
  77461. case ']': $bracket_level--; continue 2;
  77462. case '(': $paren_level++; continue 2;
  77463. case ')': $paren_level--; continue 2;
  77464. case T_INTERFACE:
  77465. $interface = true;
  77466. case T_CLASS:
  77467. if (($current_class_level != -1) || ($current_function_level != -1)) {
  77468. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
  77469. array('file' => $file));
  77470. return false;
  77471. }
  77472. case T_FUNCTION:
  77473. case T_NEW:
  77474. case T_EXTENDS:
  77475. case T_IMPLEMENTS:
  77476. $look_for = $token;
  77477. continue 2;
  77478. case T_STRING:
  77479. if ($look_for == T_CLASS) {
  77480. $current_class = $data;
  77481. $current_class_level = $brace_level;
  77482. $declared_classes[] = $current_class;
  77483. } elseif ($look_for == T_INTERFACE) {
  77484. $current_interface = $data;
  77485. $current_class_level = $brace_level;
  77486. $declared_interfaces[] = $current_interface;
  77487. } elseif ($look_for == T_IMPLEMENTS) {
  77488. $implements[$current_class] = $data;
  77489. } elseif ($look_for == T_EXTENDS) {
  77490. $extends[$current_class] = $data;
  77491. } elseif ($look_for == T_FUNCTION) {
  77492. if ($current_class) {
  77493. $current_function = "$current_class::$data";
  77494. $declared_methods[$current_class][] = $data;
  77495. } elseif ($current_interface) {
  77496. $current_function = "$current_interface::$data";
  77497. $declared_methods[$current_interface][] = $data;
  77498. } else {
  77499. $current_function = $data;
  77500. $declared_functions[] = $current_function;
  77501. }
  77502. $current_function_level = $brace_level;
  77503. $m = array();
  77504. } elseif ($look_for == T_NEW) {
  77505. $used_classes[$data] = true;
  77506. }
  77507. $look_for = 0;
  77508. continue 2;
  77509. case T_VARIABLE:
  77510. $look_for = 0;
  77511. continue 2;
  77512. case T_DOC_COMMENT:
  77513. case T_COMMENT:
  77514. if (preg_match('!^/\*\*\s!', $data)) {
  77515. $lastphpdoc = $data;
  77516. if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  77517. $nodeps = array_merge($nodeps, $m[1]);
  77518. }
  77519. }
  77520. continue 2;
  77521. case T_DOUBLE_COLON:
  77522. if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
  77523. $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
  77524. array('file' => $file));
  77525. return false;
  77526. }
  77527. $class = $tokens[$i - 1][1];
  77528. if (strtolower($class) != 'parent') {
  77529. $used_classes[$class] = true;
  77530. }
  77531. continue 2;
  77532. }
  77533. }
  77534. return array(
  77535. "source_file" => $file,
  77536. "declared_classes" => $declared_classes,
  77537. "declared_interfaces" => $declared_interfaces,
  77538. "declared_methods" => $declared_methods,
  77539. "declared_functions" => $declared_functions,
  77540. "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  77541. "inheritance" => $extends,
  77542. "implements" => $implements,
  77543. );
  77544. }
  77545. /**
  77546. * Build a "provides" array from data returned by
  77547. * analyzeSourceCode(). The format of the built array is like
  77548. * this:
  77549. *
  77550. * array(
  77551. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  77552. * ...
  77553. * )
  77554. *
  77555. *
  77556. * @param array $srcinfo array with information about a source file
  77557. * as returned by the analyzeSourceCode() method.
  77558. *
  77559. * @return void
  77560. *
  77561. * @access private
  77562. *
  77563. */
  77564. function _buildProvidesArray($srcinfo)
  77565. {
  77566. if (!$this->_isValid) {
  77567. return false;
  77568. }
  77569. $file = basename($srcinfo['source_file']);
  77570. $pn = $this->getPackage();
  77571. $pnl = strlen($pn);
  77572. foreach ($srcinfo['declared_classes'] as $class) {
  77573. $key = "class;$class";
  77574. if (isset($this->_packageInfo['provides'][$key])) {
  77575. continue;
  77576. }
  77577. $this->_packageInfo['provides'][$key] =
  77578. array('file'=> $file, 'type' => 'class', 'name' => $class);
  77579. if (isset($srcinfo['inheritance'][$class])) {
  77580. $this->_packageInfo['provides'][$key]['extends'] =
  77581. $srcinfo['inheritance'][$class];
  77582. }
  77583. }
  77584. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  77585. foreach ($methods as $method) {
  77586. $function = "$class::$method";
  77587. $key = "function;$function";
  77588. if ($method[0] == '_' || !strcasecmp($method, $class) ||
  77589. isset($this->_packageInfo['provides'][$key])) {
  77590. continue;
  77591. }
  77592. $this->_packageInfo['provides'][$key] =
  77593. array('file'=> $file, 'type' => 'function', 'name' => $function);
  77594. }
  77595. }
  77596. foreach ($srcinfo['declared_functions'] as $function) {
  77597. $key = "function;$function";
  77598. if ($function[0] == '_' || isset($this->_packageInfo['provides'][$key])) {
  77599. continue;
  77600. }
  77601. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  77602. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  77603. }
  77604. $this->_packageInfo['provides'][$key] =
  77605. array('file'=> $file, 'type' => 'function', 'name' => $function);
  77606. }
  77607. }
  77608. // }}}
  77609. }
  77610. ?>
  77611. <?php
  77612. /**
  77613. * PEAR_PackageFile_v2, package.xml version 2.0
  77614. *
  77615. * PHP versions 4 and 5
  77616. *
  77617. * @category pear
  77618. * @package PEAR
  77619. * @author Greg Beaver <cellog@php.net>
  77620. * @copyright 1997-2009 The Authors
  77621. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  77622. * @link http://pear.php.net/package/PEAR
  77623. * @since File available since Release 1.4.0a1
  77624. */
  77625. /**
  77626. * For error handling
  77627. */
  77628. require_once 'phar://go-pear.phar/' . 'PEAR/ErrorStack.php';
  77629. /**
  77630. * @category pear
  77631. * @package PEAR
  77632. * @author Greg Beaver <cellog@php.net>
  77633. * @copyright 1997-2009 The Authors
  77634. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  77635. * @version Release: 1.10.10
  77636. * @link http://pear.php.net/package/PEAR
  77637. * @since Class available since Release 1.4.0a1
  77638. */
  77639. class PEAR_PackageFile_v2
  77640. {
  77641. /**
  77642. * Parsed package information
  77643. * @var array
  77644. * @access private
  77645. */
  77646. var $_packageInfo = array();
  77647. /**
  77648. * path to package .tgz or false if this is a local/extracted package.xml
  77649. * @var string|false
  77650. * @access private
  77651. */
  77652. var $_archiveFile;
  77653. /**
  77654. * path to package .xml or false if this is an abstract parsed-from-string xml
  77655. * @var string|false
  77656. * @access private
  77657. */
  77658. var $_packageFile;
  77659. /**
  77660. * This is used by file analysis routines to log progress information
  77661. * @var PEAR_Common
  77662. * @access protected
  77663. */
  77664. var $_logger;
  77665. /**
  77666. * This is set to the highest validation level that has been validated
  77667. *
  77668. * If the package.xml is invalid or unknown, this is set to 0. If
  77669. * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If
  77670. * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING
  77671. * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation
  77672. * "caching" to occur, which is particularly important for package validation, so
  77673. * that PHP files are not validated twice
  77674. * @var int
  77675. * @access private
  77676. */
  77677. var $_isValid = 0;
  77678. /**
  77679. * True if the filelist has been validated
  77680. * @param bool
  77681. */
  77682. var $_filesValid = false;
  77683. /**
  77684. * @var PEAR_Registry
  77685. * @access protected
  77686. */
  77687. var $_registry;
  77688. /**
  77689. * @var PEAR_Config
  77690. * @access protected
  77691. */
  77692. var $_config;
  77693. /**
  77694. * Optional Dependency group requested for installation
  77695. * @var string
  77696. * @access private
  77697. */
  77698. var $_requestedGroup = false;
  77699. /**
  77700. * @var PEAR_ErrorStack
  77701. * @access protected
  77702. */
  77703. var $_stack;
  77704. /**
  77705. * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible
  77706. */
  77707. var $_tasksNs;
  77708. /**
  77709. * Determines whether this packagefile was initialized only with partial package info
  77710. *
  77711. * If this package file was constructed via parsing REST, it will only contain
  77712. *
  77713. * - package name
  77714. * - channel name
  77715. * - dependencies
  77716. * @var boolean
  77717. * @access private
  77718. */
  77719. var $_incomplete = true;
  77720. /**
  77721. * @var PEAR_PackageFile_v2_Validator
  77722. */
  77723. var $_v2Validator;
  77724. /**
  77725. * The constructor merely sets up the private error stack
  77726. */
  77727. function __construct()
  77728. {
  77729. $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null);
  77730. $this->_isValid = false;
  77731. }
  77732. /**
  77733. * PHP 4 style constructor for backwards compatibility.
  77734. * Used by PEAR_PackageFileManager2
  77735. */
  77736. public function PEAR_PackageFile_v2()
  77737. {
  77738. $this->__construct();
  77739. }
  77740. /**
  77741. * To make unit-testing easier
  77742. * @param PEAR_Frontend_*
  77743. * @param array options
  77744. * @param PEAR_Config
  77745. * @return PEAR_Downloader
  77746. * @access protected
  77747. */
  77748. function &getPEARDownloader(&$i, $o, &$c)
  77749. {
  77750. $z = new PEAR_Downloader($i, $o, $c);
  77751. return $z;
  77752. }
  77753. /**
  77754. * To make unit-testing easier
  77755. * @param PEAR_Config
  77756. * @param array options
  77757. * @param array package name as returned from {@link PEAR_Registry::parsePackageName()}
  77758. * @param int PEAR_VALIDATE_* constant
  77759. * @return PEAR_Dependency2
  77760. * @access protected
  77761. */
  77762. function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING)
  77763. {
  77764. if (!class_exists('PEAR_Dependency2')) {
  77765. require_once 'phar://go-pear.phar/' . 'PEAR/Dependency2.php';
  77766. }
  77767. $z = new PEAR_Dependency2($c, $o, $p, $s);
  77768. return $z;
  77769. }
  77770. function getInstalledBinary()
  77771. {
  77772. return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] :
  77773. false;
  77774. }
  77775. /**
  77776. * Installation of source package has failed, attempt to download and install the
  77777. * binary version of this package.
  77778. * @param PEAR_Installer
  77779. * @return array|false
  77780. */
  77781. function installBinary(&$installer)
  77782. {
  77783. if (!OS_WINDOWS) {
  77784. $a = false;
  77785. return $a;
  77786. }
  77787. if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
  77788. $releasetype = $this->getPackageType() . 'release';
  77789. if (!is_array($installer->getInstallPackages())) {
  77790. $a = false;
  77791. return $a;
  77792. }
  77793. foreach ($installer->getInstallPackages() as $p) {
  77794. if ($p->isExtension($this->_packageInfo['providesextension'])) {
  77795. if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') {
  77796. $a = false;
  77797. return $a; // the user probably downloaded it separately
  77798. }
  77799. }
  77800. }
  77801. if (isset($this->_packageInfo[$releasetype]['binarypackage'])) {
  77802. $installer->log(0, 'Attempting to download binary version of extension "' .
  77803. $this->_packageInfo['providesextension'] . '"');
  77804. $params = $this->_packageInfo[$releasetype]['binarypackage'];
  77805. if (!is_array($params) || !isset($params[0])) {
  77806. $params = array($params);
  77807. }
  77808. if (isset($this->_packageInfo['channel'])) {
  77809. foreach ($params as $i => $param) {
  77810. $params[$i] = array('channel' => $this->_packageInfo['channel'],
  77811. 'package' => $param, 'version' => $this->getVersion());
  77812. }
  77813. }
  77814. $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(),
  77815. $installer->config);
  77816. $verbose = $dl->config->get('verbose');
  77817. $dl->config->set('verbose', -1);
  77818. foreach ($params as $param) {
  77819. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  77820. $ret = $dl->download(array($param));
  77821. PEAR::popErrorHandling();
  77822. if (is_array($ret) && count($ret)) {
  77823. break;
  77824. }
  77825. }
  77826. $dl->config->set('verbose', $verbose);
  77827. if (is_array($ret)) {
  77828. if (count($ret) == 1) {
  77829. $pf = $ret[0]->getPackageFile();
  77830. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  77831. $err = $installer->install($ret[0]);
  77832. PEAR::popErrorHandling();
  77833. if (is_array($err)) {
  77834. $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage();
  77835. // "install" self, so all dependencies will work transparently
  77836. $this->_registry->addPackage2($this);
  77837. $installer->log(0, 'Download and install of binary extension "' .
  77838. $this->_registry->parsedPackageNameToString(
  77839. array('channel' => $pf->getChannel(),
  77840. 'package' => $pf->getPackage()), true) . '" successful');
  77841. $a = array($ret[0], $err);
  77842. return $a;
  77843. }
  77844. $installer->log(0, 'Download and install of binary extension "' .
  77845. $this->_registry->parsedPackageNameToString(
  77846. array('channel' => $pf->getChannel(),
  77847. 'package' => $pf->getPackage()), true) . '" failed');
  77848. }
  77849. }
  77850. }
  77851. }
  77852. $a = false;
  77853. return $a;
  77854. }
  77855. /**
  77856. * @return string|false Extension name
  77857. */
  77858. function getProvidesExtension()
  77859. {
  77860. if (in_array($this->getPackageType(),
  77861. array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
  77862. if (isset($this->_packageInfo['providesextension'])) {
  77863. return $this->_packageInfo['providesextension'];
  77864. }
  77865. }
  77866. return false;
  77867. }
  77868. /**
  77869. * @param string Extension name
  77870. * @return bool
  77871. */
  77872. function isExtension($extension)
  77873. {
  77874. if (in_array($this->getPackageType(),
  77875. array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
  77876. return $this->_packageInfo['providesextension'] == $extension;
  77877. }
  77878. return false;
  77879. }
  77880. /**
  77881. * Tests whether every part of the package.xml 1.0 is represented in
  77882. * this package.xml 2.0
  77883. * @param PEAR_PackageFile_v1
  77884. * @return bool
  77885. */
  77886. function isEquivalent($pf1)
  77887. {
  77888. if (!$pf1) {
  77889. return true;
  77890. }
  77891. if ($this->getPackageType() == 'bundle') {
  77892. return false;
  77893. }
  77894. $this->_stack->getErrors(true);
  77895. if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) {
  77896. return false;
  77897. }
  77898. $pass = true;
  77899. if ($pf1->getPackage() != $this->getPackage()) {
  77900. $this->_differentPackage($pf1->getPackage());
  77901. $pass = false;
  77902. }
  77903. if ($pf1->getVersion() != $this->getVersion()) {
  77904. $this->_differentVersion($pf1->getVersion());
  77905. $pass = false;
  77906. }
  77907. if (trim($pf1->getSummary()) != $this->getSummary()) {
  77908. $this->_differentSummary($pf1->getSummary());
  77909. $pass = false;
  77910. }
  77911. if (preg_replace('/\s+/', '', $pf1->getDescription()) !=
  77912. preg_replace('/\s+/', '', $this->getDescription())) {
  77913. $this->_differentDescription($pf1->getDescription());
  77914. $pass = false;
  77915. }
  77916. if ($pf1->getState() != $this->getState()) {
  77917. $this->_differentState($pf1->getState());
  77918. $pass = false;
  77919. }
  77920. if (!strstr(preg_replace('/\s+/', '', $this->getNotes()),
  77921. preg_replace('/\s+/', '', $pf1->getNotes()))) {
  77922. $this->_differentNotes($pf1->getNotes());
  77923. $pass = false;
  77924. }
  77925. $mymaintainers = $this->getMaintainers();
  77926. $yourmaintainers = $pf1->getMaintainers();
  77927. for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) {
  77928. $reset = false;
  77929. for ($i2 = 0; $i2 < count($mymaintainers); $i2++) {
  77930. if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) {
  77931. if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) {
  77932. $this->_differentRole($mymaintainers[$i2]['handle'],
  77933. $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']);
  77934. $pass = false;
  77935. }
  77936. if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) {
  77937. $this->_differentEmail($mymaintainers[$i2]['handle'],
  77938. $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']);
  77939. $pass = false;
  77940. }
  77941. if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) {
  77942. $this->_differentName($mymaintainers[$i2]['handle'],
  77943. $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']);
  77944. $pass = false;
  77945. }
  77946. unset($mymaintainers[$i2]);
  77947. $mymaintainers = array_values($mymaintainers);
  77948. unset($yourmaintainers[$i1]);
  77949. $yourmaintainers = array_values($yourmaintainers);
  77950. $reset = true;
  77951. break;
  77952. }
  77953. }
  77954. if ($reset) {
  77955. $i1 = -1;
  77956. }
  77957. }
  77958. $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers);
  77959. $filelist = $this->getFilelist();
  77960. foreach ($pf1->getFilelist() as $file => $atts) {
  77961. if (!isset($filelist[$file])) {
  77962. $this->_missingFile($file);
  77963. $pass = false;
  77964. }
  77965. }
  77966. return $pass;
  77967. }
  77968. function _differentPackage($package)
  77969. {
  77970. $this->_stack->push(__FUNCTION__, 'error', array('package' => $package,
  77971. 'self' => $this->getPackage()),
  77972. 'package.xml 1.0 package "%package%" does not match "%self%"');
  77973. }
  77974. function _differentVersion($version)
  77975. {
  77976. $this->_stack->push(__FUNCTION__, 'error', array('version' => $version,
  77977. 'self' => $this->getVersion()),
  77978. 'package.xml 1.0 version "%version%" does not match "%self%"');
  77979. }
  77980. function _differentState($state)
  77981. {
  77982. $this->_stack->push(__FUNCTION__, 'error', array('state' => $state,
  77983. 'self' => $this->getState()),
  77984. 'package.xml 1.0 state "%state%" does not match "%self%"');
  77985. }
  77986. function _differentRole($handle, $role, $selfrole)
  77987. {
  77988. $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
  77989. 'role' => $role, 'self' => $selfrole),
  77990. 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"');
  77991. }
  77992. function _differentEmail($handle, $email, $selfemail)
  77993. {
  77994. $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
  77995. 'email' => $email, 'self' => $selfemail),
  77996. 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"');
  77997. }
  77998. function _differentName($handle, $name, $selfname)
  77999. {
  78000. $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
  78001. 'name' => $name, 'self' => $selfname),
  78002. 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"');
  78003. }
  78004. function _unmatchedMaintainers($my, $yours)
  78005. {
  78006. if ($my) {
  78007. array_walk($my, function(&$i, $k) { $i = $i["handle"]; });
  78008. $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my),
  78009. 'package.xml 2.0 has unmatched extra maintainers "%handles%"');
  78010. }
  78011. if ($yours) {
  78012. array_walk($yours, function(&$i, $k) { $i = $i["handle"]; });
  78013. $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours),
  78014. 'package.xml 1.0 has unmatched extra maintainers "%handles%"');
  78015. }
  78016. }
  78017. function _differentNotes($notes)
  78018. {
  78019. $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...';
  78020. $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() :
  78021. substr($this->getNotes(), 0, 24) . '...';
  78022. $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes,
  78023. 'self' => $truncmynotes),
  78024. 'package.xml 1.0 release notes "%notes%" do not match "%self%"');
  78025. }
  78026. function _differentSummary($summary)
  78027. {
  78028. $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...';
  78029. $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() :
  78030. substr($this->getsummary(), 0, 24) . '...';
  78031. $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary,
  78032. 'self' => $truncmysummary),
  78033. 'package.xml 1.0 summary "%summary%" does not match "%self%"');
  78034. }
  78035. function _differentDescription($description)
  78036. {
  78037. $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...');
  78038. $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() :
  78039. substr($this->getdescription(), 0, 24) . '...');
  78040. $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription,
  78041. 'self' => $truncmydescription),
  78042. 'package.xml 1.0 description "%description%" does not match "%self%"');
  78043. }
  78044. function _missingFile($file)
  78045. {
  78046. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  78047. 'package.xml 1.0 file "%file%" is not present in <contents>');
  78048. }
  78049. /**
  78050. * WARNING - do not use this function unless you know what you're doing
  78051. */
  78052. function setRawState($state)
  78053. {
  78054. if (!isset($this->_packageInfo['stability'])) {
  78055. $this->_packageInfo['stability'] = array();
  78056. }
  78057. $this->_packageInfo['stability']['release'] = $state;
  78058. }
  78059. /**
  78060. * WARNING - do not use this function unless you know what you're doing
  78061. */
  78062. function setRawCompatible($compatible)
  78063. {
  78064. $this->_packageInfo['compatible'] = $compatible;
  78065. }
  78066. /**
  78067. * WARNING - do not use this function unless you know what you're doing
  78068. */
  78069. function setRawPackage($package)
  78070. {
  78071. $this->_packageInfo['name'] = $package;
  78072. }
  78073. /**
  78074. * WARNING - do not use this function unless you know what you're doing
  78075. */
  78076. function setRawChannel($channel)
  78077. {
  78078. $this->_packageInfo['channel'] = $channel;
  78079. }
  78080. function setRequestedGroup($group)
  78081. {
  78082. $this->_requestedGroup = $group;
  78083. }
  78084. function getRequestedGroup()
  78085. {
  78086. if (isset($this->_requestedGroup)) {
  78087. return $this->_requestedGroup;
  78088. }
  78089. return false;
  78090. }
  78091. /**
  78092. * For saving in the registry.
  78093. *
  78094. * Set the last version that was installed
  78095. * @param string
  78096. */
  78097. function setLastInstalledVersion($version)
  78098. {
  78099. $this->_packageInfo['_lastversion'] = $version;
  78100. }
  78101. /**
  78102. * @return string|false
  78103. */
  78104. function getLastInstalledVersion()
  78105. {
  78106. if (isset($this->_packageInfo['_lastversion'])) {
  78107. return $this->_packageInfo['_lastversion'];
  78108. }
  78109. return false;
  78110. }
  78111. /**
  78112. * Determines whether this package.xml has post-install scripts or not
  78113. * @return array|false
  78114. */
  78115. function listPostinstallScripts()
  78116. {
  78117. $filelist = $this->getFilelist();
  78118. $contents = $this->getContents();
  78119. $contents = $contents['dir']['file'];
  78120. if (!is_array($contents) || !isset($contents[0])) {
  78121. $contents = array($contents);
  78122. }
  78123. $taskfiles = array();
  78124. foreach ($contents as $file) {
  78125. $atts = $file['attribs'];
  78126. unset($file['attribs']);
  78127. if (count($file)) {
  78128. $taskfiles[$atts['name']] = $file;
  78129. }
  78130. }
  78131. $common = new PEAR_Common;
  78132. $common->debug = $this->_config->get('verbose');
  78133. $this->_scripts = array();
  78134. $ret = array();
  78135. foreach ($taskfiles as $name => $tasks) {
  78136. if (!isset($filelist[$name])) {
  78137. // ignored files will not be in the filelist
  78138. continue;
  78139. }
  78140. $atts = $filelist[$name];
  78141. foreach ($tasks as $tag => $raw) {
  78142. $task = $this->getTask($tag);
  78143. $task = new $task($this->_config, $common, PEAR_TASK_INSTALL);
  78144. if ($task->isScript()) {
  78145. $ret[] = $filelist[$name]['installed_as'];
  78146. }
  78147. }
  78148. }
  78149. if (count($ret)) {
  78150. return $ret;
  78151. }
  78152. return false;
  78153. }
  78154. /**
  78155. * Initialize post-install scripts for running
  78156. *
  78157. * This method can be used to detect post-install scripts, as the return value
  78158. * indicates whether any exist
  78159. * @return bool
  78160. */
  78161. function initPostinstallScripts()
  78162. {
  78163. $filelist = $this->getFilelist();
  78164. $contents = $this->getContents();
  78165. $contents = $contents['dir']['file'];
  78166. if (!is_array($contents) || !isset($contents[0])) {
  78167. $contents = array($contents);
  78168. }
  78169. $taskfiles = array();
  78170. foreach ($contents as $file) {
  78171. $atts = $file['attribs'];
  78172. unset($file['attribs']);
  78173. if (count($file)) {
  78174. $taskfiles[$atts['name']] = $file;
  78175. }
  78176. }
  78177. $common = new PEAR_Common;
  78178. $common->debug = $this->_config->get('verbose');
  78179. $this->_scripts = array();
  78180. foreach ($taskfiles as $name => $tasks) {
  78181. if (!isset($filelist[$name])) {
  78182. // file was not installed due to installconditions
  78183. continue;
  78184. }
  78185. $atts = $filelist[$name];
  78186. foreach ($tasks as $tag => $raw) {
  78187. $taskname = $this->getTask($tag);
  78188. $task = new $taskname($this->_config, $common, PEAR_TASK_INSTALL);
  78189. if (!$task->isScript()) {
  78190. continue; // scripts are only handled after installation
  78191. }
  78192. $lastversion = isset($this->_packageInfo['_lastversion']) ?
  78193. $this->_packageInfo['_lastversion'] : null;
  78194. $task->init($raw, $atts, $lastversion);
  78195. $res = $task->startSession($this, $atts['installed_as'], null);
  78196. if (!$res) {
  78197. continue; // skip this file
  78198. }
  78199. if (PEAR::isError($res)) {
  78200. return $res;
  78201. }
  78202. $this->_scripts[] = $task;
  78203. }
  78204. }
  78205. if (count($this->_scripts)) {
  78206. return true;
  78207. }
  78208. return false;
  78209. }
  78210. function runPostinstallScripts()
  78211. {
  78212. if ($this->initPostinstallScripts()) {
  78213. $ui = &PEAR_Frontend::singleton();
  78214. if ($ui) {
  78215. $ui->runPostinstallScripts($this->_scripts, $this);
  78216. }
  78217. }
  78218. }
  78219. /**
  78220. * Convert a recursive set of <dir> and <file> tags into a single <dir> tag with
  78221. * <file> tags.
  78222. */
  78223. function flattenFilelist()
  78224. {
  78225. if (isset($this->_packageInfo['bundle'])) {
  78226. return;
  78227. }
  78228. $filelist = array();
  78229. if (isset($this->_packageInfo['contents']['dir']['dir'])) {
  78230. $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']);
  78231. if (!isset($filelist[1])) {
  78232. $filelist = $filelist[0];
  78233. }
  78234. $this->_packageInfo['contents']['dir']['file'] = $filelist;
  78235. unset($this->_packageInfo['contents']['dir']['dir']);
  78236. } else {
  78237. // else already flattened but check for baseinstalldir propagation
  78238. if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) {
  78239. if (isset($this->_packageInfo['contents']['dir']['file'][0])) {
  78240. foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) {
  78241. if (isset($file['attribs']['baseinstalldir'])) {
  78242. continue;
  78243. }
  78244. $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir']
  78245. = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
  78246. }
  78247. } else {
  78248. if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) {
  78249. $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir']
  78250. = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
  78251. }
  78252. }
  78253. }
  78254. }
  78255. }
  78256. /**
  78257. * @param array the final flattened file list
  78258. * @param array the current directory being processed
  78259. * @param string|false any recursively inherited baeinstalldir attribute
  78260. * @param string private recursion variable
  78261. * @return array
  78262. * @access protected
  78263. */
  78264. function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '')
  78265. {
  78266. if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) {
  78267. $baseinstall = $dir['attribs']['baseinstalldir'];
  78268. }
  78269. if (isset($dir['dir'])) {
  78270. if (!isset($dir['dir'][0])) {
  78271. $dir['dir'] = array($dir['dir']);
  78272. }
  78273. foreach ($dir['dir'] as $subdir) {
  78274. if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) {
  78275. $name = '*unknown*';
  78276. } else {
  78277. $name = $subdir['attribs']['name'];
  78278. }
  78279. $newpath = empty($path) ? $name :
  78280. $path . '/' . $name;
  78281. $this->_getFlattenedFilelist($files, $subdir,
  78282. $baseinstall, $newpath);
  78283. }
  78284. }
  78285. if (isset($dir['file'])) {
  78286. if (!isset($dir['file'][0])) {
  78287. $dir['file'] = array($dir['file']);
  78288. }
  78289. foreach ($dir['file'] as $file) {
  78290. $attrs = $file['attribs'];
  78291. $name = $attrs['name'];
  78292. if ($baseinstall && !isset($attrs['baseinstalldir'])) {
  78293. $attrs['baseinstalldir'] = $baseinstall;
  78294. }
  78295. $attrs['name'] = empty($path) ? $name : $path . '/' . $name;
  78296. $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
  78297. $attrs['name']);
  78298. $file['attribs'] = $attrs;
  78299. $files[] = $file;
  78300. }
  78301. }
  78302. }
  78303. function setConfig(&$config)
  78304. {
  78305. $this->_config = &$config;
  78306. $this->_registry = &$config->getRegistry();
  78307. }
  78308. function setLogger(&$logger)
  78309. {
  78310. if (!is_object($logger) || !method_exists($logger, 'log')) {
  78311. return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
  78312. }
  78313. $this->_logger = &$logger;
  78314. }
  78315. /**
  78316. * WARNING - do not use this function directly unless you know what you're doing
  78317. */
  78318. function setDeps($deps)
  78319. {
  78320. $this->_packageInfo['dependencies'] = $deps;
  78321. }
  78322. /**
  78323. * WARNING - do not use this function directly unless you know what you're doing
  78324. */
  78325. function setCompatible($compat)
  78326. {
  78327. $this->_packageInfo['compatible'] = $compat;
  78328. }
  78329. function setPackagefile($file, $archive = false)
  78330. {
  78331. $this->_packageFile = $file;
  78332. $this->_archiveFile = $archive ? $archive : $file;
  78333. }
  78334. /**
  78335. * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  78336. * @param boolean determines whether to purge the error stack after retrieving
  78337. * @return array
  78338. */
  78339. function getValidationWarnings($purge = true)
  78340. {
  78341. return $this->_stack->getErrors($purge);
  78342. }
  78343. function getPackageFile()
  78344. {
  78345. return $this->_packageFile;
  78346. }
  78347. function getArchiveFile()
  78348. {
  78349. return $this->_archiveFile;
  78350. }
  78351. /**
  78352. * Directly set the array that defines this packagefile
  78353. *
  78354. * WARNING: no validation. This should only be performed by internal methods
  78355. * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2
  78356. * @param array
  78357. */
  78358. function fromArray($pinfo)
  78359. {
  78360. unset($pinfo['old']);
  78361. unset($pinfo['xsdversion']);
  78362. // If the changelog isn't an array then it was passed in as an empty tag
  78363. if (isset($pinfo['changelog']) && !is_array($pinfo['changelog'])) {
  78364. unset($pinfo['changelog']);
  78365. }
  78366. $this->_incomplete = false;
  78367. $this->_packageInfo = $pinfo;
  78368. }
  78369. function isIncomplete()
  78370. {
  78371. return $this->_incomplete;
  78372. }
  78373. /**
  78374. * @return array
  78375. */
  78376. function toArray($forreg = false)
  78377. {
  78378. if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
  78379. return false;
  78380. }
  78381. return $this->getArray($forreg);
  78382. }
  78383. function getArray($forReg = false)
  78384. {
  78385. if ($forReg) {
  78386. $arr = $this->_packageInfo;
  78387. $arr['old'] = array();
  78388. $arr['old']['version'] = $this->getVersion();
  78389. $arr['old']['release_date'] = $this->getDate();
  78390. $arr['old']['release_state'] = $this->getState();
  78391. $arr['old']['release_license'] = $this->getLicense();
  78392. $arr['old']['release_notes'] = $this->getNotes();
  78393. $arr['old']['release_deps'] = $this->getDeps();
  78394. $arr['old']['maintainers'] = $this->getMaintainers();
  78395. $arr['xsdversion'] = '2.0';
  78396. return $arr;
  78397. } else {
  78398. $info = $this->_packageInfo;
  78399. unset($info['dirtree']);
  78400. if (isset($info['_lastversion'])) {
  78401. unset($info['_lastversion']);
  78402. }
  78403. if (isset($info['#binarypackage'])) {
  78404. unset($info['#binarypackage']);
  78405. }
  78406. return $info;
  78407. }
  78408. }
  78409. function packageInfo($field)
  78410. {
  78411. $arr = $this->getArray(true);
  78412. if ($field == 'state') {
  78413. return $arr['stability']['release'];
  78414. }
  78415. if ($field == 'api-version') {
  78416. return $arr['version']['api'];
  78417. }
  78418. if ($field == 'api-state') {
  78419. return $arr['stability']['api'];
  78420. }
  78421. if (isset($arr['old'][$field])) {
  78422. if (!is_string($arr['old'][$field])) {
  78423. return null;
  78424. }
  78425. return $arr['old'][$field];
  78426. }
  78427. if (isset($arr[$field])) {
  78428. if (!is_string($arr[$field])) {
  78429. return null;
  78430. }
  78431. return $arr[$field];
  78432. }
  78433. return null;
  78434. }
  78435. function getName()
  78436. {
  78437. return $this->getPackage();
  78438. }
  78439. function getPackage()
  78440. {
  78441. if (isset($this->_packageInfo['name'])) {
  78442. return $this->_packageInfo['name'];
  78443. }
  78444. return false;
  78445. }
  78446. function getChannel()
  78447. {
  78448. if (isset($this->_packageInfo['uri'])) {
  78449. return '__uri';
  78450. }
  78451. if (isset($this->_packageInfo['channel'])) {
  78452. return strtolower($this->_packageInfo['channel']);
  78453. }
  78454. return false;
  78455. }
  78456. function getUri()
  78457. {
  78458. if (isset($this->_packageInfo['uri'])) {
  78459. return $this->_packageInfo['uri'];
  78460. }
  78461. return false;
  78462. }
  78463. function getExtends()
  78464. {
  78465. if (isset($this->_packageInfo['extends'])) {
  78466. return $this->_packageInfo['extends'];
  78467. }
  78468. return false;
  78469. }
  78470. function getSummary()
  78471. {
  78472. if (isset($this->_packageInfo['summary'])) {
  78473. return $this->_packageInfo['summary'];
  78474. }
  78475. return false;
  78476. }
  78477. function getDescription()
  78478. {
  78479. if (isset($this->_packageInfo['description'])) {
  78480. return $this->_packageInfo['description'];
  78481. }
  78482. return false;
  78483. }
  78484. function getMaintainers($raw = false)
  78485. {
  78486. if (!isset($this->_packageInfo['lead'])) {
  78487. return false;
  78488. }
  78489. if ($raw) {
  78490. $ret = array('lead' => $this->_packageInfo['lead']);
  78491. (isset($this->_packageInfo['developer'])) ?
  78492. $ret['developer'] = $this->_packageInfo['developer'] :null;
  78493. (isset($this->_packageInfo['contributor'])) ?
  78494. $ret['contributor'] = $this->_packageInfo['contributor'] :null;
  78495. (isset($this->_packageInfo['helper'])) ?
  78496. $ret['helper'] = $this->_packageInfo['helper'] :null;
  78497. return $ret;
  78498. } else {
  78499. $ret = array();
  78500. $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] :
  78501. array($this->_packageInfo['lead']);
  78502. foreach ($leads as $lead) {
  78503. $s = $lead;
  78504. $s['handle'] = $s['user'];
  78505. unset($s['user']);
  78506. $s['role'] = 'lead';
  78507. $ret[] = $s;
  78508. }
  78509. if (isset($this->_packageInfo['developer'])) {
  78510. $leads = isset($this->_packageInfo['developer'][0]) ?
  78511. $this->_packageInfo['developer'] :
  78512. array($this->_packageInfo['developer']);
  78513. foreach ($leads as $maintainer) {
  78514. $s = $maintainer;
  78515. $s['handle'] = $s['user'];
  78516. unset($s['user']);
  78517. $s['role'] = 'developer';
  78518. $ret[] = $s;
  78519. }
  78520. }
  78521. if (isset($this->_packageInfo['contributor'])) {
  78522. $leads = isset($this->_packageInfo['contributor'][0]) ?
  78523. $this->_packageInfo['contributor'] :
  78524. array($this->_packageInfo['contributor']);
  78525. foreach ($leads as $maintainer) {
  78526. $s = $maintainer;
  78527. $s['handle'] = $s['user'];
  78528. unset($s['user']);
  78529. $s['role'] = 'contributor';
  78530. $ret[] = $s;
  78531. }
  78532. }
  78533. if (isset($this->_packageInfo['helper'])) {
  78534. $leads = isset($this->_packageInfo['helper'][0]) ?
  78535. $this->_packageInfo['helper'] :
  78536. array($this->_packageInfo['helper']);
  78537. foreach ($leads as $maintainer) {
  78538. $s = $maintainer;
  78539. $s['handle'] = $s['user'];
  78540. unset($s['user']);
  78541. $s['role'] = 'helper';
  78542. $ret[] = $s;
  78543. }
  78544. }
  78545. return $ret;
  78546. }
  78547. return false;
  78548. }
  78549. function getLeads()
  78550. {
  78551. if (isset($this->_packageInfo['lead'])) {
  78552. return $this->_packageInfo['lead'];
  78553. }
  78554. return false;
  78555. }
  78556. function getDevelopers()
  78557. {
  78558. if (isset($this->_packageInfo['developer'])) {
  78559. return $this->_packageInfo['developer'];
  78560. }
  78561. return false;
  78562. }
  78563. function getContributors()
  78564. {
  78565. if (isset($this->_packageInfo['contributor'])) {
  78566. return $this->_packageInfo['contributor'];
  78567. }
  78568. return false;
  78569. }
  78570. function getHelpers()
  78571. {
  78572. if (isset($this->_packageInfo['helper'])) {
  78573. return $this->_packageInfo['helper'];
  78574. }
  78575. return false;
  78576. }
  78577. function setDate($date)
  78578. {
  78579. if (!isset($this->_packageInfo['date'])) {
  78580. // ensure that the extends tag is set up in the right location
  78581. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  78582. array('time', 'version',
  78583. 'stability', 'license', 'notes', 'contents', 'compatible',
  78584. 'dependencies', 'providesextension', 'srcpackage', 'srcuri',
  78585. 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
  78586. 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date');
  78587. }
  78588. $this->_packageInfo['date'] = $date;
  78589. $this->_isValid = 0;
  78590. }
  78591. function setTime($time)
  78592. {
  78593. $this->_isValid = 0;
  78594. if (!isset($this->_packageInfo['time'])) {
  78595. // ensure that the time tag is set up in the right location
  78596. $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
  78597. array('version',
  78598. 'stability', 'license', 'notes', 'contents', 'compatible',
  78599. 'dependencies', 'providesextension', 'srcpackage', 'srcuri',
  78600. 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
  78601. 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time');
  78602. }
  78603. $this->_packageInfo['time'] = $time;
  78604. }
  78605. function getDate()
  78606. {
  78607. if (isset($this->_packageInfo['date'])) {
  78608. return $this->_packageInfo['date'];
  78609. }
  78610. return false;
  78611. }
  78612. function getTime()
  78613. {
  78614. if (isset($this->_packageInfo['time'])) {
  78615. return $this->_packageInfo['time'];
  78616. }
  78617. return false;
  78618. }
  78619. /**
  78620. * @param package|api version category to return
  78621. */
  78622. function getVersion($key = 'release')
  78623. {
  78624. if (isset($this->_packageInfo['version'][$key])) {
  78625. return $this->_packageInfo['version'][$key];
  78626. }
  78627. return false;
  78628. }
  78629. function getStability()
  78630. {
  78631. if (isset($this->_packageInfo['stability'])) {
  78632. return $this->_packageInfo['stability'];
  78633. }
  78634. return false;
  78635. }
  78636. function getState($key = 'release')
  78637. {
  78638. if (isset($this->_packageInfo['stability'][$key])) {
  78639. return $this->_packageInfo['stability'][$key];
  78640. }
  78641. return false;
  78642. }
  78643. function getLicense($raw = false)
  78644. {
  78645. if (isset($this->_packageInfo['license'])) {
  78646. if ($raw) {
  78647. return $this->_packageInfo['license'];
  78648. }
  78649. if (is_array($this->_packageInfo['license'])) {
  78650. return $this->_packageInfo['license']['_content'];
  78651. } else {
  78652. return $this->_packageInfo['license'];
  78653. }
  78654. }
  78655. return false;
  78656. }
  78657. function getLicenseLocation()
  78658. {
  78659. if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) {
  78660. return false;
  78661. }
  78662. return $this->_packageInfo['license']['attribs'];
  78663. }
  78664. function getNotes()
  78665. {
  78666. if (isset($this->_packageInfo['notes'])) {
  78667. return $this->_packageInfo['notes'];
  78668. }
  78669. return false;
  78670. }
  78671. /**
  78672. * Return the <usesrole> tag contents, if any
  78673. * @return array|false
  78674. */
  78675. function getUsesrole()
  78676. {
  78677. if (isset($this->_packageInfo['usesrole'])) {
  78678. return $this->_packageInfo['usesrole'];
  78679. }
  78680. return false;
  78681. }
  78682. /**
  78683. * Return the <usestask> tag contents, if any
  78684. * @return array|false
  78685. */
  78686. function getUsestask()
  78687. {
  78688. if (isset($this->_packageInfo['usestask'])) {
  78689. return $this->_packageInfo['usestask'];
  78690. }
  78691. return false;
  78692. }
  78693. /**
  78694. * This should only be used to retrieve filenames and install attributes
  78695. */
  78696. function getFilelist($preserve = false)
  78697. {
  78698. if (isset($this->_packageInfo['filelist']) && !$preserve) {
  78699. return $this->_packageInfo['filelist'];
  78700. }
  78701. $this->flattenFilelist();
  78702. if ($contents = $this->getContents()) {
  78703. $ret = array();
  78704. if (!isset($contents['dir'])) {
  78705. return false;
  78706. }
  78707. if (!isset($contents['dir']['file'][0])) {
  78708. $contents['dir']['file'] = array($contents['dir']['file']);
  78709. }
  78710. foreach ($contents['dir']['file'] as $file) {
  78711. if (!isset($file['attribs']['name'])) {
  78712. continue;
  78713. }
  78714. $name = $file['attribs']['name'];
  78715. if (!$preserve) {
  78716. $file = $file['attribs'];
  78717. }
  78718. $ret[$name] = $file;
  78719. }
  78720. if (!$preserve) {
  78721. $this->_packageInfo['filelist'] = $ret;
  78722. }
  78723. return $ret;
  78724. }
  78725. return false;
  78726. }
  78727. /**
  78728. * Return configure options array, if any
  78729. *
  78730. * @return array|false
  78731. */
  78732. function getConfigureOptions()
  78733. {
  78734. if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
  78735. return false;
  78736. }
  78737. $releases = $this->getReleases();
  78738. if (isset($releases[0])) {
  78739. $releases = $releases[0];
  78740. }
  78741. if (isset($releases['configureoption'])) {
  78742. if (!isset($releases['configureoption'][0])) {
  78743. $releases['configureoption'] = array($releases['configureoption']);
  78744. }
  78745. for ($i = 0; $i < count($releases['configureoption']); $i++) {
  78746. $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs'];
  78747. }
  78748. return $releases['configureoption'];
  78749. }
  78750. return false;
  78751. }
  78752. /**
  78753. * This is only used at install-time, after all serialization
  78754. * is over.
  78755. */
  78756. function resetFilelist()
  78757. {
  78758. $this->_packageInfo['filelist'] = array();
  78759. }
  78760. /**
  78761. * Retrieve a list of files that should be installed on this computer
  78762. * @return array
  78763. */
  78764. function getInstallationFilelist($forfilecheck = false)
  78765. {
  78766. $contents = $this->getFilelist(true);
  78767. if (isset($contents['dir']['attribs']['baseinstalldir'])) {
  78768. $base = $contents['dir']['attribs']['baseinstalldir'];
  78769. }
  78770. if (isset($this->_packageInfo['bundle'])) {
  78771. return PEAR::raiseError(
  78772. 'Exception: bundles should be handled in download code only');
  78773. }
  78774. $release = $this->getReleases();
  78775. if ($release) {
  78776. if (!isset($release[0])) {
  78777. if (!isset($release['installconditions']) && !isset($release['filelist'])) {
  78778. if ($forfilecheck) {
  78779. return $this->getFilelist();
  78780. }
  78781. return $contents;
  78782. }
  78783. $release = array($release);
  78784. }
  78785. $depchecker = &$this->getPEARDependency2($this->_config, array(),
  78786. array('channel' => $this->getChannel(), 'package' => $this->getPackage()),
  78787. PEAR_VALIDATE_INSTALLING);
  78788. foreach ($release as $instance) {
  78789. if (isset($instance['installconditions'])) {
  78790. $installconditions = $instance['installconditions'];
  78791. if (is_array($installconditions)) {
  78792. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  78793. foreach ($installconditions as $type => $conditions) {
  78794. if (!isset($conditions[0])) {
  78795. $conditions = array($conditions);
  78796. }
  78797. foreach ($conditions as $condition) {
  78798. $ret = $depchecker->{"validate{$type}Dependency"}($condition);
  78799. if (PEAR::isError($ret)) {
  78800. PEAR::popErrorHandling();
  78801. continue 3; // skip this release
  78802. }
  78803. }
  78804. }
  78805. PEAR::popErrorHandling();
  78806. }
  78807. }
  78808. // this is the release to use
  78809. if (isset($instance['filelist'])) {
  78810. // ignore files
  78811. if (isset($instance['filelist']['ignore'])) {
  78812. $ignore = isset($instance['filelist']['ignore'][0]) ?
  78813. $instance['filelist']['ignore'] :
  78814. array($instance['filelist']['ignore']);
  78815. foreach ($ignore as $ig) {
  78816. unset ($contents[$ig['attribs']['name']]);
  78817. }
  78818. }
  78819. // install files as this name
  78820. if (isset($instance['filelist']['install'])) {
  78821. $installas = isset($instance['filelist']['install'][0]) ?
  78822. $instance['filelist']['install'] :
  78823. array($instance['filelist']['install']);
  78824. foreach ($installas as $as) {
  78825. $contents[$as['attribs']['name']]['attribs']['install-as'] =
  78826. $as['attribs']['as'];
  78827. }
  78828. }
  78829. }
  78830. if ($forfilecheck) {
  78831. foreach ($contents as $file => $attrs) {
  78832. $contents[$file] = $attrs['attribs'];
  78833. }
  78834. }
  78835. return $contents;
  78836. }
  78837. } else { // simple release - no installconditions or install-as
  78838. if ($forfilecheck) {
  78839. return $this->getFilelist();
  78840. }
  78841. return $contents;
  78842. }
  78843. // no releases matched
  78844. return PEAR::raiseError('No releases in package.xml matched the existing operating ' .
  78845. 'system, extensions installed, or architecture, cannot install');
  78846. }
  78847. /**
  78848. * This is only used at install-time, after all serialization
  78849. * is over.
  78850. * @param string file name
  78851. * @param string installed path
  78852. */
  78853. function setInstalledAs($file, $path)
  78854. {
  78855. if ($path) {
  78856. return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
  78857. }
  78858. unset($this->_packageInfo['filelist'][$file]['installed_as']);
  78859. }
  78860. function getInstalledLocation($file)
  78861. {
  78862. if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) {
  78863. return $this->_packageInfo['filelist'][$file]['installed_as'];
  78864. }
  78865. return false;
  78866. }
  78867. /**
  78868. * This is only used at install-time, after all serialization
  78869. * is over.
  78870. */
  78871. function installedFile($file, $atts)
  78872. {
  78873. if (isset($this->_packageInfo['filelist'][$file])) {
  78874. $this->_packageInfo['filelist'][$file] =
  78875. array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
  78876. } else {
  78877. $this->_packageInfo['filelist'][$file] = $atts['attribs'];
  78878. }
  78879. }
  78880. /**
  78881. * Retrieve the contents tag
  78882. */
  78883. function getContents()
  78884. {
  78885. if (isset($this->_packageInfo['contents'])) {
  78886. return $this->_packageInfo['contents'];
  78887. }
  78888. return false;
  78889. }
  78890. /**
  78891. * @param string full path to file
  78892. * @param string attribute name
  78893. * @param string attribute value
  78894. * @param int risky but fast - use this to choose a file based on its position in the list
  78895. * of files. Index is zero-based like PHP arrays.
  78896. * @return bool success of operation
  78897. */
  78898. function setFileAttribute($filename, $attr, $value, $index = false)
  78899. {
  78900. $this->_isValid = 0;
  78901. if (in_array($attr, array('role', 'name', 'baseinstalldir'))) {
  78902. $this->_filesValid = false;
  78903. }
  78904. if ($index !== false &&
  78905. isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) {
  78906. $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value;
  78907. return true;
  78908. }
  78909. if (!isset($this->_packageInfo['contents']['dir']['file'])) {
  78910. return false;
  78911. }
  78912. $files = $this->_packageInfo['contents']['dir']['file'];
  78913. if (!isset($files[0])) {
  78914. $files = array($files);
  78915. $ind = false;
  78916. } else {
  78917. $ind = true;
  78918. }
  78919. foreach ($files as $i => $file) {
  78920. if (isset($file['attribs'])) {
  78921. if ($file['attribs']['name'] == $filename) {
  78922. if ($ind) {
  78923. $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value;
  78924. } else {
  78925. $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value;
  78926. }
  78927. return true;
  78928. }
  78929. }
  78930. }
  78931. return false;
  78932. }
  78933. function setDirtree($path)
  78934. {
  78935. if (!isset($this->_packageInfo['dirtree'])) {
  78936. $this->_packageInfo['dirtree'] = array();
  78937. }
  78938. $this->_packageInfo['dirtree'][$path] = true;
  78939. }
  78940. function getDirtree()
  78941. {
  78942. if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
  78943. return $this->_packageInfo['dirtree'];
  78944. }
  78945. return false;
  78946. }
  78947. function resetDirtree()
  78948. {
  78949. unset($this->_packageInfo['dirtree']);
  78950. }
  78951. /**
  78952. * Determines whether this package claims it is compatible with the version of
  78953. * the package that has a recommended version dependency
  78954. * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package
  78955. * @return boolean
  78956. */
  78957. function isCompatible($pf)
  78958. {
  78959. if (!isset($this->_packageInfo['compatible'])) {
  78960. return false;
  78961. }
  78962. if (!isset($this->_packageInfo['channel'])) {
  78963. return false;
  78964. }
  78965. $me = $pf->getVersion();
  78966. $compatible = $this->_packageInfo['compatible'];
  78967. if (!isset($compatible[0])) {
  78968. $compatible = array($compatible);
  78969. }
  78970. $found = false;
  78971. foreach ($compatible as $info) {
  78972. if (strtolower($info['name']) == strtolower($pf->getPackage())) {
  78973. if (strtolower($info['channel']) == strtolower($pf->getChannel())) {
  78974. $found = true;
  78975. break;
  78976. }
  78977. }
  78978. }
  78979. if (!$found) {
  78980. return false;
  78981. }
  78982. if (isset($info['exclude'])) {
  78983. if (!isset($info['exclude'][0])) {
  78984. $info['exclude'] = array($info['exclude']);
  78985. }
  78986. foreach ($info['exclude'] as $exclude) {
  78987. if (version_compare($me, $exclude, '==')) {
  78988. return false;
  78989. }
  78990. }
  78991. }
  78992. if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) {
  78993. return true;
  78994. }
  78995. return false;
  78996. }
  78997. /**
  78998. * @return array|false
  78999. */
  79000. function getCompatible()
  79001. {
  79002. if (isset($this->_packageInfo['compatible'])) {
  79003. return $this->_packageInfo['compatible'];
  79004. }
  79005. return false;
  79006. }
  79007. function getDependencies()
  79008. {
  79009. if (isset($this->_packageInfo['dependencies'])) {
  79010. return $this->_packageInfo['dependencies'];
  79011. }
  79012. return false;
  79013. }
  79014. function isSubpackageOf($p)
  79015. {
  79016. return $p->isSubpackage($this);
  79017. }
  79018. /**
  79019. * Determines whether the passed in package is a subpackage of this package.
  79020. *
  79021. * No version checking is done, only name verification.
  79022. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  79023. * @return bool
  79024. */
  79025. function isSubpackage($p)
  79026. {
  79027. $sub = array();
  79028. if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) {
  79029. $sub = $this->_packageInfo['dependencies']['required']['subpackage'];
  79030. if (!isset($sub[0])) {
  79031. $sub = array($sub);
  79032. }
  79033. }
  79034. if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) {
  79035. $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage'];
  79036. if (!isset($sub1[0])) {
  79037. $sub1 = array($sub1);
  79038. }
  79039. $sub = array_merge($sub, $sub1);
  79040. }
  79041. if (isset($this->_packageInfo['dependencies']['group'])) {
  79042. $group = $this->_packageInfo['dependencies']['group'];
  79043. if (!isset($group[0])) {
  79044. $group = array($group);
  79045. }
  79046. foreach ($group as $deps) {
  79047. if (isset($deps['subpackage'])) {
  79048. $sub2 = $deps['subpackage'];
  79049. if (!isset($sub2[0])) {
  79050. $sub2 = array($sub2);
  79051. }
  79052. $sub = array_merge($sub, $sub2);
  79053. }
  79054. }
  79055. }
  79056. foreach ($sub as $dep) {
  79057. if (strtolower($dep['name']) == strtolower($p->getPackage())) {
  79058. if (isset($dep['channel'])) {
  79059. if (strtolower($dep['channel']) == strtolower($p->getChannel())) {
  79060. return true;
  79061. }
  79062. } else {
  79063. if ($dep['uri'] == $p->getURI()) {
  79064. return true;
  79065. }
  79066. }
  79067. }
  79068. }
  79069. return false;
  79070. }
  79071. function dependsOn($package, $channel)
  79072. {
  79073. if (!($deps = $this->getDependencies())) {
  79074. return false;
  79075. }
  79076. foreach (array('package', 'subpackage') as $type) {
  79077. foreach (array('required', 'optional') as $needed) {
  79078. if (isset($deps[$needed][$type])) {
  79079. if (!isset($deps[$needed][$type][0])) {
  79080. $deps[$needed][$type] = array($deps[$needed][$type]);
  79081. }
  79082. foreach ($deps[$needed][$type] as $dep) {
  79083. $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
  79084. if (strtolower($dep['name']) == strtolower($package) &&
  79085. $depchannel == $channel) {
  79086. return true;
  79087. }
  79088. }
  79089. }
  79090. }
  79091. if (isset($deps['group'])) {
  79092. if (!isset($deps['group'][0])) {
  79093. $dep['group'] = array($deps['group']);
  79094. }
  79095. foreach ($deps['group'] as $group) {
  79096. if (isset($group[$type])) {
  79097. if (!is_array($group[$type])) {
  79098. $group[$type] = array($group[$type]);
  79099. }
  79100. foreach ($group[$type] as $dep) {
  79101. $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
  79102. if (strtolower($dep['name']) == strtolower($package) &&
  79103. $depchannel == $channel) {
  79104. return true;
  79105. }
  79106. }
  79107. }
  79108. }
  79109. }
  79110. }
  79111. return false;
  79112. }
  79113. /**
  79114. * Get the contents of a dependency group
  79115. * @param string
  79116. * @return array|false
  79117. */
  79118. function getDependencyGroup($name)
  79119. {
  79120. $name = strtolower($name);
  79121. if (!isset($this->_packageInfo['dependencies']['group'])) {
  79122. return false;
  79123. }
  79124. $groups = $this->_packageInfo['dependencies']['group'];
  79125. if (!isset($groups[0])) {
  79126. $groups = array($groups);
  79127. }
  79128. foreach ($groups as $group) {
  79129. if (strtolower($group['attribs']['name']) == $name) {
  79130. return $group;
  79131. }
  79132. }
  79133. return false;
  79134. }
  79135. /**
  79136. * Retrieve a partial package.xml 1.0 representation of dependencies
  79137. *
  79138. * a very limited representation of dependencies is returned by this method.
  79139. * The <exclude> tag for excluding certain versions of a dependency is
  79140. * completely ignored. In addition, dependency groups are ignored, with the
  79141. * assumption that all dependencies in dependency groups are also listed in
  79142. * the optional group that work with all dependency groups
  79143. * @param boolean return package.xml 2.0 <dependencies> tag
  79144. * @return array|false
  79145. */
  79146. function getDeps($raw = false, $nopearinstaller = false)
  79147. {
  79148. if (isset($this->_packageInfo['dependencies'])) {
  79149. if ($raw) {
  79150. return $this->_packageInfo['dependencies'];
  79151. }
  79152. $ret = array();
  79153. $map = array(
  79154. 'php' => 'php',
  79155. 'package' => 'pkg',
  79156. 'subpackage' => 'pkg',
  79157. 'extension' => 'ext',
  79158. 'os' => 'os',
  79159. 'pearinstaller' => 'pkg',
  79160. );
  79161. foreach (array('required', 'optional') as $type) {
  79162. $optional = ($type == 'optional') ? 'yes' : 'no';
  79163. if (!isset($this->_packageInfo['dependencies'][$type])
  79164. || empty($this->_packageInfo['dependencies'][$type])) {
  79165. continue;
  79166. }
  79167. foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) {
  79168. if ($dtype == 'pearinstaller' && $nopearinstaller) {
  79169. continue;
  79170. }
  79171. if ((is_array($deps) && !isset($deps[0])) || !is_array($deps)) {
  79172. $deps = array($deps);
  79173. }
  79174. foreach ($deps as $dep) {
  79175. if (!isset($map[$dtype])) {
  79176. // no support for arch type
  79177. continue;
  79178. }
  79179. if ($dtype == 'pearinstaller') {
  79180. $dep['name'] = 'PEAR';
  79181. $dep['channel'] = 'pear.php.net';
  79182. }
  79183. $s = array('type' => $map[$dtype]);
  79184. if (isset($dep['channel'])) {
  79185. $s['channel'] = $dep['channel'];
  79186. }
  79187. if (isset($dep['uri'])) {
  79188. $s['uri'] = $dep['uri'];
  79189. }
  79190. if (isset($dep['name'])) {
  79191. $s['name'] = $dep['name'];
  79192. }
  79193. if (isset($dep['conflicts'])) {
  79194. $s['rel'] = 'not';
  79195. } else {
  79196. if (!isset($dep['min']) &&
  79197. !isset($dep['max'])) {
  79198. $s['rel'] = 'has';
  79199. $s['optional'] = $optional;
  79200. } elseif (isset($dep['min']) &&
  79201. isset($dep['max'])) {
  79202. $s['rel'] = 'ge';
  79203. $s1 = $s;
  79204. $s1['rel'] = 'le';
  79205. $s['version'] = $dep['min'];
  79206. $s1['version'] = $dep['max'];
  79207. if (isset($dep['channel'])) {
  79208. $s1['channel'] = $dep['channel'];
  79209. }
  79210. if ($dtype != 'php') {
  79211. $s['name'] = $dep['name'];
  79212. $s1['name'] = $dep['name'];
  79213. }
  79214. $s['optional'] = $optional;
  79215. $s1['optional'] = $optional;
  79216. $ret[] = $s1;
  79217. } elseif (isset($dep['min'])) {
  79218. if (isset($dep['exclude']) &&
  79219. $dep['exclude'] == $dep['min']) {
  79220. $s['rel'] = 'gt';
  79221. } else {
  79222. $s['rel'] = 'ge';
  79223. }
  79224. $s['version'] = $dep['min'];
  79225. $s['optional'] = $optional;
  79226. if ($dtype != 'php') {
  79227. $s['name'] = $dep['name'];
  79228. }
  79229. } elseif (isset($dep['max'])) {
  79230. if (isset($dep['exclude']) &&
  79231. $dep['exclude'] == $dep['max']) {
  79232. $s['rel'] = 'lt';
  79233. } else {
  79234. $s['rel'] = 'le';
  79235. }
  79236. $s['version'] = $dep['max'];
  79237. $s['optional'] = $optional;
  79238. if ($dtype != 'php') {
  79239. $s['name'] = $dep['name'];
  79240. }
  79241. }
  79242. }
  79243. $ret[] = $s;
  79244. }
  79245. }
  79246. }
  79247. if (count($ret)) {
  79248. return $ret;
  79249. }
  79250. }
  79251. return false;
  79252. }
  79253. /**
  79254. * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false
  79255. */
  79256. function getPackageType()
  79257. {
  79258. if (isset($this->_packageInfo['phprelease'])) {
  79259. return 'php';
  79260. }
  79261. if (isset($this->_packageInfo['extsrcrelease'])) {
  79262. return 'extsrc';
  79263. }
  79264. if (isset($this->_packageInfo['extbinrelease'])) {
  79265. return 'extbin';
  79266. }
  79267. if (isset($this->_packageInfo['zendextsrcrelease'])) {
  79268. return 'zendextsrc';
  79269. }
  79270. if (isset($this->_packageInfo['zendextbinrelease'])) {
  79271. return 'zendextbin';
  79272. }
  79273. if (isset($this->_packageInfo['bundle'])) {
  79274. return 'bundle';
  79275. }
  79276. return false;
  79277. }
  79278. /**
  79279. * @return array|false
  79280. */
  79281. function getReleases()
  79282. {
  79283. $type = $this->getPackageType();
  79284. if ($type != 'bundle') {
  79285. $type .= 'release';
  79286. }
  79287. if ($this->getPackageType() && isset($this->_packageInfo[$type])) {
  79288. return $this->_packageInfo[$type];
  79289. }
  79290. return false;
  79291. }
  79292. /**
  79293. * @return array
  79294. */
  79295. function getChangelog()
  79296. {
  79297. if (isset($this->_packageInfo['changelog'])) {
  79298. return $this->_packageInfo['changelog'];
  79299. }
  79300. return false;
  79301. }
  79302. function hasDeps()
  79303. {
  79304. return isset($this->_packageInfo['dependencies']);
  79305. }
  79306. function getPackagexmlVersion()
  79307. {
  79308. if (isset($this->_packageInfo['zendextsrcrelease'])) {
  79309. return '2.1';
  79310. }
  79311. if (isset($this->_packageInfo['zendextbinrelease'])) {
  79312. return '2.1';
  79313. }
  79314. return '2.0';
  79315. }
  79316. /**
  79317. * @return array|false
  79318. */
  79319. function getSourcePackage()
  79320. {
  79321. if (isset($this->_packageInfo['extbinrelease']) ||
  79322. isset($this->_packageInfo['zendextbinrelease'])) {
  79323. return array('channel' => $this->_packageInfo['srcchannel'],
  79324. 'package' => $this->_packageInfo['srcpackage']);
  79325. }
  79326. return false;
  79327. }
  79328. function getBundledPackages()
  79329. {
  79330. if (isset($this->_packageInfo['bundle'])) {
  79331. return $this->_packageInfo['contents']['bundledpackage'];
  79332. }
  79333. return false;
  79334. }
  79335. function getLastModified()
  79336. {
  79337. if (isset($this->_packageInfo['_lastmodified'])) {
  79338. return $this->_packageInfo['_lastmodified'];
  79339. }
  79340. return false;
  79341. }
  79342. /**
  79343. * Get the contents of a file listed within the package.xml
  79344. * @param string
  79345. * @return string
  79346. */
  79347. function getFileContents($file)
  79348. {
  79349. if ($this->_archiveFile == $this->_packageFile) { // unpacked
  79350. $dir = dirname($this->_packageFile);
  79351. $file = $dir . DIRECTORY_SEPARATOR . $file;
  79352. $file = str_replace(array('/', '\\'),
  79353. array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
  79354. if (file_exists($file) && is_readable($file)) {
  79355. return implode('', file($file));
  79356. }
  79357. } else { // tgz
  79358. $tar = new Archive_Tar($this->_archiveFile);
  79359. $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  79360. if ($file != 'package.xml' && $file != 'package2.xml') {
  79361. $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
  79362. }
  79363. $file = $tar->extractInString($file);
  79364. $tar->popErrorHandling();
  79365. if (PEAR::isError($file)) {
  79366. return PEAR::raiseError("Cannot locate file '$file' in archive");
  79367. }
  79368. return $file;
  79369. }
  79370. }
  79371. function &getRW()
  79372. {
  79373. if (!class_exists('PEAR_PackageFile_v2_rw')) {
  79374. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/rw.php';
  79375. }
  79376. $a = new PEAR_PackageFile_v2_rw;
  79377. foreach (get_object_vars($this) as $name => $unused) {
  79378. if (!isset($this->$name)) {
  79379. continue;
  79380. }
  79381. if ($name == '_config' || $name == '_logger'|| $name == '_registry' ||
  79382. $name == '_stack') {
  79383. $a->$name = &$this->$name;
  79384. } else {
  79385. $a->$name = $this->$name;
  79386. }
  79387. }
  79388. return $a;
  79389. }
  79390. function &getDefaultGenerator()
  79391. {
  79392. if (!class_exists('PEAR_PackageFile_Generator_v2')) {
  79393. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/Generator/v2.php';
  79394. }
  79395. $a = new PEAR_PackageFile_Generator_v2($this);
  79396. return $a;
  79397. }
  79398. function analyzeSourceCode($file, $string = false)
  79399. {
  79400. if (!isset($this->_v2Validator) ||
  79401. !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
  79402. if (!class_exists('PEAR_PackageFile_v2_Validator')) {
  79403. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/Validator.php';
  79404. }
  79405. $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
  79406. }
  79407. return $this->_v2Validator->analyzeSourceCode($file, $string);
  79408. }
  79409. function validate($state = PEAR_VALIDATE_NORMAL)
  79410. {
  79411. if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
  79412. return false;
  79413. }
  79414. if (!isset($this->_v2Validator) ||
  79415. !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
  79416. if (!class_exists('PEAR_PackageFile_v2_Validator')) {
  79417. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2/Validator.php';
  79418. }
  79419. $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
  79420. }
  79421. if (isset($this->_packageInfo['xsdversion'])) {
  79422. unset($this->_packageInfo['xsdversion']);
  79423. }
  79424. return $this->_v2Validator->validate($this, $state);
  79425. }
  79426. function getTasksNs()
  79427. {
  79428. if (!isset($this->_tasksNs)) {
  79429. if (isset($this->_packageInfo['attribs'])) {
  79430. foreach ($this->_packageInfo['attribs'] as $name => $value) {
  79431. if ($value == 'http://pear.php.net/dtd/tasks-1.0') {
  79432. $this->_tasksNs = str_replace('xmlns:', '', $name);
  79433. break;
  79434. }
  79435. }
  79436. }
  79437. }
  79438. return $this->_tasksNs;
  79439. }
  79440. /**
  79441. * Determine whether a task name is a valid task. Custom tasks may be defined
  79442. * using subdirectories by putting a "-" in the name, as in <tasks:mycustom-task>
  79443. *
  79444. * Note that this method will auto-load the task class file and test for the existence
  79445. * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class
  79446. * PEAR_Task_mycustom_task
  79447. * @param string
  79448. * @return boolean
  79449. */
  79450. function getTask($task)
  79451. {
  79452. $this->getTasksNs();
  79453. // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace
  79454. $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task);
  79455. $taskfile = str_replace(' ', '/', ucwords($task));
  79456. $task = str_replace(array(' ', '/'), '_', ucwords($task));
  79457. if (class_exists("PEAR_Task_$task")) {
  79458. return "PEAR_Task_$task";
  79459. }
  79460. $fp = @fopen("phar://go-pear.phar/PEAR/Task/$taskfile.php", 'r', true);
  79461. if ($fp) {
  79462. fclose($fp);
  79463. require_once 'phar://go-pear.phar/' . "PEAR/Task/$taskfile.php";
  79464. return "PEAR_Task_$task";
  79465. }
  79466. return false;
  79467. }
  79468. /**
  79469. * Key-friendly array_splice
  79470. * @param tagname to splice a value in before
  79471. * @param mixed the value to splice in
  79472. * @param string the new tag name
  79473. */
  79474. function _ksplice($array, $key, $value, $newkey)
  79475. {
  79476. $offset = array_search($key, array_keys($array));
  79477. $after = array_slice($array, $offset);
  79478. $before = array_slice($array, 0, $offset);
  79479. $before[$newkey] = $value;
  79480. return array_merge($before, $after);
  79481. }
  79482. /**
  79483. * @param array a list of possible keys, in the order they may occur
  79484. * @param mixed contents of the new package.xml tag
  79485. * @param string tag name
  79486. * @access private
  79487. */
  79488. function _insertBefore($array, $keys, $contents, $newkey)
  79489. {
  79490. foreach ($keys as $key) {
  79491. if (isset($array[$key])) {
  79492. return $array = $this->_ksplice($array, $key, $contents, $newkey);
  79493. }
  79494. }
  79495. $array[$newkey] = $contents;
  79496. return $array;
  79497. }
  79498. /**
  79499. * @param subsection of {@link $_packageInfo}
  79500. * @param array|string tag contents
  79501. * @param array format:
  79502. * <pre>
  79503. * array(
  79504. * tagname => array(list of tag names that follow this one),
  79505. * childtagname => array(list of child tag names that follow this one),
  79506. * )
  79507. * </pre>
  79508. *
  79509. * This allows construction of nested tags
  79510. * @access private
  79511. */
  79512. function _mergeTag($manip, $contents, $order)
  79513. {
  79514. if (count($order)) {
  79515. foreach ($order as $tag => $curorder) {
  79516. if (!isset($manip[$tag])) {
  79517. // ensure that the tag is set up
  79518. $manip = $this->_insertBefore($manip, $curorder, array(), $tag);
  79519. }
  79520. if (count($order) > 1) {
  79521. $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1));
  79522. return $manip;
  79523. }
  79524. }
  79525. } else {
  79526. return $manip;
  79527. }
  79528. if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) {
  79529. $manip[$tag][] = $contents;
  79530. } else {
  79531. if (is_array($manip[$tag]) && !count($manip[$tag])) {
  79532. $manip[$tag] = $contents;
  79533. } else {
  79534. $manip[$tag] = array($manip[$tag]);
  79535. $manip[$tag][] = $contents;
  79536. }
  79537. }
  79538. return $manip;
  79539. }
  79540. }
  79541. ?>
  79542. <?php
  79543. /**
  79544. * PEAR_PackageFile_v2, package.xml version 2.0, read/write version
  79545. *
  79546. * PHP versions 4 and 5
  79547. *
  79548. * @category pear
  79549. * @package PEAR
  79550. * @author Greg Beaver <cellog@php.net>
  79551. * @copyright 1997-2009 The Authors
  79552. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  79553. * @link http://pear.php.net/package/PEAR
  79554. * @since File available since Release 1.4.0a8
  79555. */
  79556. /**
  79557. * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its
  79558. * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller
  79559. * @category pear
  79560. * @package PEAR
  79561. * @author Greg Beaver <cellog@php.net>
  79562. * @copyright 1997-2009 The Authors
  79563. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  79564. * @version Release: 1.10.10
  79565. * @link http://pear.php.net/package/PEAR
  79566. * @since Class available since Release 1.4.0a8
  79567. * @access private
  79568. */
  79569. class PEAR_PackageFile_v2_Validator
  79570. {
  79571. /**
  79572. * @var array
  79573. */
  79574. var $_packageInfo;
  79575. /**
  79576. * @var PEAR_PackageFile_v2
  79577. */
  79578. var $_pf;
  79579. /**
  79580. * @var PEAR_ErrorStack
  79581. */
  79582. var $_stack;
  79583. /**
  79584. * @var int
  79585. */
  79586. var $_isValid = 0;
  79587. /**
  79588. * @var int
  79589. */
  79590. var $_filesValid = 0;
  79591. /**
  79592. * @var int
  79593. */
  79594. var $_curState = 0;
  79595. /**
  79596. * @param PEAR_PackageFile_v2
  79597. * @param int
  79598. */
  79599. function validate(&$pf, $state = PEAR_VALIDATE_NORMAL)
  79600. {
  79601. $this->_pf = &$pf;
  79602. $this->_curState = $state;
  79603. $this->_packageInfo = $this->_pf->getArray();
  79604. $this->_isValid = $this->_pf->_isValid;
  79605. $this->_filesValid = $this->_pf->_filesValid;
  79606. $this->_stack = &$pf->_stack;
  79607. $this->_stack->getErrors(true);
  79608. if (($this->_isValid & $state) == $state) {
  79609. return true;
  79610. }
  79611. if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
  79612. return false;
  79613. }
  79614. if (!isset($this->_packageInfo['attribs']['version']) ||
  79615. ($this->_packageInfo['attribs']['version'] != '2.0' &&
  79616. $this->_packageInfo['attribs']['version'] != '2.1')
  79617. ) {
  79618. $this->_noPackageVersion();
  79619. }
  79620. $structure =
  79621. array(
  79622. 'name',
  79623. 'channel|uri',
  79624. '*extends', // can't be multiple, but this works fine
  79625. 'summary',
  79626. 'description',
  79627. '+lead', // these all need content checks
  79628. '*developer',
  79629. '*contributor',
  79630. '*helper',
  79631. 'date',
  79632. '*time',
  79633. 'version',
  79634. 'stability',
  79635. 'license->?uri->?filesource',
  79636. 'notes',
  79637. 'contents', //special validation needed
  79638. '*compatible',
  79639. 'dependencies', //special validation needed
  79640. '*usesrole',
  79641. '*usestask', // reserve these for 1.4.0a1 to implement
  79642. // this will allow a package.xml to gracefully say it
  79643. // needs a certain package installed in order to implement a role or task
  79644. '*providesextension',
  79645. '*srcpackage|*srcuri',
  79646. '+phprelease|+extsrcrelease|+extbinrelease|' .
  79647. '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed
  79648. '*changelog',
  79649. );
  79650. $test = $this->_packageInfo;
  79651. if (isset($test['dependencies']) &&
  79652. isset($test['dependencies']['required']) &&
  79653. isset($test['dependencies']['required']['pearinstaller']) &&
  79654. isset($test['dependencies']['required']['pearinstaller']['min']) &&
  79655. '1.10.10' != '@package' . '_version@' &&
  79656. version_compare('1.10.10',
  79657. $test['dependencies']['required']['pearinstaller']['min'], '<')
  79658. ) {
  79659. $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']);
  79660. return false;
  79661. }
  79662. // ignore post-installation array fields
  79663. if (array_key_exists('filelist', $test)) {
  79664. unset($test['filelist']);
  79665. }
  79666. if (array_key_exists('_lastmodified', $test)) {
  79667. unset($test['_lastmodified']);
  79668. }
  79669. if (array_key_exists('#binarypackage', $test)) {
  79670. unset($test['#binarypackage']);
  79671. }
  79672. if (array_key_exists('old', $test)) {
  79673. unset($test['old']);
  79674. }
  79675. if (array_key_exists('_lastversion', $test)) {
  79676. unset($test['_lastversion']);
  79677. }
  79678. if (!$this->_stupidSchemaValidate($structure, $test, '<package>')) {
  79679. return false;
  79680. }
  79681. if (empty($this->_packageInfo['name'])) {
  79682. $this->_tagCannotBeEmpty('name');
  79683. }
  79684. $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel';
  79685. if (empty($this->_packageInfo[$test])) {
  79686. $this->_tagCannotBeEmpty($test);
  79687. }
  79688. if (is_array($this->_packageInfo['license']) &&
  79689. (!isset($this->_packageInfo['license']['_content']) ||
  79690. empty($this->_packageInfo['license']['_content']))) {
  79691. $this->_tagCannotBeEmpty('license');
  79692. } elseif (empty($this->_packageInfo['license'])) {
  79693. $this->_tagCannotBeEmpty('license');
  79694. }
  79695. if (empty($this->_packageInfo['summary'])) {
  79696. $this->_tagCannotBeEmpty('summary');
  79697. }
  79698. if (empty($this->_packageInfo['description'])) {
  79699. $this->_tagCannotBeEmpty('description');
  79700. }
  79701. if (empty($this->_packageInfo['date'])) {
  79702. $this->_tagCannotBeEmpty('date');
  79703. }
  79704. if (empty($this->_packageInfo['notes'])) {
  79705. $this->_tagCannotBeEmpty('notes');
  79706. }
  79707. if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) {
  79708. $this->_tagCannotBeEmpty('time');
  79709. }
  79710. if (isset($this->_packageInfo['dependencies'])) {
  79711. $this->_validateDependencies();
  79712. }
  79713. if (isset($this->_packageInfo['compatible'])) {
  79714. $this->_validateCompatible();
  79715. }
  79716. if (!isset($this->_packageInfo['bundle'])) {
  79717. if (empty($this->_packageInfo['contents'])) {
  79718. $this->_tagCannotBeEmpty('contents');
  79719. }
  79720. if (!isset($this->_packageInfo['contents']['dir'])) {
  79721. $this->_filelistMustContainDir('contents');
  79722. return false;
  79723. }
  79724. if (isset($this->_packageInfo['contents']['file'])) {
  79725. $this->_filelistCannotContainFile('contents');
  79726. return false;
  79727. }
  79728. }
  79729. $this->_validateMaintainers();
  79730. $this->_validateStabilityVersion();
  79731. $fail = false;
  79732. if (array_key_exists('usesrole', $this->_packageInfo)) {
  79733. $roles = $this->_packageInfo['usesrole'];
  79734. if (!is_array($roles) || !isset($roles[0])) {
  79735. $roles = array($roles);
  79736. }
  79737. foreach ($roles as $role) {
  79738. if (!isset($role['role'])) {
  79739. $this->_usesroletaskMustHaveRoleTask('usesrole', 'role');
  79740. $fail = true;
  79741. } else {
  79742. if (!isset($role['channel'])) {
  79743. if (!isset($role['uri'])) {
  79744. $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole');
  79745. $fail = true;
  79746. }
  79747. } elseif (!isset($role['package'])) {
  79748. $this->_usesroletaskMustHavePackage($role['role'], 'usesrole');
  79749. $fail = true;
  79750. }
  79751. }
  79752. }
  79753. }
  79754. if (array_key_exists('usestask', $this->_packageInfo)) {
  79755. $roles = $this->_packageInfo['usestask'];
  79756. if (!is_array($roles) || !isset($roles[0])) {
  79757. $roles = array($roles);
  79758. }
  79759. foreach ($roles as $role) {
  79760. if (!isset($role['task'])) {
  79761. $this->_usesroletaskMustHaveRoleTask('usestask', 'task');
  79762. $fail = true;
  79763. } else {
  79764. if (!isset($role['channel'])) {
  79765. if (!isset($role['uri'])) {
  79766. $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask');
  79767. $fail = true;
  79768. }
  79769. } elseif (!isset($role['package'])) {
  79770. $this->_usesroletaskMustHavePackage($role['task'], 'usestask');
  79771. $fail = true;
  79772. }
  79773. }
  79774. }
  79775. }
  79776. if ($fail) {
  79777. return false;
  79778. }
  79779. $list = $this->_packageInfo['contents'];
  79780. if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) {
  79781. $this->_multipleToplevelDirNotAllowed();
  79782. return $this->_isValid = 0;
  79783. }
  79784. $this->_validateFilelist();
  79785. $this->_validateRelease();
  79786. if (!$this->_stack->hasErrors()) {
  79787. $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true);
  79788. if (PEAR::isError($chan)) {
  79789. $this->_unknownChannel($this->_pf->getChannel());
  79790. } else {
  79791. $valpack = $chan->getValidationPackage();
  79792. // for channel validator packages, always use the default PEAR validator.
  79793. // otherwise, they can't be installed or packaged
  79794. $validator = $chan->getValidationObject($this->_pf->getPackage());
  79795. if (!$validator) {
  79796. $this->_stack->push(__FUNCTION__, 'error',
  79797. array('channel' => $chan->getName(),
  79798. 'package' => $this->_pf->getPackage(),
  79799. 'name' => $valpack['_content'],
  79800. 'version' => $valpack['attribs']['version']),
  79801. 'package "%channel%/%package%" cannot be properly validated without ' .
  79802. 'validation package "%channel%/%name%-%version%"');
  79803. return $this->_isValid = 0;
  79804. }
  79805. $validator->setPackageFile($this->_pf);
  79806. $validator->validate($state);
  79807. $failures = $validator->getFailures();
  79808. foreach ($failures['errors'] as $error) {
  79809. $this->_stack->push(__FUNCTION__, 'error', $error,
  79810. 'Channel validator error: field "%field%" - %reason%');
  79811. }
  79812. foreach ($failures['warnings'] as $warning) {
  79813. $this->_stack->push(__FUNCTION__, 'warning', $warning,
  79814. 'Channel validator warning: field "%field%" - %reason%');
  79815. }
  79816. }
  79817. }
  79818. $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error');
  79819. if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) {
  79820. if ($this->_pf->getPackageType() == 'bundle') {
  79821. if ($this->_analyzeBundledPackages()) {
  79822. $this->_filesValid = $this->_pf->_filesValid = true;
  79823. } else {
  79824. $this->_pf->_isValid = $this->_isValid = 0;
  79825. }
  79826. } else {
  79827. if (!$this->_analyzePhpFiles()) {
  79828. $this->_pf->_isValid = $this->_isValid = 0;
  79829. } else {
  79830. $this->_filesValid = $this->_pf->_filesValid = true;
  79831. }
  79832. }
  79833. }
  79834. if ($this->_isValid) {
  79835. return $this->_pf->_isValid = $this->_isValid = $state;
  79836. }
  79837. return $this->_pf->_isValid = $this->_isValid = 0;
  79838. }
  79839. function _stupidSchemaValidate($structure, $xml, $root)
  79840. {
  79841. if (!is_array($xml)) {
  79842. $xml = array();
  79843. }
  79844. $keys = array_keys($xml);
  79845. reset($keys);
  79846. $key = current($keys);
  79847. while ($key == 'attribs' || $key == '_contents') {
  79848. $key = next($keys);
  79849. }
  79850. $unfoundtags = $optionaltags = array();
  79851. $ret = true;
  79852. $mismatch = false;
  79853. foreach ($structure as $struc) {
  79854. if ($key) {
  79855. $tag = $xml[$key];
  79856. }
  79857. $test = $this->_processStructure($struc);
  79858. if (isset($test['choices'])) {
  79859. $loose = true;
  79860. foreach ($test['choices'] as $choice) {
  79861. if ($key == $choice['tag']) {
  79862. $key = next($keys);
  79863. while ($key == 'attribs' || $key == '_contents') {
  79864. $key = next($keys);
  79865. }
  79866. $unfoundtags = $optionaltags = array();
  79867. $mismatch = false;
  79868. if ($key && $key != $choice['tag'] && isset($choice['multiple'])) {
  79869. $unfoundtags[] = $choice['tag'];
  79870. $optionaltags[] = $choice['tag'];
  79871. if ($key) {
  79872. $mismatch = true;
  79873. }
  79874. }
  79875. $ret &= $this->_processAttribs($choice, $tag, $root);
  79876. continue 2;
  79877. } else {
  79878. $unfoundtags[] = $choice['tag'];
  79879. $mismatch = true;
  79880. }
  79881. if (!isset($choice['multiple']) || $choice['multiple'] != '*') {
  79882. $loose = false;
  79883. } else {
  79884. $optionaltags[] = $choice['tag'];
  79885. }
  79886. }
  79887. if (!$loose) {
  79888. $this->_invalidTagOrder($unfoundtags, $key, $root);
  79889. return false;
  79890. }
  79891. } else {
  79892. if ($key != $test['tag']) {
  79893. if (isset($test['multiple']) && $test['multiple'] != '*') {
  79894. $unfoundtags[] = $test['tag'];
  79895. $this->_invalidTagOrder($unfoundtags, $key, $root);
  79896. return false;
  79897. } else {
  79898. if ($key) {
  79899. $mismatch = true;
  79900. }
  79901. $unfoundtags[] = $test['tag'];
  79902. $optionaltags[] = $test['tag'];
  79903. }
  79904. if (!isset($test['multiple'])) {
  79905. $this->_invalidTagOrder($unfoundtags, $key, $root);
  79906. return false;
  79907. }
  79908. continue;
  79909. } else {
  79910. $unfoundtags = $optionaltags = array();
  79911. $mismatch = false;
  79912. }
  79913. $key = next($keys);
  79914. while ($key == 'attribs' || $key == '_contents') {
  79915. $key = next($keys);
  79916. }
  79917. if ($key && $key != $test['tag'] && isset($test['multiple'])) {
  79918. $unfoundtags[] = $test['tag'];
  79919. $optionaltags[] = $test['tag'];
  79920. $mismatch = true;
  79921. }
  79922. $ret &= $this->_processAttribs($test, $tag, $root);
  79923. continue;
  79924. }
  79925. }
  79926. if (!$mismatch && count($optionaltags)) {
  79927. // don't error out on any optional tags
  79928. $unfoundtags = array_diff($unfoundtags, $optionaltags);
  79929. }
  79930. if (count($unfoundtags)) {
  79931. $this->_invalidTagOrder($unfoundtags, $key, $root);
  79932. } elseif ($key) {
  79933. // unknown tags
  79934. $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
  79935. while ($key = next($keys)) {
  79936. $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
  79937. }
  79938. }
  79939. return $ret;
  79940. }
  79941. function _processAttribs($choice, $tag, $context)
  79942. {
  79943. if (isset($choice['attribs'])) {
  79944. if (!is_array($tag)) {
  79945. $tag = array($tag);
  79946. }
  79947. $tags = $tag;
  79948. if (!isset($tags[0])) {
  79949. $tags = array($tags);
  79950. }
  79951. $ret = true;
  79952. foreach ($tags as $i => $tag) {
  79953. if (!is_array($tag) || !isset($tag['attribs'])) {
  79954. foreach ($choice['attribs'] as $attrib) {
  79955. if ($attrib[0] != '?') {
  79956. $ret &= $this->_tagHasNoAttribs($choice['tag'],
  79957. $context);
  79958. continue 2;
  79959. }
  79960. }
  79961. }
  79962. foreach ($choice['attribs'] as $attrib) {
  79963. if ($attrib[0] != '?') {
  79964. if (!isset($tag['attribs'][$attrib])) {
  79965. $ret &= $this->_tagMissingAttribute($choice['tag'],
  79966. $attrib, $context);
  79967. }
  79968. }
  79969. }
  79970. }
  79971. return $ret;
  79972. }
  79973. return true;
  79974. }
  79975. function _processStructure($key)
  79976. {
  79977. $ret = array();
  79978. if (count($pieces = explode('|', $key)) > 1) {
  79979. $ret['choices'] = array();
  79980. foreach ($pieces as $piece) {
  79981. $ret['choices'][] = $this->_processStructure($piece);
  79982. }
  79983. return $ret;
  79984. }
  79985. $multi = $key[0];
  79986. if ($multi == '+' || $multi == '*') {
  79987. $ret['multiple'] = $key[0];
  79988. $key = substr($key, 1);
  79989. }
  79990. if (count($attrs = explode('->', $key)) > 1) {
  79991. $ret['tag'] = array_shift($attrs);
  79992. $ret['attribs'] = $attrs;
  79993. } else {
  79994. $ret['tag'] = $key;
  79995. }
  79996. return $ret;
  79997. }
  79998. function _validateStabilityVersion()
  79999. {
  80000. $structure = array('release', 'api');
  80001. $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], '<version>');
  80002. $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '<stability>');
  80003. if ($a) {
  80004. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80005. $this->_packageInfo['version']['release'])) {
  80006. $this->_invalidVersion('release', $this->_packageInfo['version']['release']);
  80007. }
  80008. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80009. $this->_packageInfo['version']['api'])) {
  80010. $this->_invalidVersion('api', $this->_packageInfo['version']['api']);
  80011. }
  80012. if (!in_array($this->_packageInfo['stability']['release'],
  80013. array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) {
  80014. $this->_invalidState('release', $this->_packageInfo['stability']['release']);
  80015. }
  80016. if (!in_array($this->_packageInfo['stability']['api'],
  80017. array('devel', 'alpha', 'beta', 'stable'))) {
  80018. $this->_invalidState('api', $this->_packageInfo['stability']['api']);
  80019. }
  80020. }
  80021. }
  80022. function _validateMaintainers()
  80023. {
  80024. $structure =
  80025. array(
  80026. 'name',
  80027. 'user',
  80028. 'email',
  80029. 'active',
  80030. );
  80031. foreach (array('lead', 'developer', 'contributor', 'helper') as $type) {
  80032. if (!isset($this->_packageInfo[$type])) {
  80033. continue;
  80034. }
  80035. if (isset($this->_packageInfo[$type][0])) {
  80036. foreach ($this->_packageInfo[$type] as $lead) {
  80037. $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>');
  80038. }
  80039. } else {
  80040. $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type],
  80041. '<' . $type . '>');
  80042. }
  80043. }
  80044. }
  80045. function _validatePhpDep($dep, $installcondition = false)
  80046. {
  80047. $structure = array(
  80048. 'min',
  80049. '*max',
  80050. '*exclude',
  80051. );
  80052. $type = $installcondition ? '<installcondition><php>' : '<dependencies><required><php>';
  80053. $this->_stupidSchemaValidate($structure, $dep, $type);
  80054. if (isset($dep['min'])) {
  80055. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
  80056. $dep['min'])) {
  80057. $this->_invalidVersion($type . '<min>', $dep['min']);
  80058. }
  80059. }
  80060. if (isset($dep['max'])) {
  80061. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
  80062. $dep['max'])) {
  80063. $this->_invalidVersion($type . '<max>', $dep['max']);
  80064. }
  80065. }
  80066. if (isset($dep['exclude'])) {
  80067. if (!is_array($dep['exclude'])) {
  80068. $dep['exclude'] = array($dep['exclude']);
  80069. }
  80070. foreach ($dep['exclude'] as $exclude) {
  80071. if (!preg_match(
  80072. '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
  80073. $exclude)) {
  80074. $this->_invalidVersion($type . '<exclude>', $exclude);
  80075. }
  80076. }
  80077. }
  80078. }
  80079. function _validatePearinstallerDep($dep)
  80080. {
  80081. $structure = array(
  80082. 'min',
  80083. '*max',
  80084. '*recommended',
  80085. '*exclude',
  80086. );
  80087. $this->_stupidSchemaValidate($structure, $dep, '<dependencies><required><pearinstaller>');
  80088. if (isset($dep['min'])) {
  80089. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80090. $dep['min'])) {
  80091. $this->_invalidVersion('<dependencies><required><pearinstaller><min>',
  80092. $dep['min']);
  80093. }
  80094. }
  80095. if (isset($dep['max'])) {
  80096. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80097. $dep['max'])) {
  80098. $this->_invalidVersion('<dependencies><required><pearinstaller><max>',
  80099. $dep['max']);
  80100. }
  80101. }
  80102. if (isset($dep['recommended'])) {
  80103. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80104. $dep['recommended'])) {
  80105. $this->_invalidVersion('<dependencies><required><pearinstaller><recommended>',
  80106. $dep['recommended']);
  80107. }
  80108. }
  80109. if (isset($dep['exclude'])) {
  80110. if (!is_array($dep['exclude'])) {
  80111. $dep['exclude'] = array($dep['exclude']);
  80112. }
  80113. foreach ($dep['exclude'] as $exclude) {
  80114. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80115. $exclude)) {
  80116. $this->_invalidVersion('<dependencies><required><pearinstaller><exclude>',
  80117. $exclude);
  80118. }
  80119. }
  80120. }
  80121. }
  80122. function _validatePackageDep($dep, $group, $type = '<package>')
  80123. {
  80124. if (isset($dep['uri'])) {
  80125. if (isset($dep['conflicts'])) {
  80126. $structure = array(
  80127. 'name',
  80128. 'uri',
  80129. 'conflicts',
  80130. '*providesextension',
  80131. );
  80132. } else {
  80133. $structure = array(
  80134. 'name',
  80135. 'uri',
  80136. '*providesextension',
  80137. );
  80138. }
  80139. } else {
  80140. if (isset($dep['conflicts'])) {
  80141. $structure = array(
  80142. 'name',
  80143. 'channel',
  80144. '*min',
  80145. '*max',
  80146. '*exclude',
  80147. 'conflicts',
  80148. '*providesextension',
  80149. );
  80150. } else {
  80151. $structure = array(
  80152. 'name',
  80153. 'channel',
  80154. '*min',
  80155. '*max',
  80156. '*recommended',
  80157. '*exclude',
  80158. '*nodefault',
  80159. '*providesextension',
  80160. );
  80161. }
  80162. }
  80163. if (isset($dep['name'])) {
  80164. $type .= '<name>' . $dep['name'] . '</name>';
  80165. }
  80166. $this->_stupidSchemaValidate($structure, $dep, '<dependencies>' . $group . $type);
  80167. if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) ||
  80168. isset($dep['recommended']) || isset($dep['exclude']))) {
  80169. $this->_uriDepsCannotHaveVersioning('<dependencies>' . $group . $type);
  80170. }
  80171. if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') {
  80172. $this->_DepchannelCannotBeUri('<dependencies>' . $group . $type);
  80173. }
  80174. if (isset($dep['min'])) {
  80175. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80176. $dep['min'])) {
  80177. $this->_invalidVersion('<dependencies>' . $group . $type . '<min>', $dep['min']);
  80178. }
  80179. }
  80180. if (isset($dep['max'])) {
  80181. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80182. $dep['max'])) {
  80183. $this->_invalidVersion('<dependencies>' . $group . $type . '<max>', $dep['max']);
  80184. }
  80185. }
  80186. if (isset($dep['recommended'])) {
  80187. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80188. $dep['recommended'])) {
  80189. $this->_invalidVersion('<dependencies>' . $group . $type . '<recommended>',
  80190. $dep['recommended']);
  80191. }
  80192. }
  80193. if (isset($dep['exclude'])) {
  80194. if (!is_array($dep['exclude'])) {
  80195. $dep['exclude'] = array($dep['exclude']);
  80196. }
  80197. foreach ($dep['exclude'] as $exclude) {
  80198. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80199. $exclude)) {
  80200. $this->_invalidVersion('<dependencies>' . $group . $type . '<exclude>',
  80201. $exclude);
  80202. }
  80203. }
  80204. }
  80205. }
  80206. function _validateSubpackageDep($dep, $group)
  80207. {
  80208. $this->_validatePackageDep($dep, $group, '<subpackage>');
  80209. if (isset($dep['providesextension'])) {
  80210. $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : '');
  80211. }
  80212. if (isset($dep['conflicts'])) {
  80213. $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : '');
  80214. }
  80215. }
  80216. function _validateExtensionDep($dep, $group = false, $installcondition = false)
  80217. {
  80218. if (isset($dep['conflicts'])) {
  80219. $structure = array(
  80220. 'name',
  80221. '*min',
  80222. '*max',
  80223. '*exclude',
  80224. 'conflicts',
  80225. );
  80226. } else {
  80227. $structure = array(
  80228. 'name',
  80229. '*min',
  80230. '*max',
  80231. '*recommended',
  80232. '*exclude',
  80233. );
  80234. }
  80235. if ($installcondition) {
  80236. $type = '<installcondition><extension>';
  80237. } else {
  80238. $type = '<dependencies>' . $group . '<extension>';
  80239. }
  80240. if (isset($dep['name'])) {
  80241. $type .= '<name>' . $dep['name'] . '</name>';
  80242. }
  80243. $this->_stupidSchemaValidate($structure, $dep, $type);
  80244. if (isset($dep['min'])) {
  80245. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80246. $dep['min'])) {
  80247. $this->_invalidVersion(substr($type, 1) . '<min', $dep['min']);
  80248. }
  80249. }
  80250. if (isset($dep['max'])) {
  80251. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80252. $dep['max'])) {
  80253. $this->_invalidVersion(substr($type, 1) . '<max', $dep['max']);
  80254. }
  80255. }
  80256. if (isset($dep['recommended'])) {
  80257. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80258. $dep['recommended'])) {
  80259. $this->_invalidVersion(substr($type, 1) . '<recommended', $dep['recommended']);
  80260. }
  80261. }
  80262. if (isset($dep['exclude'])) {
  80263. if (!is_array($dep['exclude'])) {
  80264. $dep['exclude'] = array($dep['exclude']);
  80265. }
  80266. foreach ($dep['exclude'] as $exclude) {
  80267. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80268. $exclude)) {
  80269. $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
  80270. }
  80271. }
  80272. }
  80273. }
  80274. function _validateOsDep($dep, $installcondition = false)
  80275. {
  80276. $structure = array(
  80277. 'name',
  80278. '*conflicts',
  80279. );
  80280. $type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>';
  80281. if ($this->_stupidSchemaValidate($structure, $dep, $type)) {
  80282. if ($dep['name'] == '*') {
  80283. if (array_key_exists('conflicts', $dep)) {
  80284. $this->_cannotConflictWithAllOs($type);
  80285. }
  80286. }
  80287. }
  80288. }
  80289. function _validateArchDep($dep, $installcondition = false)
  80290. {
  80291. $structure = array(
  80292. 'pattern',
  80293. '*conflicts',
  80294. );
  80295. $type = $installcondition ? '<installcondition><arch>' : '<dependencies><required><arch>';
  80296. $this->_stupidSchemaValidate($structure, $dep, $type);
  80297. }
  80298. function _validateInstallConditions($cond, $release)
  80299. {
  80300. $structure = array(
  80301. '*php',
  80302. '*extension',
  80303. '*os',
  80304. '*arch',
  80305. );
  80306. if (!$this->_stupidSchemaValidate($structure,
  80307. $cond, $release)) {
  80308. return false;
  80309. }
  80310. foreach (array('php', 'extension', 'os', 'arch') as $type) {
  80311. if (isset($cond[$type])) {
  80312. $iter = $cond[$type];
  80313. if (!is_array($iter) || !isset($iter[0])) {
  80314. $iter = array($iter);
  80315. }
  80316. foreach ($iter as $package) {
  80317. if ($type == 'extension') {
  80318. $this->{"_validate{$type}Dep"}($package, false, true);
  80319. } else {
  80320. $this->{"_validate{$type}Dep"}($package, true);
  80321. }
  80322. }
  80323. }
  80324. }
  80325. }
  80326. function _validateDependencies()
  80327. {
  80328. $structure = array(
  80329. 'required',
  80330. '*optional',
  80331. '*group->name->hint'
  80332. );
  80333. if (!$this->_stupidSchemaValidate($structure,
  80334. $this->_packageInfo['dependencies'], '<dependencies>')) {
  80335. return false;
  80336. }
  80337. foreach (array('required', 'optional') as $simpledep) {
  80338. if (isset($this->_packageInfo['dependencies'][$simpledep])) {
  80339. if ($simpledep == 'optional') {
  80340. $structure = array(
  80341. '*package',
  80342. '*subpackage',
  80343. '*extension',
  80344. );
  80345. } else {
  80346. $structure = array(
  80347. 'php',
  80348. 'pearinstaller',
  80349. '*package',
  80350. '*subpackage',
  80351. '*extension',
  80352. '*os',
  80353. '*arch',
  80354. );
  80355. }
  80356. if ($this->_stupidSchemaValidate($structure,
  80357. $this->_packageInfo['dependencies'][$simpledep],
  80358. "<dependencies><$simpledep>")) {
  80359. foreach (array('package', 'subpackage', 'extension') as $type) {
  80360. if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
  80361. $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
  80362. if (!isset($iter[0])) {
  80363. $iter = array($iter);
  80364. }
  80365. foreach ($iter as $package) {
  80366. if ($type != 'extension') {
  80367. if (isset($package['uri'])) {
  80368. if (isset($package['channel'])) {
  80369. $this->_UrlOrChannel($type,
  80370. $package['name']);
  80371. }
  80372. } else {
  80373. if (!isset($package['channel'])) {
  80374. $this->_NoChannel($type, $package['name']);
  80375. }
  80376. }
  80377. }
  80378. $this->{"_validate{$type}Dep"}($package, "<$simpledep>");
  80379. }
  80380. }
  80381. }
  80382. if ($simpledep == 'optional') {
  80383. continue;
  80384. }
  80385. foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) {
  80386. if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
  80387. $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
  80388. if (!isset($iter[0])) {
  80389. $iter = array($iter);
  80390. }
  80391. foreach ($iter as $package) {
  80392. $this->{"_validate{$type}Dep"}($package);
  80393. }
  80394. }
  80395. }
  80396. }
  80397. }
  80398. }
  80399. if (isset($this->_packageInfo['dependencies']['group'])) {
  80400. $groups = $this->_packageInfo['dependencies']['group'];
  80401. if (!isset($groups[0])) {
  80402. $groups = array($groups);
  80403. }
  80404. $structure = array(
  80405. '*package',
  80406. '*subpackage',
  80407. '*extension',
  80408. );
  80409. foreach ($groups as $group) {
  80410. if ($this->_stupidSchemaValidate($structure, $group, '<group>')) {
  80411. if (!PEAR_Validate::validGroupName($group['attribs']['name'])) {
  80412. $this->_invalidDepGroupName($group['attribs']['name']);
  80413. }
  80414. foreach (array('package', 'subpackage', 'extension') as $type) {
  80415. if (isset($group[$type])) {
  80416. $iter = $group[$type];
  80417. if (!isset($iter[0])) {
  80418. $iter = array($iter);
  80419. }
  80420. foreach ($iter as $package) {
  80421. if ($type != 'extension') {
  80422. if (isset($package['uri'])) {
  80423. if (isset($package['channel'])) {
  80424. $this->_UrlOrChannelGroup($type,
  80425. $package['name'],
  80426. $group['name']);
  80427. }
  80428. } else {
  80429. if (!isset($package['channel'])) {
  80430. $this->_NoChannelGroup($type,
  80431. $package['name'],
  80432. $group['name']);
  80433. }
  80434. }
  80435. }
  80436. $this->{"_validate{$type}Dep"}($package, '<group name="' .
  80437. $group['attribs']['name'] . '">');
  80438. }
  80439. }
  80440. }
  80441. }
  80442. }
  80443. }
  80444. }
  80445. function _validateCompatible()
  80446. {
  80447. $compat = $this->_packageInfo['compatible'];
  80448. if (!isset($compat[0])) {
  80449. $compat = array($compat);
  80450. }
  80451. $required = array('name', 'channel', 'min', 'max', '*exclude');
  80452. foreach ($compat as $package) {
  80453. $type = '<compatible>';
  80454. if (is_array($package) && array_key_exists('name', $package)) {
  80455. $type .= '<name>' . $package['name'] . '</name>';
  80456. }
  80457. $this->_stupidSchemaValidate($required, $package, $type);
  80458. if (is_array($package) && array_key_exists('min', $package)) {
  80459. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80460. $package['min'])) {
  80461. $this->_invalidVersion(substr($type, 1) . '<min', $package['min']);
  80462. }
  80463. }
  80464. if (is_array($package) && array_key_exists('max', $package)) {
  80465. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80466. $package['max'])) {
  80467. $this->_invalidVersion(substr($type, 1) . '<max', $package['max']);
  80468. }
  80469. }
  80470. if (is_array($package) && array_key_exists('exclude', $package)) {
  80471. if (!is_array($package['exclude'])) {
  80472. $package['exclude'] = array($package['exclude']);
  80473. }
  80474. foreach ($package['exclude'] as $exclude) {
  80475. if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
  80476. $exclude)) {
  80477. $this->_invalidVersion(substr($type, 1) . '<exclude', $exclude);
  80478. }
  80479. }
  80480. }
  80481. }
  80482. }
  80483. function _validateBundle($list)
  80484. {
  80485. if (!is_array($list) || !isset($list['bundledpackage'])) {
  80486. return $this->_NoBundledPackages();
  80487. }
  80488. if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) {
  80489. return $this->_AtLeast2BundledPackages();
  80490. }
  80491. foreach ($list['bundledpackage'] as $package) {
  80492. if (!is_string($package)) {
  80493. $this->_bundledPackagesMustBeFilename();
  80494. }
  80495. }
  80496. }
  80497. function _validateFilelist($list = false, $allowignore = false, $dirs = '')
  80498. {
  80499. $iscontents = false;
  80500. if (!$list) {
  80501. $iscontents = true;
  80502. $list = $this->_packageInfo['contents'];
  80503. if (isset($this->_packageInfo['bundle'])) {
  80504. return $this->_validateBundle($list);
  80505. }
  80506. }
  80507. if ($allowignore) {
  80508. $struc = array(
  80509. '*install->name->as',
  80510. '*ignore->name'
  80511. );
  80512. } else {
  80513. $struc = array(
  80514. '*dir->name->?baseinstalldir',
  80515. '*file->name->role->?baseinstalldir->?md5sum'
  80516. );
  80517. if (isset($list['dir']) && isset($list['file'])) {
  80518. // stave off validation errors without requiring a set order.
  80519. $_old = $list;
  80520. if (isset($list['attribs'])) {
  80521. $list = array('attribs' => $_old['attribs']);
  80522. }
  80523. $list['dir'] = $_old['dir'];
  80524. $list['file'] = $_old['file'];
  80525. }
  80526. }
  80527. if (!isset($list['attribs']) || !isset($list['attribs']['name'])) {
  80528. $unknown = $allowignore ? '<filelist>' : '<dir name="*unknown*">';
  80529. $dirname = $iscontents ? '<contents>' : $unknown;
  80530. } else {
  80531. $dirname = '<dir name="' . $list['attribs']['name'] . '">';
  80532. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  80533. str_replace('\\', '/', $list['attribs']['name']))) {
  80534. // file contains .. parent directory or . cur directory
  80535. $this->_invalidDirName($list['attribs']['name']);
  80536. }
  80537. }
  80538. $res = $this->_stupidSchemaValidate($struc, $list, $dirname);
  80539. if ($allowignore && $res) {
  80540. $ignored_or_installed = array();
  80541. $this->_pf->getFilelist();
  80542. $fcontents = $this->_pf->getContents();
  80543. $filelist = array();
  80544. if (!isset($fcontents['dir']['file'][0])) {
  80545. $fcontents['dir']['file'] = array($fcontents['dir']['file']);
  80546. }
  80547. foreach ($fcontents['dir']['file'] as $file) {
  80548. $filelist[$file['attribs']['name']] = true;
  80549. }
  80550. if (isset($list['install'])) {
  80551. if (!isset($list['install'][0])) {
  80552. $list['install'] = array($list['install']);
  80553. }
  80554. foreach ($list['install'] as $file) {
  80555. if (!isset($filelist[$file['attribs']['name']])) {
  80556. $this->_notInContents($file['attribs']['name'], 'install');
  80557. continue;
  80558. }
  80559. if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {
  80560. $this->_multipleInstallAs($file['attribs']['name']);
  80561. }
  80562. if (!isset($ignored_or_installed[$file['attribs']['name']])) {
  80563. $ignored_or_installed[$file['attribs']['name']] = array();
  80564. }
  80565. $ignored_or_installed[$file['attribs']['name']][] = 1;
  80566. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  80567. str_replace('\\', '/', $file['attribs']['as']))) {
  80568. // file contains .. parent directory or . cur directory references
  80569. $this->_invalidFileInstallAs($file['attribs']['name'],
  80570. $file['attribs']['as']);
  80571. }
  80572. }
  80573. }
  80574. if (isset($list['ignore'])) {
  80575. if (!isset($list['ignore'][0])) {
  80576. $list['ignore'] = array($list['ignore']);
  80577. }
  80578. foreach ($list['ignore'] as $file) {
  80579. if (!isset($filelist[$file['attribs']['name']])) {
  80580. $this->_notInContents($file['attribs']['name'], 'ignore');
  80581. continue;
  80582. }
  80583. if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {
  80584. $this->_ignoreAndInstallAs($file['attribs']['name']);
  80585. }
  80586. }
  80587. }
  80588. }
  80589. if (!$allowignore && isset($list['file'])) {
  80590. if (is_string($list['file'])) {
  80591. $this->_oldStyleFileNotAllowed();
  80592. return false;
  80593. }
  80594. if (!isset($list['file'][0])) {
  80595. // single file
  80596. $list['file'] = array($list['file']);
  80597. }
  80598. foreach ($list['file'] as $i => $file)
  80599. {
  80600. if (isset($file['attribs']) && isset($file['attribs']['name'])) {
  80601. if ($file['attribs']['name'][0] == '.' &&
  80602. $file['attribs']['name'][1] == '/') {
  80603. // name is something like "./doc/whatever.txt"
  80604. $this->_invalidFileName($file['attribs']['name'], $dirname);
  80605. }
  80606. if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
  80607. str_replace('\\', '/', $file['attribs']['name']))) {
  80608. // file contains .. parent directory or . cur directory
  80609. $this->_invalidFileName($file['attribs']['name'], $dirname);
  80610. }
  80611. }
  80612. if (isset($file['attribs']) && isset($file['attribs']['role'])) {
  80613. if (!$this->_validateRole($file['attribs']['role'])) {
  80614. if (isset($this->_packageInfo['usesrole'])) {
  80615. $roles = $this->_packageInfo['usesrole'];
  80616. if (!isset($roles[0])) {
  80617. $roles = array($roles);
  80618. }
  80619. foreach ($roles as $role) {
  80620. if ($role['role'] = $file['attribs']['role']) {
  80621. $msg = 'This package contains role "%role%" and requires ' .
  80622. 'package "%package%" to be used';
  80623. if (isset($role['uri'])) {
  80624. $params = array('role' => $role['role'],
  80625. 'package' => $role['uri']);
  80626. } else {
  80627. $params = array('role' => $role['role'],
  80628. 'package' => $this->_pf->_registry->
  80629. parsedPackageNameToString(array('package' =>
  80630. $role['package'], 'channel' => $role['channel']),
  80631. true));
  80632. }
  80633. $this->_stack->push('_mustInstallRole', 'error', $params, $msg);
  80634. }
  80635. }
  80636. }
  80637. $this->_invalidFileRole($file['attribs']['name'],
  80638. $dirname, $file['attribs']['role']);
  80639. }
  80640. }
  80641. if (!isset($file['attribs'])) {
  80642. continue;
  80643. }
  80644. $save = $file['attribs'];
  80645. if ($dirs) {
  80646. $save['name'] = $dirs . '/' . $save['name'];
  80647. }
  80648. unset($file['attribs']);
  80649. if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks
  80650. foreach ($file as $task => $value) {
  80651. if ($tagClass = $this->_pf->getTask($task)) {
  80652. if (!is_array($value) || !isset($value[0])) {
  80653. $value = array($value);
  80654. }
  80655. foreach ($value as $v) {
  80656. $ret = call_user_func(array($tagClass, 'validateXml'),
  80657. $this->_pf, $v, $this->_pf->_config, $save);
  80658. if (is_array($ret)) {
  80659. $this->_invalidTask($task, $ret, isset($save['name']) ?
  80660. $save['name'] : '');
  80661. }
  80662. }
  80663. } else {
  80664. if (isset($this->_packageInfo['usestask'])) {
  80665. $roles = $this->_packageInfo['usestask'];
  80666. if (!isset($roles[0])) {
  80667. $roles = array($roles);
  80668. }
  80669. foreach ($roles as $role) {
  80670. if ($role['task'] = $task) {
  80671. $msg = 'This package contains task "%task%" and requires ' .
  80672. 'package "%package%" to be used';
  80673. if (isset($role['uri'])) {
  80674. $params = array('task' => $role['task'],
  80675. 'package' => $role['uri']);
  80676. } else {
  80677. $params = array('task' => $role['task'],
  80678. 'package' => $this->_pf->_registry->
  80679. parsedPackageNameToString(array('package' =>
  80680. $role['package'], 'channel' => $role['channel']),
  80681. true));
  80682. }
  80683. $this->_stack->push('_mustInstallTask', 'error',
  80684. $params, $msg);
  80685. }
  80686. }
  80687. }
  80688. $this->_unknownTask($task, $save['name']);
  80689. }
  80690. }
  80691. }
  80692. }
  80693. }
  80694. if (isset($list['ignore'])) {
  80695. if (!$allowignore) {
  80696. $this->_ignoreNotAllowed('ignore');
  80697. }
  80698. }
  80699. if (isset($list['install'])) {
  80700. if (!$allowignore) {
  80701. $this->_ignoreNotAllowed('install');
  80702. }
  80703. }
  80704. if (isset($list['file'])) {
  80705. if ($allowignore) {
  80706. $this->_fileNotAllowed('file');
  80707. }
  80708. }
  80709. if (isset($list['dir'])) {
  80710. if ($allowignore) {
  80711. $this->_fileNotAllowed('dir');
  80712. } else {
  80713. if (!isset($list['dir'][0])) {
  80714. $list['dir'] = array($list['dir']);
  80715. }
  80716. foreach ($list['dir'] as $dir) {
  80717. if (isset($dir['attribs']) && isset($dir['attribs']['name'])) {
  80718. if ($dir['attribs']['name'] == '/' ||
  80719. !isset($this->_packageInfo['contents']['dir']['dir'])) {
  80720. // always use nothing if the filelist has already been flattened
  80721. $newdirs = '';
  80722. } elseif ($dirs == '') {
  80723. $newdirs = $dir['attribs']['name'];
  80724. } else {
  80725. $newdirs = $dirs . '/' . $dir['attribs']['name'];
  80726. }
  80727. } else {
  80728. $newdirs = $dirs;
  80729. }
  80730. $this->_validateFilelist($dir, $allowignore, $newdirs);
  80731. }
  80732. }
  80733. }
  80734. }
  80735. function _validateRelease()
  80736. {
  80737. if (isset($this->_packageInfo['phprelease'])) {
  80738. $release = 'phprelease';
  80739. if (isset($this->_packageInfo['providesextension'])) {
  80740. $this->_cannotProvideExtension($release);
  80741. }
  80742. if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
  80743. $this->_cannotHaveSrcpackage($release);
  80744. }
  80745. $releases = $this->_packageInfo['phprelease'];
  80746. if (!is_array($releases)) {
  80747. return true;
  80748. }
  80749. if (!isset($releases[0])) {
  80750. $releases = array($releases);
  80751. }
  80752. foreach ($releases as $rel) {
  80753. $this->_stupidSchemaValidate(array(
  80754. '*installconditions',
  80755. '*filelist',
  80756. ), $rel, '<phprelease>');
  80757. }
  80758. }
  80759. foreach (array('', 'zend') as $prefix) {
  80760. $releasetype = $prefix . 'extsrcrelease';
  80761. if (isset($this->_packageInfo[$releasetype])) {
  80762. $release = $releasetype;
  80763. if (!isset($this->_packageInfo['providesextension'])) {
  80764. $this->_mustProvideExtension($release);
  80765. }
  80766. if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
  80767. $this->_cannotHaveSrcpackage($release);
  80768. }
  80769. $releases = $this->_packageInfo[$releasetype];
  80770. if (!is_array($releases)) {
  80771. return true;
  80772. }
  80773. if (!isset($releases[0])) {
  80774. $releases = array($releases);
  80775. }
  80776. foreach ($releases as $rel) {
  80777. $this->_stupidSchemaValidate(array(
  80778. '*installconditions',
  80779. '*configureoption->name->prompt->?default',
  80780. '*binarypackage',
  80781. '*filelist',
  80782. ), $rel, '<' . $releasetype . '>');
  80783. if (isset($rel['binarypackage'])) {
  80784. if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) {
  80785. $rel['binarypackage'] = array($rel['binarypackage']);
  80786. }
  80787. foreach ($rel['binarypackage'] as $bin) {
  80788. if (!is_string($bin)) {
  80789. $this->_binaryPackageMustBePackagename();
  80790. }
  80791. }
  80792. }
  80793. }
  80794. }
  80795. $releasetype = 'extbinrelease';
  80796. if (isset($this->_packageInfo[$releasetype])) {
  80797. $release = $releasetype;
  80798. if (!isset($this->_packageInfo['providesextension'])) {
  80799. $this->_mustProvideExtension($release);
  80800. }
  80801. if (isset($this->_packageInfo['channel']) &&
  80802. !isset($this->_packageInfo['srcpackage'])) {
  80803. $this->_mustSrcPackage($release);
  80804. }
  80805. if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) {
  80806. $this->_mustSrcuri($release);
  80807. }
  80808. $releases = $this->_packageInfo[$releasetype];
  80809. if (!is_array($releases)) {
  80810. return true;
  80811. }
  80812. if (!isset($releases[0])) {
  80813. $releases = array($releases);
  80814. }
  80815. foreach ($releases as $rel) {
  80816. $this->_stupidSchemaValidate(array(
  80817. '*installconditions',
  80818. '*filelist',
  80819. ), $rel, '<' . $releasetype . '>');
  80820. }
  80821. }
  80822. }
  80823. if (isset($this->_packageInfo['bundle'])) {
  80824. $release = 'bundle';
  80825. if (isset($this->_packageInfo['providesextension'])) {
  80826. $this->_cannotProvideExtension($release);
  80827. }
  80828. if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
  80829. $this->_cannotHaveSrcpackage($release);
  80830. }
  80831. $releases = $this->_packageInfo['bundle'];
  80832. if (!is_array($releases) || !isset($releases[0])) {
  80833. $releases = array($releases);
  80834. }
  80835. foreach ($releases as $rel) {
  80836. $this->_stupidSchemaValidate(array(
  80837. '*installconditions',
  80838. '*filelist',
  80839. ), $rel, '<bundle>');
  80840. }
  80841. }
  80842. foreach ($releases as $rel) {
  80843. if (is_array($rel) && array_key_exists('installconditions', $rel)) {
  80844. $this->_validateInstallConditions($rel['installconditions'],
  80845. "<$release><installconditions>");
  80846. }
  80847. if (is_array($rel) && array_key_exists('filelist', $rel)) {
  80848. if ($rel['filelist']) {
  80849. $this->_validateFilelist($rel['filelist'], true);
  80850. }
  80851. }
  80852. }
  80853. }
  80854. /**
  80855. * This is here to allow role extension through plugins
  80856. * @param string
  80857. */
  80858. function _validateRole($role)
  80859. {
  80860. return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType()));
  80861. }
  80862. function _pearVersionTooLow($version)
  80863. {
  80864. $this->_stack->push(__FUNCTION__, 'error',
  80865. array('version' => $version),
  80866. 'This package.xml requires PEAR version %version% to parse properly, we are ' .
  80867. 'version 1.10.10');
  80868. }
  80869. function _invalidTagOrder($oktags, $actual, $root)
  80870. {
  80871. $this->_stack->push(__FUNCTION__, 'error',
  80872. array('oktags' => $oktags, 'actual' => $actual, 'root' => $root),
  80873. 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"');
  80874. }
  80875. function _ignoreNotAllowed($type)
  80876. {
  80877. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  80878. '<%type%> is not allowed inside global <contents>, only inside ' .
  80879. '<phprelease>/<extbinrelease>/<zendextbinrelease>, use <dir> and <file> only');
  80880. }
  80881. function _fileNotAllowed($type)
  80882. {
  80883. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  80884. '<%type%> is not allowed inside release <filelist>, only inside ' .
  80885. '<contents>, use <ignore> and <install> only');
  80886. }
  80887. function _oldStyleFileNotAllowed()
  80888. {
  80889. $this->_stack->push(__FUNCTION__, 'error', array(),
  80890. 'Old-style <file>name</file> is not allowed. Use' .
  80891. '<file name="name" role="role"/>');
  80892. }
  80893. function _tagMissingAttribute($tag, $attr, $context)
  80894. {
  80895. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
  80896. 'attribute' => $attr, 'context' => $context),
  80897. 'tag <%tag%> in context "%context%" has no attribute "%attribute%"');
  80898. }
  80899. function _tagHasNoAttribs($tag, $context)
  80900. {
  80901. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
  80902. 'context' => $context),
  80903. 'tag <%tag%> has no attributes in context "%context%"');
  80904. }
  80905. function _invalidInternalStructure()
  80906. {
  80907. $this->_stack->push(__FUNCTION__, 'exception', array(),
  80908. 'internal array was not generated by compatible parser, or extreme parser error, cannot continue');
  80909. }
  80910. function _invalidFileRole($file, $dir, $role)
  80911. {
  80912. $this->_stack->push(__FUNCTION__, 'error', array(
  80913. 'file' => $file, 'dir' => $dir, 'role' => $role,
  80914. 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())),
  80915. 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%');
  80916. }
  80917. function _invalidFileName($file, $dir)
  80918. {
  80919. $this->_stack->push(__FUNCTION__, 'error', array(
  80920. 'file' => $file),
  80921. 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."');
  80922. }
  80923. function _invalidFileInstallAs($file, $as)
  80924. {
  80925. $this->_stack->push(__FUNCTION__, 'error', array(
  80926. 'file' => $file, 'as' => $as),
  80927. 'File "%file%" <install as="%as%"/> cannot contain "./" or contain ".."');
  80928. }
  80929. function _invalidDirName($dir)
  80930. {
  80931. $this->_stack->push(__FUNCTION__, 'error', array(
  80932. 'dir' => $file),
  80933. 'Directory "%dir%" cannot begin with "./" or contain ".."');
  80934. }
  80935. function _filelistCannotContainFile($filelist)
  80936. {
  80937. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
  80938. '<%tag%> can only contain <dir>, contains <file>. Use ' .
  80939. '<dir name="/"> as the first dir element');
  80940. }
  80941. function _filelistMustContainDir($filelist)
  80942. {
  80943. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
  80944. '<%tag%> must contain <dir>. Use <dir name="/"> as the ' .
  80945. 'first dir element');
  80946. }
  80947. function _tagCannotBeEmpty($tag)
  80948. {
  80949. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
  80950. '<%tag%> cannot be empty (<%tag%/>)');
  80951. }
  80952. function _UrlOrChannel($type, $name)
  80953. {
  80954. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  80955. 'name' => $name),
  80956. 'Required dependency <%type%> "%name%" can have either url OR ' .
  80957. 'channel attributes, and not both');
  80958. }
  80959. function _NoChannel($type, $name)
  80960. {
  80961. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  80962. 'name' => $name),
  80963. 'Required dependency <%type%> "%name%" must have either url OR ' .
  80964. 'channel attributes');
  80965. }
  80966. function _UrlOrChannelGroup($type, $name, $group)
  80967. {
  80968. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  80969. 'name' => $name, 'group' => $group),
  80970. 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .
  80971. 'channel attributes, and not both');
  80972. }
  80973. function _NoChannelGroup($type, $name, $group)
  80974. {
  80975. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
  80976. 'name' => $name, 'group' => $group),
  80977. 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .
  80978. 'channel attributes');
  80979. }
  80980. function _unknownChannel($channel)
  80981. {
  80982. $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel),
  80983. 'Unknown channel "%channel%"');
  80984. }
  80985. function _noPackageVersion()
  80986. {
  80987. $this->_stack->push(__FUNCTION__, 'error', array(),
  80988. 'package.xml <package> tag has no version attribute, or version is not 2.0');
  80989. }
  80990. function _NoBundledPackages()
  80991. {
  80992. $this->_stack->push(__FUNCTION__, 'error', array(),
  80993. 'No <bundledpackage> tag was found in <contents>, required for bundle packages');
  80994. }
  80995. function _AtLeast2BundledPackages()
  80996. {
  80997. $this->_stack->push(__FUNCTION__, 'error', array(),
  80998. 'At least 2 packages must be bundled in a bundle package');
  80999. }
  81000. function _ChannelOrUri($name)
  81001. {
  81002. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  81003. 'Bundled package "%name%" can have either a uri or a channel, not both');
  81004. }
  81005. function _noChildTag($child, $tag)
  81006. {
  81007. $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag),
  81008. 'Tag <%tag%> is missing child tag <%child%>');
  81009. }
  81010. function _invalidVersion($type, $value)
  81011. {
  81012. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value),
  81013. 'Version type <%type%> is not a valid version (%value%)');
  81014. }
  81015. function _invalidState($type, $value)
  81016. {
  81017. $states = array('stable', 'beta', 'alpha', 'devel');
  81018. if ($type != 'api') {
  81019. $states[] = 'snapshot';
  81020. }
  81021. if (strtolower($value) == 'rc') {
  81022. $this->_stack->push(__FUNCTION__, 'error',
  81023. array('version' => $this->_packageInfo['version']['release']),
  81024. 'RC is not a state, it is a version postfix, try %version%RC1, stability beta');
  81025. }
  81026. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value,
  81027. 'types' => $states),
  81028. 'Stability type <%type%> is not a valid stability (%value%), must be one of ' .
  81029. '%types%');
  81030. }
  81031. function _invalidTask($task, $ret, $file)
  81032. {
  81033. switch ($ret[0]) {
  81034. case PEAR_TASK_ERROR_MISSING_ATTRIB :
  81035. $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file);
  81036. $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%';
  81037. break;
  81038. case PEAR_TASK_ERROR_NOATTRIBS :
  81039. $info = array('task' => $task, 'file' => $file);
  81040. $msg = 'task <%task%> has no attributes in file %file%';
  81041. break;
  81042. case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :
  81043. $info = array('attrib' => $ret[1], 'values' => $ret[3],
  81044. 'was' => $ret[2], 'task' => $task, 'file' => $file);
  81045. $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '.
  81046. 'in file %file%, expecting one of "%values%"';
  81047. break;
  81048. case PEAR_TASK_ERROR_INVALID :
  81049. $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file);
  81050. $msg = 'task <%task%> in file %file% is invalid because of "%reason%"';
  81051. break;
  81052. }
  81053. $this->_stack->push(__FUNCTION__, 'error', $info, $msg);
  81054. }
  81055. function _unknownTask($task, $file)
  81056. {
  81057. $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file),
  81058. 'Unknown task "%task%" passed in file <file name="%file%">');
  81059. }
  81060. function _subpackageCannotProvideExtension($name)
  81061. {
  81062. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  81063. 'Subpackage dependency "%name%" cannot use <providesextension>, ' .
  81064. 'only package dependencies can use this tag');
  81065. }
  81066. function _subpackagesCannotConflict($name)
  81067. {
  81068. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  81069. 'Subpackage dependency "%name%" cannot use <conflicts/>, ' .
  81070. 'only package dependencies can use this tag');
  81071. }
  81072. function _cannotProvideExtension($release)
  81073. {
  81074. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  81075. '<%release%> packages cannot use <providesextension>, only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension');
  81076. }
  81077. function _mustProvideExtension($release)
  81078. {
  81079. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  81080. '<%release%> packages must use <providesextension> to indicate which PHP extension is provided');
  81081. }
  81082. function _cannotHaveSrcpackage($release)
  81083. {
  81084. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  81085. '<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag');
  81086. }
  81087. function _mustSrcPackage($release)
  81088. {
  81089. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  81090. '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcpackage>');
  81091. }
  81092. function _mustSrcuri($release)
  81093. {
  81094. $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
  81095. '<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcuri>');
  81096. }
  81097. function _uriDepsCannotHaveVersioning($type)
  81098. {
  81099. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  81100. '%type%: dependencies with a <uri> tag cannot have any versioning information');
  81101. }
  81102. function _conflictingDepsCannotHaveVersioning($type)
  81103. {
  81104. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  81105. '%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' .
  81106. 'exclude specific versions of a dependency');
  81107. }
  81108. function _DepchannelCannotBeUri($type)
  81109. {
  81110. $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
  81111. '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .
  81112. 'dependencies only');
  81113. }
  81114. function _bundledPackagesMustBeFilename()
  81115. {
  81116. $this->_stack->push(__FUNCTION__, 'error', array(),
  81117. '<bundledpackage> tags must contain only the filename of a package release ' .
  81118. 'in the bundle');
  81119. }
  81120. function _binaryPackageMustBePackagename()
  81121. {
  81122. $this->_stack->push(__FUNCTION__, 'error', array(),
  81123. '<binarypackage> tags must contain the name of a package that is ' .
  81124. 'a compiled version of this extsrc/zendextsrc package');
  81125. }
  81126. function _fileNotFound($file)
  81127. {
  81128. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  81129. 'File "%file%" in package.xml does not exist');
  81130. }
  81131. function _notInContents($file, $tag)
  81132. {
  81133. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag),
  81134. '<%tag% name="%file%"> is invalid, file is not in <contents>');
  81135. }
  81136. function _cannotValidateNoPathSet()
  81137. {
  81138. $this->_stack->push(__FUNCTION__, 'error', array(),
  81139. 'Cannot validate files, no path to package file is set (use setPackageFile())');
  81140. }
  81141. function _usesroletaskMustHaveChannelOrUri($role, $tag)
  81142. {
  81143. $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
  81144. '<%tag%> for role "%role%" must contain either <uri>, or <channel> and <package>');
  81145. }
  81146. function _usesroletaskMustHavePackage($role, $tag)
  81147. {
  81148. $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
  81149. '<%tag%> for role "%role%" must contain <package>');
  81150. }
  81151. function _usesroletaskMustHaveRoleTask($tag, $type)
  81152. {
  81153. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type),
  81154. '<%tag%> must contain <%type%> defining the %type% to be used');
  81155. }
  81156. function _cannotConflictWithAllOs($type)
  81157. {
  81158. $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
  81159. '%tag% cannot conflict with all OSes');
  81160. }
  81161. function _invalidDepGroupName($name)
  81162. {
  81163. $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
  81164. 'Invalid dependency group name "%name%"');
  81165. }
  81166. function _multipleToplevelDirNotAllowed()
  81167. {
  81168. $this->_stack->push(__FUNCTION__, 'error', array(),
  81169. 'Multiple top-level <dir> tags are not allowed. Enclose them ' .
  81170. 'in a <dir name="/">');
  81171. }
  81172. function _multipleInstallAs($file)
  81173. {
  81174. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  81175. 'Only one <install> tag is allowed for file "%file%"');
  81176. }
  81177. function _ignoreAndInstallAs($file)
  81178. {
  81179. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  81180. 'Cannot have both <ignore> and <install> tags for file "%file%"');
  81181. }
  81182. function _analyzeBundledPackages()
  81183. {
  81184. if (!$this->_isValid) {
  81185. return false;
  81186. }
  81187. if (!$this->_pf->getPackageType() == 'bundle') {
  81188. return false;
  81189. }
  81190. if (!isset($this->_pf->_packageFile)) {
  81191. return false;
  81192. }
  81193. $dir_prefix = dirname($this->_pf->_packageFile);
  81194. $common = new PEAR_Common;
  81195. $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
  81196. array($common, 'log');
  81197. $info = $this->_pf->getContents();
  81198. $info = $info['bundledpackage'];
  81199. if (!is_array($info)) {
  81200. $info = array($info);
  81201. }
  81202. $pkg = new PEAR_PackageFile($this->_pf->_config);
  81203. foreach ($info as $package) {
  81204. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) {
  81205. $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package);
  81206. $this->_isValid = 0;
  81207. continue;
  81208. }
  81209. call_user_func_array($log, array(1, "Analyzing bundled package $package"));
  81210. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  81211. $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package,
  81212. PEAR_VALIDATE_NORMAL);
  81213. PEAR::popErrorHandling();
  81214. if (PEAR::isError($ret)) {
  81215. call_user_func_array($log, array(0, "ERROR: package $package is not a valid " .
  81216. 'package'));
  81217. $inf = $ret->getUserInfo();
  81218. if (is_array($inf)) {
  81219. foreach ($inf as $err) {
  81220. call_user_func_array($log, array(1, $err['message']));
  81221. }
  81222. }
  81223. return false;
  81224. }
  81225. }
  81226. return true;
  81227. }
  81228. function _analyzePhpFiles()
  81229. {
  81230. if (!$this->_isValid) {
  81231. return false;
  81232. }
  81233. if (!isset($this->_pf->_packageFile)) {
  81234. $this->_cannotValidateNoPathSet();
  81235. return false;
  81236. }
  81237. $dir_prefix = dirname($this->_pf->_packageFile);
  81238. $common = new PEAR_Common;
  81239. $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
  81240. array(&$common, 'log');
  81241. $info = $this->_pf->getContents();
  81242. if (!$info || !isset($info['dir']['file'])) {
  81243. $this->_tagCannotBeEmpty('contents><dir');
  81244. return false;
  81245. }
  81246. $info = $info['dir']['file'];
  81247. if (isset($info['attribs'])) {
  81248. $info = array($info);
  81249. }
  81250. $provides = array();
  81251. foreach ($info as $fa) {
  81252. $fa = $fa['attribs'];
  81253. $file = $fa['name'];
  81254. if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
  81255. $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file);
  81256. $this->_isValid = 0;
  81257. continue;
  81258. }
  81259. if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) {
  81260. call_user_func_array($log, array(1, "Analyzing $file"));
  81261. $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
  81262. if ($srcinfo) {
  81263. $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo));
  81264. }
  81265. }
  81266. }
  81267. $this->_packageName = $pn = $this->_pf->getPackage();
  81268. $pnl = strlen($pn);
  81269. foreach ($provides as $key => $what) {
  81270. if (isset($what['explicit']) || !$what) {
  81271. // skip conformance checks if the provides entry is
  81272. // specified in the package.xml file
  81273. continue;
  81274. }
  81275. extract($what);
  81276. if ($type == 'class') {
  81277. if (!strncasecmp($name, $pn, $pnl)) {
  81278. continue;
  81279. }
  81280. $this->_stack->push(__FUNCTION__, 'warning',
  81281. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
  81282. 'in %file%: %type% "%name%" not prefixed with package name "%package%"');
  81283. } elseif ($type == 'function') {
  81284. if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
  81285. continue;
  81286. }
  81287. $this->_stack->push(__FUNCTION__, 'warning',
  81288. array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
  81289. 'in %file%: %type% "%name%" not prefixed with package name "%package%"');
  81290. }
  81291. }
  81292. return $this->_isValid;
  81293. }
  81294. /**
  81295. * Analyze the source code of the given PHP file
  81296. *
  81297. * @param string Filename of the PHP file
  81298. * @param boolean whether to analyze $file as the file contents
  81299. * @return mixed
  81300. */
  81301. function analyzeSourceCode($file, $string = false)
  81302. {
  81303. if (!function_exists("token_get_all")) {
  81304. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  81305. 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer');
  81306. return false;
  81307. }
  81308. if (!defined('T_DOC_COMMENT')) {
  81309. define('T_DOC_COMMENT', T_COMMENT);
  81310. }
  81311. if (!defined('T_INTERFACE')) {
  81312. define('T_INTERFACE', -1);
  81313. }
  81314. if (!defined('T_IMPLEMENTS')) {
  81315. define('T_IMPLEMENTS', -1);
  81316. }
  81317. if ($string) {
  81318. $contents = $file;
  81319. } else {
  81320. if (!$fp = @fopen($file, "r")) {
  81321. return false;
  81322. }
  81323. fclose($fp);
  81324. $contents = file_get_contents($file);
  81325. }
  81326. // Silence this function so we can catch PHP Warnings and show our own custom message
  81327. $tokens = @token_get_all($contents);
  81328. if (isset($php_errormsg)) {
  81329. if (isset($this->_stack)) {
  81330. $pn = $this->_pf->getPackage();
  81331. $this->_stack->push(__FUNCTION__, 'warning',
  81332. array('file' => $file, 'package' => $pn),
  81333. 'in %file%: Could not process file for unknown reasons,' .
  81334. ' possibly a PHP parse error in %file% from %package%');
  81335. }
  81336. }
  81337. /*
  81338. for ($i = 0; $i < sizeof($tokens); $i++) {
  81339. @list($token, $data) = $tokens[$i];
  81340. if (is_string($token)) {
  81341. var_dump($token);
  81342. } else {
  81343. print token_name($token) . ' ';
  81344. var_dump(rtrim($data));
  81345. }
  81346. }
  81347. */
  81348. $look_for = 0;
  81349. $paren_level = 0;
  81350. $bracket_level = 0;
  81351. $brace_level = 0;
  81352. $lastphpdoc = '';
  81353. $current_class = '';
  81354. $current_interface = '';
  81355. $current_class_level = -1;
  81356. $current_function = '';
  81357. $current_function_level = -1;
  81358. $declared_classes = array();
  81359. $declared_interfaces = array();
  81360. $declared_functions = array();
  81361. $declared_methods = array();
  81362. $used_classes = array();
  81363. $used_functions = array();
  81364. $extends = array();
  81365. $implements = array();
  81366. $nodeps = array();
  81367. $inquote = false;
  81368. $interface = false;
  81369. for ($i = 0; $i < sizeof($tokens); $i++) {
  81370. if (is_array($tokens[$i])) {
  81371. list($token, $data) = $tokens[$i];
  81372. } else {
  81373. $token = $tokens[$i];
  81374. $data = '';
  81375. }
  81376. if ($inquote) {
  81377. if ($token != '"' && $token != T_END_HEREDOC) {
  81378. continue;
  81379. } else {
  81380. $inquote = false;
  81381. continue;
  81382. }
  81383. }
  81384. switch ($token) {
  81385. case T_WHITESPACE :
  81386. continue 2;
  81387. case ';':
  81388. if ($interface) {
  81389. $current_function = '';
  81390. $current_function_level = -1;
  81391. }
  81392. break;
  81393. case '"':
  81394. case T_START_HEREDOC:
  81395. $inquote = true;
  81396. break;
  81397. case T_CURLY_OPEN:
  81398. case T_DOLLAR_OPEN_CURLY_BRACES:
  81399. case '{': $brace_level++; continue 2;
  81400. case '}':
  81401. $brace_level--;
  81402. if ($current_class_level == $brace_level) {
  81403. $current_class = '';
  81404. $current_class_level = -1;
  81405. }
  81406. if ($current_function_level == $brace_level) {
  81407. $current_function = '';
  81408. $current_function_level = -1;
  81409. }
  81410. continue 2;
  81411. case '[': $bracket_level++; continue 2;
  81412. case ']': $bracket_level--; continue 2;
  81413. case '(': $paren_level++; continue 2;
  81414. case ')': $paren_level--; continue 2;
  81415. case T_INTERFACE:
  81416. $interface = true;
  81417. case T_CLASS:
  81418. if (($current_class_level != -1) || ($current_function_level != -1)) {
  81419. if (isset($this->_stack)) {
  81420. $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
  81421. 'Parser error: invalid PHP found in file "%file%"');
  81422. } else {
  81423. PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  81424. PEAR_COMMON_ERROR_INVALIDPHP);
  81425. }
  81426. return false;
  81427. }
  81428. case T_FUNCTION:
  81429. case T_NEW:
  81430. case T_EXTENDS:
  81431. case T_IMPLEMENTS:
  81432. $look_for = $token;
  81433. continue 2;
  81434. case T_STRING:
  81435. if ($look_for == T_CLASS) {
  81436. $current_class = $data;
  81437. $current_class_level = $brace_level;
  81438. $declared_classes[] = $current_class;
  81439. } elseif ($look_for == T_INTERFACE) {
  81440. $current_interface = $data;
  81441. $current_class_level = $brace_level;
  81442. $declared_interfaces[] = $current_interface;
  81443. } elseif ($look_for == T_IMPLEMENTS) {
  81444. $implements[$current_class] = $data;
  81445. } elseif ($look_for == T_EXTENDS) {
  81446. $extends[$current_class] = $data;
  81447. } elseif ($look_for == T_FUNCTION) {
  81448. if ($current_class) {
  81449. $current_function = "$current_class::$data";
  81450. $declared_methods[$current_class][] = $data;
  81451. } elseif ($current_interface) {
  81452. $current_function = "$current_interface::$data";
  81453. $declared_methods[$current_interface][] = $data;
  81454. } else {
  81455. $current_function = $data;
  81456. $declared_functions[] = $current_function;
  81457. }
  81458. $current_function_level = $brace_level;
  81459. $m = array();
  81460. } elseif ($look_for == T_NEW) {
  81461. $used_classes[$data] = true;
  81462. }
  81463. $look_for = 0;
  81464. continue 2;
  81465. case T_VARIABLE:
  81466. $look_for = 0;
  81467. continue 2;
  81468. case T_DOC_COMMENT:
  81469. case T_COMMENT:
  81470. if (preg_match('!^/\*\*\s!', $data)) {
  81471. $lastphpdoc = $data;
  81472. if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  81473. $nodeps = array_merge($nodeps, $m[1]);
  81474. }
  81475. }
  81476. continue 2;
  81477. case T_DOUBLE_COLON:
  81478. $token = $tokens[$i - 1][0];
  81479. if (!($token == T_WHITESPACE || $token == T_STRING || $token == T_STATIC || $token == T_VARIABLE)) {
  81480. if (isset($this->_stack)) {
  81481. $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file),
  81482. 'Parser error: invalid PHP found in file "%file%"');
  81483. } else {
  81484. PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  81485. PEAR_COMMON_ERROR_INVALIDPHP);
  81486. }
  81487. return false;
  81488. }
  81489. $class = $tokens[$i - 1][1];
  81490. if (strtolower($class) != 'parent') {
  81491. $used_classes[$class] = true;
  81492. }
  81493. continue 2;
  81494. }
  81495. }
  81496. return array(
  81497. "source_file" => $file,
  81498. "declared_classes" => $declared_classes,
  81499. "declared_interfaces" => $declared_interfaces,
  81500. "declared_methods" => $declared_methods,
  81501. "declared_functions" => $declared_functions,
  81502. "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  81503. "inheritance" => $extends,
  81504. "implements" => $implements,
  81505. );
  81506. }
  81507. /**
  81508. * Build a "provides" array from data returned by
  81509. * analyzeSourceCode(). The format of the built array is like
  81510. * this:
  81511. *
  81512. * array(
  81513. * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  81514. * ...
  81515. * )
  81516. *
  81517. *
  81518. * @param array $srcinfo array with information about a source file
  81519. * as returned by the analyzeSourceCode() method.
  81520. *
  81521. * @return void
  81522. *
  81523. * @access private
  81524. *
  81525. */
  81526. function _buildProvidesArray($srcinfo)
  81527. {
  81528. if (!$this->_isValid) {
  81529. return array();
  81530. }
  81531. $providesret = array();
  81532. $file = basename($srcinfo['source_file']);
  81533. $pn = isset($this->_pf) ? $this->_pf->getPackage() : '';
  81534. $pnl = strlen($pn);
  81535. foreach ($srcinfo['declared_classes'] as $class) {
  81536. $key = "class;$class";
  81537. if (isset($providesret[$key])) {
  81538. continue;
  81539. }
  81540. $providesret[$key] =
  81541. array('file'=> $file, 'type' => 'class', 'name' => $class);
  81542. if (isset($srcinfo['inheritance'][$class])) {
  81543. $providesret[$key]['extends'] =
  81544. $srcinfo['inheritance'][$class];
  81545. }
  81546. }
  81547. foreach ($srcinfo['declared_methods'] as $class => $methods) {
  81548. foreach ($methods as $method) {
  81549. $function = "$class::$method";
  81550. $key = "function;$function";
  81551. if ($method[0] == '_' || !strcasecmp($method, $class) ||
  81552. isset($providesret[$key])) {
  81553. continue;
  81554. }
  81555. $providesret[$key] =
  81556. array('file'=> $file, 'type' => 'function', 'name' => $function);
  81557. }
  81558. }
  81559. foreach ($srcinfo['declared_functions'] as $function) {
  81560. $key = "function;$function";
  81561. if ($function[0] == '_' || isset($providesret[$key])) {
  81562. continue;
  81563. }
  81564. if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  81565. $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  81566. }
  81567. $providesret[$key] =
  81568. array('file'=> $file, 'type' => 'function', 'name' => $function);
  81569. }
  81570. return $providesret;
  81571. }
  81572. }
  81573. <?php
  81574. /**
  81575. * PEAR_Proxy
  81576. *
  81577. * HTTP Proxy handling
  81578. *
  81579. * @category pear
  81580. * @package PEAR
  81581. * @author Nico Boehr
  81582. * @copyright 1997-2009 The Authors
  81583. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  81584. * @link http://pear.php.net/package/PEAR
  81585. */
  81586. class PEAR_Proxy
  81587. {
  81588. var $config = null;
  81589. /**
  81590. * @access private
  81591. */
  81592. var $proxy_host;
  81593. /**
  81594. * @access private
  81595. */
  81596. var $proxy_port;
  81597. /**
  81598. * @access private
  81599. */
  81600. var $proxy_user;
  81601. /**
  81602. * @access private
  81603. */
  81604. var $proxy_pass;
  81605. /**
  81606. * @access private
  81607. */
  81608. var $proxy_schema;
  81609. function __construct($config = null)
  81610. {
  81611. $this->config = $config;
  81612. $this->_parseProxyInfo();
  81613. }
  81614. /**
  81615. * @access private
  81616. */
  81617. function _parseProxyInfo()
  81618. {
  81619. $this->proxy_host = $this->proxy_port = $this->proxy_user = $this->proxy_pass = '';
  81620. if ($this->config->get('http_proxy')&&
  81621. $proxy = parse_url($this->config->get('http_proxy'))
  81622. ) {
  81623. $this->proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
  81624. $this->proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
  81625. $this->proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
  81626. $this->proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
  81627. $this->proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http';
  81628. }
  81629. }
  81630. /**
  81631. * @access private
  81632. */
  81633. function _httpConnect($fp, $host, $port)
  81634. {
  81635. fwrite($fp, "CONNECT $host:$port HTTP/1.1\r\n");
  81636. fwrite($fp, "Host: $host:$port\r\n");
  81637. if ($this->getProxyAuth()) {
  81638. fwrite($fp, 'Proxy-Authorization: Basic ' . $this->getProxyAuth() . "\r\n");
  81639. }
  81640. fwrite($fp, "\r\n");
  81641. while ($line = trim(fgets($fp, 1024))) {
  81642. if (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  81643. $code = (int)$matches[1];
  81644. /* as per RFC 2817 */
  81645. if ($code < 200 || $code >= 300) {
  81646. return PEAR::raiseError("Establishing a CONNECT tunnel through proxy failed with response code $code");
  81647. }
  81648. }
  81649. }
  81650. // connection was successful -- establish SSL through
  81651. // the tunnel
  81652. $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
  81653. if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
  81654. $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
  81655. $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
  81656. }
  81657. // set the correct hostname for working hostname
  81658. // verification
  81659. stream_context_set_option($fp, 'ssl', 'peer_name', $host);
  81660. // blocking socket needed for
  81661. // stream_socket_enable_crypto()
  81662. // see
  81663. // <http://php.net/manual/en/function.stream-socket-enable-crypto.php>
  81664. stream_set_blocking ($fp, true);
  81665. $crypto_res = stream_socket_enable_crypto($fp, true, $crypto_method);
  81666. if (!$crypto_res) {
  81667. return PEAR::raiseError("Could not establish SSL connection through proxy $proxy_host:$proxy_port: $crypto_res");
  81668. }
  81669. return true;
  81670. }
  81671. /**
  81672. * get the authorization information for the proxy, encoded to be
  81673. * passed in the Proxy-Authentication HTTP header.
  81674. * @return null|string the encoded authentication information if a
  81675. * proxy and authentication is configured, null
  81676. * otherwise.
  81677. */
  81678. function getProxyAuth()
  81679. {
  81680. if ($this->isProxyConfigured() && $this->proxy_user != '') {
  81681. return base64_encode($this->proxy_user . ':' . $this->proxy_pass);
  81682. }
  81683. return null;
  81684. }
  81685. function getProxyUser()
  81686. {
  81687. return $this->proxy_user;
  81688. }
  81689. /**
  81690. * Check if we are configured to use a proxy.
  81691. *
  81692. * @return boolean true if we are configured to use a proxy, false
  81693. * otherwise.
  81694. * @access public
  81695. */
  81696. function isProxyConfigured()
  81697. {
  81698. return $this->proxy_host != '';
  81699. }
  81700. /**
  81701. * Open a socket to a remote server, possibly involving a HTTP
  81702. * proxy.
  81703. *
  81704. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  81705. * setting), the proxy will be used.
  81706. *
  81707. * @param string $host the host to connect to
  81708. * @param string $port the port to connect to
  81709. * @param boolean $secure if true, establish a secure connection
  81710. * using TLS.
  81711. * @access public
  81712. */
  81713. function openSocket($host, $port, $secure = false)
  81714. {
  81715. if ($this->isProxyConfigured()) {
  81716. $fp = @fsockopen(
  81717. $this->proxy_host, $this->proxy_port,
  81718. $errno, $errstr, 15
  81719. );
  81720. if (!$fp) {
  81721. return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276);
  81722. }
  81723. /* HTTPS is to be used and we have a proxy, use CONNECT verb */
  81724. if ($secure) {
  81725. $res = $this->_httpConnect($fp, $host, $port);
  81726. if (PEAR::isError($res)) {
  81727. return $res;
  81728. }
  81729. }
  81730. } else {
  81731. if ($secure) {
  81732. $host = 'ssl://' . $host;
  81733. }
  81734. $fp = @fsockopen($host, $port, $errno, $errstr);
  81735. if (!$fp) {
  81736. return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
  81737. }
  81738. }
  81739. return $fp;
  81740. }
  81741. }
  81742. <?php
  81743. /**
  81744. * PEAR_Registry
  81745. *
  81746. * PHP versions 4 and 5
  81747. *
  81748. * @category pear
  81749. * @package PEAR
  81750. * @author Stig Bakken <ssb@php.net>
  81751. * @author Tomas V. V. Cox <cox@idecnet.com>
  81752. * @author Greg Beaver <cellog@php.net>
  81753. * @copyright 1997-2009 The Authors
  81754. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  81755. * @link http://pear.php.net/package/PEAR
  81756. * @since File available since Release 0.1
  81757. */
  81758. /**
  81759. * for PEAR_Error
  81760. */
  81761. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  81762. require_once 'phar://go-pear.phar/' . 'PEAR/DependencyDB.php';
  81763. define('PEAR_REGISTRY_ERROR_LOCK', -2);
  81764. define('PEAR_REGISTRY_ERROR_FORMAT', -3);
  81765. define('PEAR_REGISTRY_ERROR_FILE', -4);
  81766. define('PEAR_REGISTRY_ERROR_CONFLICT', -5);
  81767. define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6);
  81768. /**
  81769. * Administration class used to maintain the installed package database.
  81770. * @category pear
  81771. * @package PEAR
  81772. * @author Stig Bakken <ssb@php.net>
  81773. * @author Tomas V. V. Cox <cox@idecnet.com>
  81774. * @author Greg Beaver <cellog@php.net>
  81775. * @copyright 1997-2009 The Authors
  81776. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  81777. * @version Release: 1.10.10
  81778. * @link http://pear.php.net/package/PEAR
  81779. * @since Class available since Release 1.4.0a1
  81780. */
  81781. class PEAR_Registry extends PEAR
  81782. {
  81783. /**
  81784. * File containing all channel information.
  81785. * @var string
  81786. */
  81787. var $channels = '';
  81788. /** Directory where registry files are stored.
  81789. * @var string
  81790. */
  81791. var $statedir = '';
  81792. /** File where the file map is stored
  81793. * @var string
  81794. */
  81795. var $filemap = '';
  81796. /** Directory where registry files for channels are stored.
  81797. * @var string
  81798. */
  81799. var $channelsdir = '';
  81800. /** Name of file used for locking the registry
  81801. * @var string
  81802. */
  81803. var $lockfile = '';
  81804. /** File descriptor used during locking
  81805. * @var resource
  81806. */
  81807. var $lock_fp = null;
  81808. /** Mode used during locking
  81809. * @var int
  81810. */
  81811. var $lock_mode = 0; // XXX UNUSED
  81812. /** Cache of package information. Structure:
  81813. * array(
  81814. * 'package' => array('id' => ... ),
  81815. * ... )
  81816. * @var array
  81817. */
  81818. var $pkginfo_cache = array();
  81819. /** Cache of file map. Structure:
  81820. * array( '/path/to/file' => 'package', ... )
  81821. * @var array
  81822. */
  81823. var $filemap_cache = array();
  81824. /**
  81825. * @var false|PEAR_ChannelFile
  81826. */
  81827. var $_pearChannel;
  81828. /**
  81829. * @var false|PEAR_ChannelFile
  81830. */
  81831. var $_peclChannel;
  81832. /**
  81833. * @var false|PEAR_ChannelFile
  81834. */
  81835. var $_docChannel;
  81836. /**
  81837. * @var PEAR_DependencyDB
  81838. */
  81839. var $_dependencyDB;
  81840. /**
  81841. * @var PEAR_Config
  81842. */
  81843. var $_config;
  81844. /**
  81845. * PEAR_Registry constructor.
  81846. *
  81847. * @param string (optional) PEAR install directory (for .php files)
  81848. * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if
  81849. * default values are not desired. Only used the very first time a PEAR
  81850. * repository is initialized
  81851. * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if
  81852. * default values are not desired. Only used the very first time a PEAR
  81853. * repository is initialized
  81854. *
  81855. * @access public
  81856. */
  81857. function __construct($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,
  81858. $pecl_channel = false, $pear_metadata_dir = '')
  81859. {
  81860. parent::__construct();
  81861. $this->setInstallDir($pear_install_dir, $pear_metadata_dir);
  81862. $this->_pearChannel = $pear_channel;
  81863. $this->_peclChannel = $pecl_channel;
  81864. $this->_config = false;
  81865. }
  81866. function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR, $pear_metadata_dir = '')
  81867. {
  81868. $ds = DIRECTORY_SEPARATOR;
  81869. $this->install_dir = $pear_install_dir;
  81870. if (!$pear_metadata_dir) {
  81871. $pear_metadata_dir = $pear_install_dir;
  81872. }
  81873. $this->channelsdir = $pear_metadata_dir.$ds.'.channels';
  81874. $this->statedir = $pear_metadata_dir.$ds.'.registry';
  81875. $this->filemap = $pear_metadata_dir.$ds.'.filemap';
  81876. $this->lockfile = $pear_metadata_dir.$ds.'.lock';
  81877. }
  81878. function hasWriteAccess()
  81879. {
  81880. if (!file_exists($this->install_dir)) {
  81881. $dir = $this->install_dir;
  81882. while ($dir && $dir != '.') {
  81883. $olddir = $dir;
  81884. $dir = dirname($dir);
  81885. if ($dir != '.' && file_exists($dir)) {
  81886. if (is_writeable($dir)) {
  81887. return true;
  81888. }
  81889. return false;
  81890. }
  81891. if ($dir == $olddir) { // this can happen in safe mode
  81892. return @is_writable($dir);
  81893. }
  81894. }
  81895. return false;
  81896. }
  81897. return is_writeable($this->install_dir);
  81898. }
  81899. function setConfig(&$config, $resetInstallDir = true)
  81900. {
  81901. $this->_config = &$config;
  81902. if ($resetInstallDir) {
  81903. $this->setInstallDir($config->get('php_dir'), $config->get('metadata_dir'));
  81904. }
  81905. }
  81906. function _initializeChannelDirs()
  81907. {
  81908. static $running = false;
  81909. if (!$running) {
  81910. $running = true;
  81911. $ds = DIRECTORY_SEPARATOR;
  81912. if (!is_dir($this->channelsdir) ||
  81913. !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
  81914. !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
  81915. !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
  81916. !file_exists($this->channelsdir . $ds . '__uri.reg')) {
  81917. if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
  81918. $pear_channel = $this->_pearChannel;
  81919. if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) {
  81920. if (!class_exists('PEAR_ChannelFile')) {
  81921. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  81922. }
  81923. $pear_channel = new PEAR_ChannelFile;
  81924. $pear_channel->setAlias('pear');
  81925. $pear_channel->setServer('pear.php.net');
  81926. $pear_channel->setSummary('PHP Extension and Application Repository');
  81927. $pear_channel->setDefaultPEARProtocols();
  81928. $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
  81929. $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
  81930. $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
  81931. //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/');
  81932. } else {
  81933. $pear_channel->setServer('pear.php.net');
  81934. $pear_channel->setAlias('pear');
  81935. }
  81936. $pear_channel->validate();
  81937. $this->_addChannel($pear_channel);
  81938. }
  81939. if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) {
  81940. $pecl_channel = $this->_peclChannel;
  81941. if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) {
  81942. if (!class_exists('PEAR_ChannelFile')) {
  81943. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  81944. }
  81945. $pecl_channel = new PEAR_ChannelFile;
  81946. $pecl_channel->setAlias('pecl');
  81947. $pecl_channel->setServer('pecl.php.net');
  81948. $pecl_channel->setSummary('PHP Extension Community Library');
  81949. $pecl_channel->setDefaultPEARProtocols();
  81950. $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
  81951. $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
  81952. $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
  81953. } else {
  81954. $pecl_channel->setServer('pecl.php.net');
  81955. $pecl_channel->setAlias('pecl');
  81956. }
  81957. $pecl_channel->validate();
  81958. $this->_addChannel($pecl_channel);
  81959. }
  81960. if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) {
  81961. $doc_channel = $this->_docChannel;
  81962. if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) {
  81963. if (!class_exists('PEAR_ChannelFile')) {
  81964. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  81965. }
  81966. $doc_channel = new PEAR_ChannelFile;
  81967. $doc_channel->setAlias('phpdocs');
  81968. $doc_channel->setServer('doc.php.net');
  81969. $doc_channel->setSummary('PHP Documentation Team');
  81970. $doc_channel->setDefaultPEARProtocols();
  81971. $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
  81972. $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
  81973. $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
  81974. } else {
  81975. $doc_channel->setServer('doc.php.net');
  81976. $doc_channel->setAlias('doc');
  81977. }
  81978. $doc_channel->validate();
  81979. $this->_addChannel($doc_channel);
  81980. }
  81981. if (!file_exists($this->channelsdir . $ds . '__uri.reg')) {
  81982. if (!class_exists('PEAR_ChannelFile')) {
  81983. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  81984. }
  81985. $private = new PEAR_ChannelFile;
  81986. $private->setName('__uri');
  81987. $private->setDefaultPEARProtocols();
  81988. $private->setBaseURL('REST1.0', '****');
  81989. $private->setSummary('Pseudo-channel for static packages');
  81990. $this->_addChannel($private);
  81991. }
  81992. $this->_rebuildFileMap();
  81993. }
  81994. $running = false;
  81995. }
  81996. }
  81997. function _initializeDirs()
  81998. {
  81999. $ds = DIRECTORY_SEPARATOR;
  82000. // XXX Compatibility code should be removed in the future
  82001. // rename all registry files if any to lowercase
  82002. if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) &&
  82003. $handle = opendir($this->statedir)) {
  82004. $dest = $this->statedir . $ds;
  82005. while (false !== ($file = readdir($handle))) {
  82006. if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) {
  82007. rename($dest . $file, $dest . strtolower($file));
  82008. }
  82009. }
  82010. closedir($handle);
  82011. }
  82012. $this->_initializeChannelDirs();
  82013. if (!file_exists($this->filemap)) {
  82014. $this->_rebuildFileMap();
  82015. }
  82016. $this->_initializeDepDB();
  82017. }
  82018. function _initializeDepDB()
  82019. {
  82020. if (!isset($this->_dependencyDB)) {
  82021. static $initializing = false;
  82022. if (!$initializing) {
  82023. $initializing = true;
  82024. if (!$this->_config) { // never used?
  82025. $file = OS_WINDOWS ? 'pear.ini' : '.pearrc';
  82026. $this->_config = new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .
  82027. $file);
  82028. $this->_config->setRegistry($this);
  82029. $this->_config->set('php_dir', $this->install_dir);
  82030. }
  82031. $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
  82032. if (PEAR::isError($this->_dependencyDB)) {
  82033. // attempt to recover by removing the dep db
  82034. if (file_exists($this->_config->get('metadata_dir', null, 'pear.php.net') .
  82035. DIRECTORY_SEPARATOR . '.depdb')) {
  82036. @unlink($this->_config->get('metadata_dir', null, 'pear.php.net') .
  82037. DIRECTORY_SEPARATOR . '.depdb');
  82038. }
  82039. $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
  82040. if (PEAR::isError($this->_dependencyDB)) {
  82041. echo $this->_dependencyDB->getMessage();
  82042. echo 'Unrecoverable error';
  82043. exit(1);
  82044. }
  82045. }
  82046. $initializing = false;
  82047. }
  82048. }
  82049. }
  82050. /**
  82051. * PEAR_Registry destructor. Makes sure no locks are forgotten.
  82052. *
  82053. * @access private
  82054. */
  82055. function _PEAR_Registry()
  82056. {
  82057. parent::_PEAR();
  82058. if (is_resource($this->lock_fp)) {
  82059. $this->_unlock();
  82060. }
  82061. }
  82062. /**
  82063. * Make sure the directory where we keep registry files exists.
  82064. *
  82065. * @return bool TRUE if directory exists, FALSE if it could not be
  82066. * created
  82067. *
  82068. * @access private
  82069. */
  82070. function _assertStateDir($channel = false)
  82071. {
  82072. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
  82073. return $this->_assertChannelStateDir($channel);
  82074. }
  82075. static $init = false;
  82076. if (!file_exists($this->statedir)) {
  82077. if (!$this->hasWriteAccess()) {
  82078. return false;
  82079. }
  82080. require_once 'phar://go-pear.phar/' . 'System.php';
  82081. if (!System::mkdir(array('-p', $this->statedir))) {
  82082. return $this->raiseError("could not create directory '{$this->statedir}'");
  82083. }
  82084. $init = true;
  82085. } elseif (!is_dir($this->statedir)) {
  82086. return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' .
  82087. 'it already exists and is not a directory');
  82088. }
  82089. $ds = DIRECTORY_SEPARATOR;
  82090. if (!file_exists($this->channelsdir)) {
  82091. if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
  82092. !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
  82093. !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
  82094. !file_exists($this->channelsdir . $ds . '__uri.reg')) {
  82095. $init = true;
  82096. }
  82097. } elseif (!is_dir($this->channelsdir)) {
  82098. return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' .
  82099. 'it already exists and is not a directory');
  82100. }
  82101. if ($init) {
  82102. static $running = false;
  82103. if (!$running) {
  82104. $running = true;
  82105. $this->_initializeDirs();
  82106. $running = false;
  82107. $init = false;
  82108. }
  82109. } else {
  82110. $this->_initializeDepDB();
  82111. }
  82112. return true;
  82113. }
  82114. /**
  82115. * Make sure the directory where we keep registry files exists for a non-standard channel.
  82116. *
  82117. * @param string channel name
  82118. * @return bool TRUE if directory exists, FALSE if it could not be
  82119. * created
  82120. *
  82121. * @access private
  82122. */
  82123. function _assertChannelStateDir($channel)
  82124. {
  82125. $ds = DIRECTORY_SEPARATOR;
  82126. if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
  82127. if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
  82128. $this->_initializeChannelDirs();
  82129. }
  82130. return $this->_assertStateDir($channel);
  82131. }
  82132. $channelDir = $this->_channelDirectoryName($channel);
  82133. if (!is_dir($this->channelsdir) ||
  82134. !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
  82135. $this->_initializeChannelDirs();
  82136. }
  82137. if (!file_exists($channelDir)) {
  82138. if (!$this->hasWriteAccess()) {
  82139. return false;
  82140. }
  82141. require_once 'phar://go-pear.phar/' . 'System.php';
  82142. if (!System::mkdir(array('-p', $channelDir))) {
  82143. return $this->raiseError("could not create directory '" . $channelDir .
  82144. "'");
  82145. }
  82146. } elseif (!is_dir($channelDir)) {
  82147. return $this->raiseError("could not create directory '" . $channelDir .
  82148. "', already exists and is not a directory");
  82149. }
  82150. return true;
  82151. }
  82152. /**
  82153. * Make sure the directory where we keep registry files for channels exists
  82154. *
  82155. * @return bool TRUE if directory exists, FALSE if it could not be
  82156. * created
  82157. *
  82158. * @access private
  82159. */
  82160. function _assertChannelDir()
  82161. {
  82162. if (!file_exists($this->channelsdir)) {
  82163. if (!$this->hasWriteAccess()) {
  82164. return false;
  82165. }
  82166. require_once 'phar://go-pear.phar/' . 'System.php';
  82167. if (!System::mkdir(array('-p', $this->channelsdir))) {
  82168. return $this->raiseError("could not create directory '{$this->channelsdir}'");
  82169. }
  82170. } elseif (!is_dir($this->channelsdir)) {
  82171. return $this->raiseError("could not create directory '{$this->channelsdir}" .
  82172. "', it already exists and is not a directory");
  82173. }
  82174. if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
  82175. if (!$this->hasWriteAccess()) {
  82176. return false;
  82177. }
  82178. require_once 'phar://go-pear.phar/' . 'System.php';
  82179. if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {
  82180. return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
  82181. }
  82182. } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
  82183. return $this->raiseError("could not create directory '{$this->channelsdir}" .
  82184. "/.alias', it already exists and is not a directory");
  82185. }
  82186. return true;
  82187. }
  82188. /**
  82189. * Get the name of the file where data for a given package is stored.
  82190. *
  82191. * @param string channel name, or false if this is a PEAR package
  82192. * @param string package name
  82193. *
  82194. * @return string registry file name
  82195. *
  82196. * @access public
  82197. */
  82198. function _packageFileName($package, $channel = false)
  82199. {
  82200. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
  82201. return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR .
  82202. strtolower($package) . '.reg';
  82203. }
  82204. return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
  82205. }
  82206. /**
  82207. * Get the name of the file where data for a given channel is stored.
  82208. * @param string channel name
  82209. * @return string registry file name
  82210. */
  82211. function _channelFileName($channel, $noaliases = false)
  82212. {
  82213. if (!$noaliases) {
  82214. if (file_exists($this->_getChannelAliasFileName($channel))) {
  82215. $channel = implode('', file($this->_getChannelAliasFileName($channel)));
  82216. }
  82217. }
  82218. return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_',
  82219. strtolower($channel)) . '.reg';
  82220. }
  82221. /**
  82222. * @param string
  82223. * @return string
  82224. */
  82225. function _getChannelAliasFileName($alias)
  82226. {
  82227. return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .
  82228. DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';
  82229. }
  82230. /**
  82231. * Get the name of a channel from its alias
  82232. */
  82233. function _getChannelFromAlias($channel)
  82234. {
  82235. if (!$this->_channelExists($channel)) {
  82236. if ($channel == 'pear.php.net') {
  82237. return 'pear.php.net';
  82238. }
  82239. if ($channel == 'pecl.php.net') {
  82240. return 'pecl.php.net';
  82241. }
  82242. if ($channel == 'doc.php.net') {
  82243. return 'doc.php.net';
  82244. }
  82245. if ($channel == '__uri') {
  82246. return '__uri';
  82247. }
  82248. return false;
  82249. }
  82250. $channel = strtolower($channel);
  82251. if (file_exists($this->_getChannelAliasFileName($channel))) {
  82252. // translate an alias to an actual channel
  82253. return implode('', file($this->_getChannelAliasFileName($channel)));
  82254. }
  82255. return $channel;
  82256. }
  82257. /**
  82258. * Get the alias of a channel from its alias or its name
  82259. */
  82260. function _getAlias($channel)
  82261. {
  82262. if (!$this->_channelExists($channel)) {
  82263. if ($channel == 'pear.php.net') {
  82264. return 'pear';
  82265. }
  82266. if ($channel == 'pecl.php.net') {
  82267. return 'pecl';
  82268. }
  82269. if ($channel == 'doc.php.net') {
  82270. return 'phpdocs';
  82271. }
  82272. return false;
  82273. }
  82274. $channel = $this->_getChannel($channel);
  82275. if (PEAR::isError($channel)) {
  82276. return $channel;
  82277. }
  82278. return $channel->getAlias();
  82279. }
  82280. /**
  82281. * Get the name of the file where data for a given package is stored.
  82282. *
  82283. * @param string channel name, or false if this is a PEAR package
  82284. * @param string package name
  82285. *
  82286. * @return string registry file name
  82287. *
  82288. * @access public
  82289. */
  82290. function _channelDirectoryName($channel)
  82291. {
  82292. if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
  82293. return $this->statedir;
  82294. }
  82295. $ch = $this->_getChannelFromAlias($channel);
  82296. if (!$ch) {
  82297. $ch = $channel;
  82298. }
  82299. return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .
  82300. str_replace('/', '_', $ch));
  82301. }
  82302. function _openPackageFile($package, $mode, $channel = false)
  82303. {
  82304. if (!$this->_assertStateDir($channel)) {
  82305. return null;
  82306. }
  82307. if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
  82308. return null;
  82309. }
  82310. $file = $this->_packageFileName($package, $channel);
  82311. if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
  82312. return null;
  82313. }
  82314. $fp = @fopen($file, $mode);
  82315. if (!$fp) {
  82316. return null;
  82317. }
  82318. return $fp;
  82319. }
  82320. function _closePackageFile($fp)
  82321. {
  82322. fclose($fp);
  82323. }
  82324. function _openChannelFile($channel, $mode)
  82325. {
  82326. if (!$this->_assertChannelDir()) {
  82327. return null;
  82328. }
  82329. if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
  82330. return null;
  82331. }
  82332. $file = $this->_channelFileName($channel);
  82333. if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
  82334. return null;
  82335. }
  82336. $fp = @fopen($file, $mode);
  82337. if (!$fp) {
  82338. return null;
  82339. }
  82340. return $fp;
  82341. }
  82342. function _closeChannelFile($fp)
  82343. {
  82344. fclose($fp);
  82345. }
  82346. function _rebuildFileMap()
  82347. {
  82348. if (!class_exists('PEAR_Installer_Role')) {
  82349. require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php';
  82350. }
  82351. $channels = $this->_listAllPackages();
  82352. $files = array();
  82353. foreach ($channels as $channel => $packages) {
  82354. foreach ($packages as $package) {
  82355. $version = $this->_packageInfo($package, 'version', $channel);
  82356. $filelist = $this->_packageInfo($package, 'filelist', $channel);
  82357. if (!is_array($filelist)) {
  82358. continue;
  82359. }
  82360. foreach ($filelist as $name => $attrs) {
  82361. if (isset($attrs['attribs'])) {
  82362. $attrs = $attrs['attribs'];
  82363. }
  82364. // it is possible for conflicting packages in different channels to
  82365. // conflict with data files/doc files
  82366. if ($name == 'dirtree') {
  82367. continue;
  82368. }
  82369. if (isset($attrs['role']) && !in_array($attrs['role'],
  82370. PEAR_Installer_Role::getInstallableRoles())) {
  82371. // these are not installed
  82372. continue;
  82373. }
  82374. if (isset($attrs['role']) && !in_array($attrs['role'],
  82375. PEAR_Installer_Role::getBaseinstallRoles())) {
  82376. $attrs['baseinstalldir'] = $package;
  82377. }
  82378. if (isset($attrs['baseinstalldir'])) {
  82379. $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
  82380. } else {
  82381. $file = $name;
  82382. }
  82383. $file = preg_replace(',^/+,', '', $file);
  82384. if ($channel != 'pear.php.net') {
  82385. if (!isset($files[$attrs['role']])) {
  82386. $files[$attrs['role']] = array();
  82387. }
  82388. $files[$attrs['role']][$file] = array(strtolower($channel),
  82389. strtolower($package));
  82390. } else {
  82391. if (!isset($files[$attrs['role']])) {
  82392. $files[$attrs['role']] = array();
  82393. }
  82394. $files[$attrs['role']][$file] = strtolower($package);
  82395. }
  82396. }
  82397. }
  82398. }
  82399. $this->_assertStateDir();
  82400. if (!$this->hasWriteAccess()) {
  82401. return false;
  82402. }
  82403. $fp = @fopen($this->filemap, 'wb');
  82404. if (!$fp) {
  82405. return false;
  82406. }
  82407. $this->filemap_cache = $files;
  82408. fwrite($fp, serialize($files));
  82409. fclose($fp);
  82410. return true;
  82411. }
  82412. function _readFileMap()
  82413. {
  82414. if (!file_exists($this->filemap)) {
  82415. return array();
  82416. }
  82417. $fp = @fopen($this->filemap, 'r');
  82418. if (!$fp) {
  82419. return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
  82420. }
  82421. clearstatcache();
  82422. $fsize = filesize($this->filemap);
  82423. fclose($fp);
  82424. $data = file_get_contents($this->filemap);
  82425. $tmp = unserialize($data);
  82426. if (!$tmp && $fsize > 7) {
  82427. return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
  82428. }
  82429. $this->filemap_cache = $tmp;
  82430. return true;
  82431. }
  82432. /**
  82433. * Lock the registry.
  82434. *
  82435. * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
  82436. * See flock manual for more information.
  82437. *
  82438. * @return bool TRUE on success, FALSE if locking failed, or a
  82439. * PEAR error if some other error occurs (such as the
  82440. * lock file not being writable).
  82441. *
  82442. * @access private
  82443. */
  82444. function _lock($mode = LOCK_EX)
  82445. {
  82446. if (stristr(php_uname(), 'Windows 9')) {
  82447. return true;
  82448. }
  82449. if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
  82450. // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  82451. return true;
  82452. }
  82453. if (!$this->_assertStateDir()) {
  82454. if ($mode == LOCK_EX) {
  82455. return $this->raiseError('Registry directory is not writeable by the current user');
  82456. }
  82457. return true;
  82458. }
  82459. $open_mode = 'w';
  82460. // XXX People reported problems with LOCK_SH and 'w'
  82461. if ($mode === LOCK_SH || $mode === LOCK_UN) {
  82462. if (!file_exists($this->lockfile)) {
  82463. touch($this->lockfile);
  82464. }
  82465. $open_mode = 'r';
  82466. }
  82467. if (!is_resource($this->lock_fp)) {
  82468. $this->lock_fp = @fopen($this->lockfile, $open_mode);
  82469. }
  82470. if (!is_resource($this->lock_fp)) {
  82471. $this->lock_fp = null;
  82472. return $this->raiseError("could not create lock file" .
  82473. (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  82474. }
  82475. if (!(int)flock($this->lock_fp, $mode)) {
  82476. switch ($mode) {
  82477. case LOCK_SH: $str = 'shared'; break;
  82478. case LOCK_EX: $str = 'exclusive'; break;
  82479. case LOCK_UN: $str = 'unlock'; break;
  82480. default: $str = 'unknown'; break;
  82481. }
  82482. //is resource at this point, close it on error.
  82483. fclose($this->lock_fp);
  82484. $this->lock_fp = null;
  82485. return $this->raiseError("could not acquire $str lock ($this->lockfile)",
  82486. PEAR_REGISTRY_ERROR_LOCK);
  82487. }
  82488. return true;
  82489. }
  82490. function _unlock()
  82491. {
  82492. $ret = $this->_lock(LOCK_UN);
  82493. if (is_resource($this->lock_fp)) {
  82494. fclose($this->lock_fp);
  82495. }
  82496. $this->lock_fp = null;
  82497. return $ret;
  82498. }
  82499. function _packageExists($package, $channel = false)
  82500. {
  82501. return file_exists($this->_packageFileName($package, $channel));
  82502. }
  82503. /**
  82504. * Determine whether a channel exists in the registry
  82505. *
  82506. * @param string Channel name
  82507. * @param bool if true, then aliases will be ignored
  82508. * @return boolean
  82509. */
  82510. function _channelExists($channel, $noaliases = false)
  82511. {
  82512. $a = file_exists($this->_channelFileName($channel, $noaliases));
  82513. if (!$a && $channel == 'pear.php.net') {
  82514. return true;
  82515. }
  82516. if (!$a && $channel == 'pecl.php.net') {
  82517. return true;
  82518. }
  82519. if (!$a && $channel == 'doc.php.net') {
  82520. return true;
  82521. }
  82522. return $a;
  82523. }
  82524. /**
  82525. * Determine whether a mirror exists within the default channel in the registry
  82526. *
  82527. * @param string Channel name
  82528. * @param string Mirror name
  82529. *
  82530. * @return boolean
  82531. */
  82532. function _mirrorExists($channel, $mirror)
  82533. {
  82534. $data = $this->_channelInfo($channel);
  82535. if (!isset($data['servers']['mirror'])) {
  82536. return false;
  82537. }
  82538. foreach ($data['servers']['mirror'] as $m) {
  82539. if ($m['attribs']['host'] == $mirror) {
  82540. return true;
  82541. }
  82542. }
  82543. return false;
  82544. }
  82545. /**
  82546. * @param PEAR_ChannelFile Channel object
  82547. * @param donotuse
  82548. * @param string Last-Modified HTTP tag from remote request
  82549. * @return boolean|PEAR_Error True on creation, false if it already exists
  82550. */
  82551. function _addChannel($channel, $update = false, $lastmodified = false)
  82552. {
  82553. if (!is_a($channel, 'PEAR_ChannelFile')) {
  82554. return false;
  82555. }
  82556. if (!$channel->validate()) {
  82557. return false;
  82558. }
  82559. if (file_exists($this->_channelFileName($channel->getName()))) {
  82560. if (!$update) {
  82561. return false;
  82562. }
  82563. $checker = $this->_getChannel($channel->getName());
  82564. if (PEAR::isError($checker)) {
  82565. return $checker;
  82566. }
  82567. if ($channel->getAlias() != $checker->getAlias()) {
  82568. if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) {
  82569. @unlink($this->_getChannelAliasFileName($checker->getAlias()));
  82570. }
  82571. }
  82572. } else {
  82573. if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) {
  82574. return false;
  82575. }
  82576. }
  82577. $ret = $this->_assertChannelDir();
  82578. if (PEAR::isError($ret)) {
  82579. return $ret;
  82580. }
  82581. $ret = $this->_assertChannelStateDir($channel->getName());
  82582. if (PEAR::isError($ret)) {
  82583. return $ret;
  82584. }
  82585. if ($channel->getAlias() != $channel->getName()) {
  82586. if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&
  82587. $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {
  82588. $channel->setAlias($channel->getName());
  82589. }
  82590. if (!$this->hasWriteAccess()) {
  82591. return false;
  82592. }
  82593. $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');
  82594. if (!$fp) {
  82595. return false;
  82596. }
  82597. fwrite($fp, $channel->getName());
  82598. fclose($fp);
  82599. }
  82600. if (!$this->hasWriteAccess()) {
  82601. return false;
  82602. }
  82603. $fp = @fopen($this->_channelFileName($channel->getName()), 'wb');
  82604. if (!$fp) {
  82605. return false;
  82606. }
  82607. $info = $channel->toArray();
  82608. if ($lastmodified) {
  82609. $info['_lastmodified'] = $lastmodified;
  82610. } else {
  82611. $info['_lastmodified'] = self::getSourceDateEpoch();
  82612. }
  82613. fwrite($fp, serialize($info));
  82614. fclose($fp);
  82615. return true;
  82616. }
  82617. /**
  82618. * Deletion fails if there are any packages installed from the channel
  82619. * @param string|PEAR_ChannelFile channel name
  82620. * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
  82621. */
  82622. function _deleteChannel($channel)
  82623. {
  82624. if (!is_string($channel)) {
  82625. if (!is_a($channel, 'PEAR_ChannelFile')) {
  82626. return false;
  82627. }
  82628. if (!$channel->validate()) {
  82629. return false;
  82630. }
  82631. $channel = $channel->getName();
  82632. }
  82633. if ($this->_getChannelFromAlias($channel) == '__uri') {
  82634. return false;
  82635. }
  82636. if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
  82637. return false;
  82638. }
  82639. if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
  82640. return false;
  82641. }
  82642. if (!$this->_channelExists($channel)) {
  82643. return false;
  82644. }
  82645. if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
  82646. return false;
  82647. }
  82648. $channel = $this->_getChannelFromAlias($channel);
  82649. if ($channel == 'pear.php.net') {
  82650. return false;
  82651. }
  82652. $test = $this->_listChannelPackages($channel);
  82653. if (count($test)) {
  82654. return false;
  82655. }
  82656. $test = @rmdir($this->_channelDirectoryName($channel));
  82657. if (!$test) {
  82658. return false;
  82659. }
  82660. $file = $this->_getChannelAliasFileName($this->_getAlias($channel));
  82661. if (file_exists($file)) {
  82662. $test = @unlink($file);
  82663. if (!$test) {
  82664. return false;
  82665. }
  82666. }
  82667. $file = $this->_channelFileName($channel);
  82668. $ret = true;
  82669. if (file_exists($file)) {
  82670. $ret = @unlink($file);
  82671. }
  82672. return $ret;
  82673. }
  82674. /**
  82675. * Determine whether a channel exists in the registry
  82676. * @param string Channel Alias
  82677. * @return boolean
  82678. */
  82679. function _isChannelAlias($alias)
  82680. {
  82681. return file_exists($this->_getChannelAliasFileName($alias));
  82682. }
  82683. /**
  82684. * @param string|null
  82685. * @param string|null
  82686. * @param string|null
  82687. * @return array|null
  82688. * @access private
  82689. */
  82690. function _packageInfo($package = null, $key = null, $channel = 'pear.php.net')
  82691. {
  82692. if ($package === null) {
  82693. if ($channel === null) {
  82694. $channels = $this->_listChannels();
  82695. $ret = array();
  82696. foreach ($channels as $channel) {
  82697. $channel = strtolower($channel);
  82698. $ret[$channel] = array();
  82699. $packages = $this->_listPackages($channel);
  82700. foreach ($packages as $package) {
  82701. $ret[$channel][] = $this->_packageInfo($package, null, $channel);
  82702. }
  82703. }
  82704. return $ret;
  82705. }
  82706. $ps = $this->_listPackages($channel);
  82707. if (!count($ps)) {
  82708. return array();
  82709. }
  82710. return array_map(array(&$this, '_packageInfo'),
  82711. $ps, array_fill(0, count($ps), null),
  82712. array_fill(0, count($ps), $channel));
  82713. }
  82714. $fp = $this->_openPackageFile($package, 'r', $channel);
  82715. if ($fp === null) {
  82716. return null;
  82717. }
  82718. clearstatcache();
  82719. $this->_closePackageFile($fp);
  82720. $data = file_get_contents($this->_packageFileName($package, $channel));
  82721. $data = unserialize($data);
  82722. if ($key === null) {
  82723. return $data;
  82724. }
  82725. // compatibility for package.xml version 2.0
  82726. if (isset($data['old'][$key])) {
  82727. return $data['old'][$key];
  82728. }
  82729. if (isset($data[$key])) {
  82730. return $data[$key];
  82731. }
  82732. return null;
  82733. }
  82734. /**
  82735. * @param string Channel name
  82736. * @param bool whether to strictly retrieve info of channels, not just aliases
  82737. * @return array|null
  82738. */
  82739. function _channelInfo($channel, $noaliases = false)
  82740. {
  82741. if (!$this->_channelExists($channel, $noaliases)) {
  82742. return null;
  82743. }
  82744. $fp = $this->_openChannelFile($channel, 'r');
  82745. if ($fp === null) {
  82746. return null;
  82747. }
  82748. clearstatcache();
  82749. $this->_closeChannelFile($fp);
  82750. $data = file_get_contents($this->_channelFileName($channel));
  82751. $data = unserialize($data);
  82752. return $data;
  82753. }
  82754. function _listChannels()
  82755. {
  82756. $channellist = array();
  82757. if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) {
  82758. return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri');
  82759. }
  82760. $dp = opendir($this->channelsdir);
  82761. while ($ent = readdir($dp)) {
  82762. if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
  82763. continue;
  82764. }
  82765. if ($ent == '__uri.reg') {
  82766. $channellist[] = '__uri';
  82767. continue;
  82768. }
  82769. $channellist[] = str_replace('_', '/', substr($ent, 0, -4));
  82770. }
  82771. closedir($dp);
  82772. if (!in_array('pear.php.net', $channellist)) {
  82773. $channellist[] = 'pear.php.net';
  82774. }
  82775. if (!in_array('pecl.php.net', $channellist)) {
  82776. $channellist[] = 'pecl.php.net';
  82777. }
  82778. if (!in_array('doc.php.net', $channellist)) {
  82779. $channellist[] = 'doc.php.net';
  82780. }
  82781. if (!in_array('__uri', $channellist)) {
  82782. $channellist[] = '__uri';
  82783. }
  82784. natsort($channellist);
  82785. return $channellist;
  82786. }
  82787. function _listPackages($channel = false)
  82788. {
  82789. if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
  82790. return $this->_listChannelPackages($channel);
  82791. }
  82792. if (!file_exists($this->statedir) || !is_dir($this->statedir)) {
  82793. return array();
  82794. }
  82795. $pkglist = array();
  82796. $dp = opendir($this->statedir);
  82797. if (!$dp) {
  82798. return $pkglist;
  82799. }
  82800. while ($ent = readdir($dp)) {
  82801. if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
  82802. continue;
  82803. }
  82804. $pkglist[] = substr($ent, 0, -4);
  82805. }
  82806. closedir($dp);
  82807. return $pkglist;
  82808. }
  82809. function _listChannelPackages($channel)
  82810. {
  82811. $pkglist = array();
  82812. if (!file_exists($this->_channelDirectoryName($channel)) ||
  82813. !is_dir($this->_channelDirectoryName($channel))) {
  82814. return array();
  82815. }
  82816. $dp = opendir($this->_channelDirectoryName($channel));
  82817. if (!$dp) {
  82818. return $pkglist;
  82819. }
  82820. while ($ent = readdir($dp)) {
  82821. if ($ent[0] == '.' || substr($ent, -4) != '.reg') {
  82822. continue;
  82823. }
  82824. $pkglist[] = substr($ent, 0, -4);
  82825. }
  82826. closedir($dp);
  82827. return $pkglist;
  82828. }
  82829. function _listAllPackages()
  82830. {
  82831. $ret = array();
  82832. foreach ($this->_listChannels() as $channel) {
  82833. $ret[$channel] = $this->_listPackages($channel);
  82834. }
  82835. return $ret;
  82836. }
  82837. /**
  82838. * Add an installed package to the registry
  82839. * @param string package name
  82840. * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  82841. * @return bool success of saving
  82842. * @access private
  82843. */
  82844. function _addPackage($package, $info)
  82845. {
  82846. if ($this->_packageExists($package)) {
  82847. return false;
  82848. }
  82849. $fp = $this->_openPackageFile($package, 'wb');
  82850. if ($fp === null) {
  82851. return false;
  82852. }
  82853. $info['_lastmodified'] = self::getSourceDateEpoch();
  82854. fwrite($fp, serialize($info));
  82855. $this->_closePackageFile($fp);
  82856. if (isset($info['filelist'])) {
  82857. $this->_rebuildFileMap();
  82858. }
  82859. return true;
  82860. }
  82861. /**
  82862. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  82863. * @return bool
  82864. * @access private
  82865. */
  82866. function _addPackage2($info)
  82867. {
  82868. if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) {
  82869. return false;
  82870. }
  82871. if (!$info->validate()) {
  82872. if (class_exists('PEAR_Common')) {
  82873. $ui = PEAR_Frontend::singleton();
  82874. if ($ui) {
  82875. foreach ($info->getValidationWarnings() as $err) {
  82876. $ui->log($err['message'], true);
  82877. }
  82878. }
  82879. }
  82880. return false;
  82881. }
  82882. $channel = $info->getChannel();
  82883. $package = $info->getPackage();
  82884. $save = $info;
  82885. if ($this->_packageExists($package, $channel)) {
  82886. return false;
  82887. }
  82888. if (!$this->_channelExists($channel, true)) {
  82889. return false;
  82890. }
  82891. $info = $info->toArray(true);
  82892. if (!$info) {
  82893. return false;
  82894. }
  82895. $fp = $this->_openPackageFile($package, 'wb', $channel);
  82896. if ($fp === null) {
  82897. return false;
  82898. }
  82899. $info['_lastmodified'] = self::getSourceDateEpoch();
  82900. fwrite($fp, serialize($info));
  82901. $this->_closePackageFile($fp);
  82902. $this->_rebuildFileMap();
  82903. return true;
  82904. }
  82905. /**
  82906. * @param string Package name
  82907. * @param array parsed package.xml 1.0
  82908. * @param bool this parameter is only here for BC. Don't use it.
  82909. * @access private
  82910. */
  82911. function _updatePackage($package, $info, $merge = true)
  82912. {
  82913. $oldinfo = $this->_packageInfo($package);
  82914. if (empty($oldinfo)) {
  82915. return false;
  82916. }
  82917. $fp = $this->_openPackageFile($package, 'w');
  82918. if ($fp === null) {
  82919. return false;
  82920. }
  82921. if (is_object($info)) {
  82922. $info = $info->toArray();
  82923. }
  82924. $info['_lastmodified'] = self::getSourceDateEpoch();
  82925. $newinfo = $info;
  82926. if ($merge) {
  82927. $info = array_merge($oldinfo, $info);
  82928. } else {
  82929. $diff = $info;
  82930. }
  82931. fwrite($fp, serialize($info));
  82932. $this->_closePackageFile($fp);
  82933. if (isset($newinfo['filelist'])) {
  82934. $this->_rebuildFileMap();
  82935. }
  82936. return true;
  82937. }
  82938. /**
  82939. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  82940. * @return bool
  82941. * @access private
  82942. */
  82943. function _updatePackage2($info)
  82944. {
  82945. if (!$this->_packageExists($info->getPackage(), $info->getChannel())) {
  82946. return false;
  82947. }
  82948. $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());
  82949. if ($fp === null) {
  82950. return false;
  82951. }
  82952. $save = $info;
  82953. $info = $save->getArray(true);
  82954. $info['_lastmodified'] = self::getSourceDateEpoch();
  82955. fwrite($fp, serialize($info));
  82956. $this->_closePackageFile($fp);
  82957. $this->_rebuildFileMap();
  82958. return true;
  82959. }
  82960. /**
  82961. * @param string Package name
  82962. * @param string Channel name
  82963. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  82964. * @access private
  82965. */
  82966. function &_getPackage($package, $channel = 'pear.php.net')
  82967. {
  82968. $info = $this->_packageInfo($package, null, $channel);
  82969. if ($info === null) {
  82970. return $info;
  82971. }
  82972. $a = $this->_config;
  82973. if (!$a) {
  82974. $this->_config = new PEAR_Config;
  82975. $this->_config->set('php_dir', $this->statedir);
  82976. }
  82977. if (!class_exists('PEAR_PackageFile')) {
  82978. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile.php';
  82979. }
  82980. $pkg = new PEAR_PackageFile($this->_config);
  82981. $pf = &$pkg->fromArray($info);
  82982. return $pf;
  82983. }
  82984. /**
  82985. * @param string channel name
  82986. * @param bool whether to strictly retrieve channel names
  82987. * @return PEAR_ChannelFile|PEAR_Error
  82988. * @access private
  82989. */
  82990. function &_getChannel($channel, $noaliases = false)
  82991. {
  82992. $ch = false;
  82993. if ($this->_channelExists($channel, $noaliases)) {
  82994. $chinfo = $this->_channelInfo($channel, $noaliases);
  82995. if ($chinfo) {
  82996. if (!class_exists('PEAR_ChannelFile')) {
  82997. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  82998. }
  82999. $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo);
  83000. }
  83001. }
  83002. if ($ch) {
  83003. if ($ch->validate()) {
  83004. return $ch;
  83005. }
  83006. foreach ($ch->getErrors(true) as $err) {
  83007. $message = $err['message'] . "\n";
  83008. }
  83009. $ch = PEAR::raiseError($message);
  83010. return $ch;
  83011. }
  83012. if ($this->_getChannelFromAlias($channel) == 'pear.php.net') {
  83013. // the registry is not properly set up, so use defaults
  83014. if (!class_exists('PEAR_ChannelFile')) {
  83015. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  83016. }
  83017. $pear_channel = new PEAR_ChannelFile;
  83018. $pear_channel->setServer('pear.php.net');
  83019. $pear_channel->setAlias('pear');
  83020. $pear_channel->setSummary('PHP Extension and Application Repository');
  83021. $pear_channel->setDefaultPEARProtocols();
  83022. $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
  83023. $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
  83024. $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
  83025. return $pear_channel;
  83026. }
  83027. if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
  83028. // the registry is not properly set up, so use defaults
  83029. if (!class_exists('PEAR_ChannelFile')) {
  83030. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  83031. }
  83032. $pear_channel = new PEAR_ChannelFile;
  83033. $pear_channel->setServer('pecl.php.net');
  83034. $pear_channel->setAlias('pecl');
  83035. $pear_channel->setSummary('PHP Extension Community Library');
  83036. $pear_channel->setDefaultPEARProtocols();
  83037. $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
  83038. $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
  83039. $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
  83040. return $pear_channel;
  83041. }
  83042. if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
  83043. // the registry is not properly set up, so use defaults
  83044. if (!class_exists('PEAR_ChannelFile')) {
  83045. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  83046. }
  83047. $doc_channel = new PEAR_ChannelFile;
  83048. $doc_channel->setServer('doc.php.net');
  83049. $doc_channel->setAlias('phpdocs');
  83050. $doc_channel->setSummary('PHP Documentation Team');
  83051. $doc_channel->setDefaultPEARProtocols();
  83052. $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
  83053. $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
  83054. $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
  83055. return $doc_channel;
  83056. }
  83057. if ($this->_getChannelFromAlias($channel) == '__uri') {
  83058. // the registry is not properly set up, so use defaults
  83059. if (!class_exists('PEAR_ChannelFile')) {
  83060. require_once 'phar://go-pear.phar/' . 'PEAR/ChannelFile.php';
  83061. }
  83062. $private = new PEAR_ChannelFile;
  83063. $private->setName('__uri');
  83064. $private->setDefaultPEARProtocols();
  83065. $private->setBaseURL('REST1.0', '****');
  83066. $private->setSummary('Pseudo-channel for static packages');
  83067. return $private;
  83068. }
  83069. return $ch;
  83070. }
  83071. /**
  83072. * @param string Package name
  83073. * @param string Channel name
  83074. * @return bool
  83075. */
  83076. function packageExists($package, $channel = 'pear.php.net')
  83077. {
  83078. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83079. return $e;
  83080. }
  83081. $ret = $this->_packageExists($package, $channel);
  83082. $this->_unlock();
  83083. return $ret;
  83084. }
  83085. // }}}
  83086. // {{{ channelExists()
  83087. /**
  83088. * @param string channel name
  83089. * @param bool if true, then aliases will be ignored
  83090. * @return bool
  83091. */
  83092. function channelExists($channel, $noaliases = false)
  83093. {
  83094. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83095. return $e;
  83096. }
  83097. $ret = $this->_channelExists($channel, $noaliases);
  83098. $this->_unlock();
  83099. return $ret;
  83100. }
  83101. // }}}
  83102. /**
  83103. * @param string channel name mirror is in
  83104. * @param string mirror name
  83105. *
  83106. * @return bool
  83107. */
  83108. function mirrorExists($channel, $mirror)
  83109. {
  83110. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83111. return $e;
  83112. }
  83113. $ret = $this->_mirrorExists($channel, $mirror);
  83114. $this->_unlock();
  83115. return $ret;
  83116. }
  83117. // {{{ isAlias()
  83118. /**
  83119. * Determines whether the parameter is an alias of a channel
  83120. * @param string
  83121. * @return bool
  83122. */
  83123. function isAlias($alias)
  83124. {
  83125. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83126. return $e;
  83127. }
  83128. $ret = $this->_isChannelAlias($alias);
  83129. $this->_unlock();
  83130. return $ret;
  83131. }
  83132. // }}}
  83133. // {{{ packageInfo()
  83134. /**
  83135. * @param string|null
  83136. * @param string|null
  83137. * @param string
  83138. * @return array|null
  83139. */
  83140. function packageInfo($package = null, $key = null, $channel = 'pear.php.net')
  83141. {
  83142. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83143. return $e;
  83144. }
  83145. $ret = $this->_packageInfo($package, $key, $channel);
  83146. $this->_unlock();
  83147. return $ret;
  83148. }
  83149. // }}}
  83150. // {{{ channelInfo()
  83151. /**
  83152. * Retrieve a raw array of channel data.
  83153. *
  83154. * Do not use this, instead use {@link getChannel()} for normal
  83155. * operations. Array structure is undefined in this method
  83156. * @param string channel name
  83157. * @param bool whether to strictly retrieve information only on non-aliases
  83158. * @return array|null|PEAR_Error
  83159. */
  83160. function channelInfo($channel = null, $noaliases = false)
  83161. {
  83162. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83163. return $e;
  83164. }
  83165. $ret = $this->_channelInfo($channel, $noaliases);
  83166. $this->_unlock();
  83167. return $ret;
  83168. }
  83169. // }}}
  83170. /**
  83171. * @param string
  83172. */
  83173. function channelName($channel)
  83174. {
  83175. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83176. return $e;
  83177. }
  83178. $ret = $this->_getChannelFromAlias($channel);
  83179. $this->_unlock();
  83180. return $ret;
  83181. }
  83182. /**
  83183. * @param string
  83184. */
  83185. function channelAlias($channel)
  83186. {
  83187. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83188. return $e;
  83189. }
  83190. $ret = $this->_getAlias($channel);
  83191. $this->_unlock();
  83192. return $ret;
  83193. }
  83194. // {{{ listPackages()
  83195. function listPackages($channel = false)
  83196. {
  83197. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83198. return $e;
  83199. }
  83200. $ret = $this->_listPackages($channel);
  83201. $this->_unlock();
  83202. return $ret;
  83203. }
  83204. // }}}
  83205. // {{{ listAllPackages()
  83206. function listAllPackages()
  83207. {
  83208. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83209. return $e;
  83210. }
  83211. $ret = $this->_listAllPackages();
  83212. $this->_unlock();
  83213. return $ret;
  83214. }
  83215. // }}}
  83216. // {{{ listChannel()
  83217. function listChannels()
  83218. {
  83219. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83220. return $e;
  83221. }
  83222. $ret = $this->_listChannels();
  83223. $this->_unlock();
  83224. return $ret;
  83225. }
  83226. // }}}
  83227. // {{{ addPackage()
  83228. /**
  83229. * Add an installed package to the registry
  83230. * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object
  83231. * that will be passed to {@link addPackage2()}
  83232. * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
  83233. * @return bool success of saving
  83234. */
  83235. function addPackage($package, $info)
  83236. {
  83237. if (is_object($info)) {
  83238. return $this->addPackage2($info);
  83239. }
  83240. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83241. return $e;
  83242. }
  83243. $ret = $this->_addPackage($package, $info);
  83244. $this->_unlock();
  83245. if ($ret) {
  83246. if (!class_exists('PEAR_PackageFile_v1')) {
  83247. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  83248. }
  83249. $pf = new PEAR_PackageFile_v1;
  83250. $pf->setConfig($this->_config);
  83251. $pf->fromArray($info);
  83252. $this->_dependencyDB->uninstallPackage($pf);
  83253. $this->_dependencyDB->installPackage($pf);
  83254. }
  83255. return $ret;
  83256. }
  83257. // }}}
  83258. // {{{ addPackage2()
  83259. function addPackage2($info)
  83260. {
  83261. if (!is_object($info)) {
  83262. return $this->addPackage($info['package'], $info);
  83263. }
  83264. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83265. return $e;
  83266. }
  83267. $ret = $this->_addPackage2($info);
  83268. $this->_unlock();
  83269. if ($ret) {
  83270. $this->_dependencyDB->uninstallPackage($info);
  83271. $this->_dependencyDB->installPackage($info);
  83272. }
  83273. return $ret;
  83274. }
  83275. // }}}
  83276. // {{{ updateChannel()
  83277. /**
  83278. * For future expandibility purposes, separate this
  83279. * @param PEAR_ChannelFile
  83280. */
  83281. function updateChannel($channel, $lastmodified = null)
  83282. {
  83283. if ($channel->getName() == '__uri') {
  83284. return false;
  83285. }
  83286. return $this->addChannel($channel, $lastmodified, true);
  83287. }
  83288. // }}}
  83289. // {{{ deleteChannel()
  83290. /**
  83291. * Deletion fails if there are any packages installed from the channel
  83292. * @param string|PEAR_ChannelFile channel name
  83293. * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
  83294. */
  83295. function deleteChannel($channel)
  83296. {
  83297. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83298. return $e;
  83299. }
  83300. $ret = $this->_deleteChannel($channel);
  83301. $this->_unlock();
  83302. if ($ret && is_a($this->_config, 'PEAR_Config')) {
  83303. $this->_config->setChannels($this->listChannels());
  83304. }
  83305. return $ret;
  83306. }
  83307. // }}}
  83308. // {{{ addChannel()
  83309. /**
  83310. * @param PEAR_ChannelFile Channel object
  83311. * @param string Last-Modified header from HTTP for caching
  83312. * @return boolean|PEAR_Error True on creation, false if it already exists
  83313. */
  83314. function addChannel($channel, $lastmodified = false, $update = false)
  83315. {
  83316. if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) {
  83317. return false;
  83318. }
  83319. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83320. return $e;
  83321. }
  83322. $ret = $this->_addChannel($channel, $update, $lastmodified);
  83323. $this->_unlock();
  83324. if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) {
  83325. $this->_config->setChannels($this->listChannels());
  83326. }
  83327. return $ret;
  83328. }
  83329. // }}}
  83330. // {{{ deletePackage()
  83331. function deletePackage($package, $channel = 'pear.php.net')
  83332. {
  83333. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83334. return $e;
  83335. }
  83336. $file = $this->_packageFileName($package, $channel);
  83337. $ret = file_exists($file) ? @unlink($file) : false;
  83338. $this->_rebuildFileMap();
  83339. $this->_unlock();
  83340. $p = array('channel' => $channel, 'package' => $package);
  83341. $this->_dependencyDB->uninstallPackage($p);
  83342. return $ret;
  83343. }
  83344. // }}}
  83345. // {{{ updatePackage()
  83346. function updatePackage($package, $info, $merge = true)
  83347. {
  83348. if (is_object($info)) {
  83349. return $this->updatePackage2($info, $merge);
  83350. }
  83351. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83352. return $e;
  83353. }
  83354. $ret = $this->_updatePackage($package, $info, $merge);
  83355. $this->_unlock();
  83356. if ($ret) {
  83357. if (!class_exists('PEAR_PackageFile_v1')) {
  83358. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v1.php';
  83359. }
  83360. $pf = new PEAR_PackageFile_v1;
  83361. $pf->setConfig($this->_config);
  83362. $pf->fromArray($this->packageInfo($package));
  83363. $this->_dependencyDB->uninstallPackage($pf);
  83364. $this->_dependencyDB->installPackage($pf);
  83365. }
  83366. return $ret;
  83367. }
  83368. // }}}
  83369. // {{{ updatePackage2()
  83370. function updatePackage2($info)
  83371. {
  83372. if (!is_object($info)) {
  83373. return $this->updatePackage($info['package'], $info, $merge);
  83374. }
  83375. if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {
  83376. return false;
  83377. }
  83378. if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  83379. return $e;
  83380. }
  83381. $ret = $this->_updatePackage2($info);
  83382. $this->_unlock();
  83383. if ($ret) {
  83384. $this->_dependencyDB->uninstallPackage($info);
  83385. $this->_dependencyDB->installPackage($info);
  83386. }
  83387. return $ret;
  83388. }
  83389. // }}}
  83390. // {{{ getChannel()
  83391. /**
  83392. * @param string channel name
  83393. * @param bool whether to strictly return raw channels (no aliases)
  83394. * @return PEAR_ChannelFile|PEAR_Error
  83395. */
  83396. function getChannel($channel, $noaliases = false)
  83397. {
  83398. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83399. return $e;
  83400. }
  83401. $ret = $this->_getChannel($channel, $noaliases);
  83402. $this->_unlock();
  83403. if (!$ret) {
  83404. return PEAR::raiseError('Unknown channel: ' . $channel);
  83405. }
  83406. return $ret;
  83407. }
  83408. // }}}
  83409. // {{{ getPackage()
  83410. /**
  83411. * @param string package name
  83412. * @param string channel name
  83413. * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
  83414. */
  83415. function &getPackage($package, $channel = 'pear.php.net')
  83416. {
  83417. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83418. return $e;
  83419. }
  83420. $pf = &$this->_getPackage($package, $channel);
  83421. $this->_unlock();
  83422. return $pf;
  83423. }
  83424. // }}}
  83425. /**
  83426. * Get PEAR_PackageFile_v[1/2] objects representing the contents of
  83427. * a dependency group that are installed.
  83428. *
  83429. * This is used at uninstall-time
  83430. * @param array
  83431. * @return array|false
  83432. */
  83433. function getInstalledGroup($group)
  83434. {
  83435. $ret = array();
  83436. if (isset($group['package'])) {
  83437. if (!isset($group['package'][0])) {
  83438. $group['package'] = array($group['package']);
  83439. }
  83440. foreach ($group['package'] as $package) {
  83441. $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
  83442. $p = &$this->getPackage($package['name'], $depchannel);
  83443. if ($p) {
  83444. $save = &$p;
  83445. $ret[] = &$save;
  83446. }
  83447. }
  83448. }
  83449. if (isset($group['subpackage'])) {
  83450. if (!isset($group['subpackage'][0])) {
  83451. $group['subpackage'] = array($group['subpackage']);
  83452. }
  83453. foreach ($group['subpackage'] as $package) {
  83454. $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
  83455. $p = &$this->getPackage($package['name'], $depchannel);
  83456. if ($p) {
  83457. $save = &$p;
  83458. $ret[] = &$save;
  83459. }
  83460. }
  83461. }
  83462. if (!count($ret)) {
  83463. return false;
  83464. }
  83465. return $ret;
  83466. }
  83467. // {{{ getChannelValidator()
  83468. /**
  83469. * @param string channel name
  83470. * @return PEAR_Validate|false
  83471. */
  83472. function &getChannelValidator($channel)
  83473. {
  83474. $chan = $this->getChannel($channel);
  83475. if (PEAR::isError($chan)) {
  83476. return $chan;
  83477. }
  83478. $val = $chan->getValidationObject();
  83479. return $val;
  83480. }
  83481. // }}}
  83482. // {{{ getChannels()
  83483. /**
  83484. * @param string channel name
  83485. * @return array an array of PEAR_ChannelFile objects representing every installed channel
  83486. */
  83487. function &getChannels()
  83488. {
  83489. $ret = array();
  83490. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83491. return $e;
  83492. }
  83493. foreach ($this->_listChannels() as $channel) {
  83494. $e = &$this->_getChannel($channel);
  83495. if (!$e || PEAR::isError($e)) {
  83496. continue;
  83497. }
  83498. $ret[] = $e;
  83499. }
  83500. $this->_unlock();
  83501. return $ret;
  83502. }
  83503. // }}}
  83504. // {{{ checkFileMap()
  83505. /**
  83506. * Test whether a file or set of files belongs to a package.
  83507. *
  83508. * If an array is passed in
  83509. * @param string|array file path, absolute or relative to the pear
  83510. * install dir
  83511. * @param string|array name of PEAR package or array('package' => name, 'channel' =>
  83512. * channel) of a package that will be ignored
  83513. * @param string API version - 1.1 will exclude any files belonging to a package
  83514. * @param array private recursion variable
  83515. * @return array|false which package and channel the file belongs to, or an empty
  83516. * string if the file does not belong to an installed package,
  83517. * or belongs to the second parameter's package
  83518. */
  83519. function checkFileMap($path, $package = false, $api = '1.0', $attrs = false)
  83520. {
  83521. if (is_array($path)) {
  83522. static $notempty;
  83523. if (empty($notempty)) {
  83524. if (!class_exists('PEAR_Installer_Role')) {
  83525. require_once 'phar://go-pear.phar/' . 'PEAR/Installer/Role.php';
  83526. }
  83527. $notempty = function($a) { return !empty($a); };
  83528. }
  83529. $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1]))
  83530. : strtolower($package);
  83531. $pkgs = array();
  83532. foreach ($path as $name => $attrs) {
  83533. if (is_array($attrs)) {
  83534. if (isset($attrs['install-as'])) {
  83535. $name = $attrs['install-as'];
  83536. }
  83537. if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) {
  83538. // these are not installed
  83539. continue;
  83540. }
  83541. if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) {
  83542. $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;
  83543. }
  83544. if (isset($attrs['baseinstalldir'])) {
  83545. $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
  83546. }
  83547. }
  83548. $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);
  83549. if (PEAR::isError($pkgs[$name])) {
  83550. return $pkgs[$name];
  83551. }
  83552. }
  83553. return array_filter($pkgs, $notempty);
  83554. }
  83555. if (empty($this->filemap_cache)) {
  83556. if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
  83557. return $e;
  83558. }
  83559. $err = $this->_readFileMap();
  83560. $this->_unlock();
  83561. if (PEAR::isError($err)) {
  83562. return $err;
  83563. }
  83564. }
  83565. if (!$attrs) {
  83566. $attrs = array('role' => 'php'); // any old call would be for PHP role only
  83567. }
  83568. if (isset($this->filemap_cache[$attrs['role']][$path])) {
  83569. if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
  83570. return false;
  83571. }
  83572. return $this->filemap_cache[$attrs['role']][$path];
  83573. }
  83574. $l = strlen($this->install_dir);
  83575. if (substr($path, 0, $l) == $this->install_dir) {
  83576. $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
  83577. }
  83578. if (isset($this->filemap_cache[$attrs['role']][$path])) {
  83579. if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
  83580. return false;
  83581. }
  83582. return $this->filemap_cache[$attrs['role']][$path];
  83583. }
  83584. return false;
  83585. }
  83586. // }}}
  83587. // {{{ flush()
  83588. /**
  83589. * Force a reload of the filemap
  83590. * @since 1.5.0RC3
  83591. */
  83592. function flushFileMap()
  83593. {
  83594. $this->filemap_cache = null;
  83595. clearstatcache(); // ensure that the next read gets the full, current filemap
  83596. }
  83597. // }}}
  83598. // {{{ apiVersion()
  83599. /**
  83600. * Get the expected API version. Channels API is version 1.1, as it is backwards
  83601. * compatible with 1.0
  83602. * @return string
  83603. */
  83604. function apiVersion()
  83605. {
  83606. return '1.1';
  83607. }
  83608. // }}}
  83609. /**
  83610. * Parse a package name, or validate a parsed package name array
  83611. * @param string|array pass in an array of format
  83612. * array(
  83613. * 'package' => 'pname',
  83614. * ['channel' => 'channame',]
  83615. * ['version' => 'version',]
  83616. * ['state' => 'state',]
  83617. * ['group' => 'groupname'])
  83618. * or a string of format
  83619. * [channel://][channame/]pname[-version|-state][/group=groupname]
  83620. * @return array|PEAR_Error
  83621. */
  83622. function parsePackageName($param, $defaultchannel = 'pear.php.net')
  83623. {
  83624. $saveparam = $param;
  83625. if (is_array($param)) {
  83626. // convert to string for error messages
  83627. $saveparam = $this->parsedPackageNameToString($param);
  83628. // process the array
  83629. if (!isset($param['package'])) {
  83630. return PEAR::raiseError('parsePackageName(): array $param ' .
  83631. 'must contain a valid package name in index "param"',
  83632. 'package', null, null, $param);
  83633. }
  83634. if (!isset($param['uri'])) {
  83635. if (!isset($param['channel'])) {
  83636. $param['channel'] = $defaultchannel;
  83637. }
  83638. } else {
  83639. $param['channel'] = '__uri';
  83640. }
  83641. } else {
  83642. $components = @parse_url((string) $param);
  83643. if (isset($components['scheme'])) {
  83644. if ($components['scheme'] == 'http') {
  83645. // uri package
  83646. $param = array('uri' => $param, 'channel' => '__uri');
  83647. } elseif($components['scheme'] != 'channel') {
  83648. return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .
  83649. 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);
  83650. }
  83651. }
  83652. if (!isset($components['path'])) {
  83653. return PEAR::raiseError('parsePackageName(): array $param ' .
  83654. 'must contain a valid package name in "' . $param . '"',
  83655. 'package', null, null, $param);
  83656. }
  83657. if (isset($components['host'])) {
  83658. // remove the leading "/"
  83659. $components['path'] = substr($components['path'], 1);
  83660. }
  83661. if (!isset($components['scheme'])) {
  83662. if (strpos($components['path'], '/') !== false) {
  83663. if ($components['path'][0] == '/') {
  83664. return PEAR::raiseError('parsePackageName(): this is not ' .
  83665. 'a package name, it begins with "/" in "' . $param . '"',
  83666. 'invalid', null, null, $param);
  83667. }
  83668. $parts = explode('/', $components['path']);
  83669. $components['host'] = array_shift($parts);
  83670. if (count($parts) > 1) {
  83671. $components['path'] = array_pop($parts);
  83672. $components['host'] .= '/' . implode('/', $parts);
  83673. } else {
  83674. $components['path'] = implode('/', $parts);
  83675. }
  83676. } else {
  83677. $components['host'] = $defaultchannel;
  83678. }
  83679. } else {
  83680. if (strpos($components['path'], '/')) {
  83681. $parts = explode('/', $components['path']);
  83682. $components['path'] = array_pop($parts);
  83683. $components['host'] .= '/' . implode('/', $parts);
  83684. }
  83685. }
  83686. if (is_array($param)) {
  83687. $param['package'] = $components['path'];
  83688. } else {
  83689. $param = array(
  83690. 'package' => $components['path']
  83691. );
  83692. if (isset($components['host'])) {
  83693. $param['channel'] = $components['host'];
  83694. }
  83695. }
  83696. if (isset($components['fragment'])) {
  83697. $param['group'] = $components['fragment'];
  83698. }
  83699. if (isset($components['user'])) {
  83700. $param['user'] = $components['user'];
  83701. }
  83702. if (isset($components['pass'])) {
  83703. $param['pass'] = $components['pass'];
  83704. }
  83705. if (isset($components['query'])) {
  83706. parse_str($components['query'], $param['opts']);
  83707. }
  83708. // check for extension
  83709. $pathinfo = pathinfo($param['package']);
  83710. if (isset($pathinfo['extension']) &&
  83711. in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) {
  83712. $param['extension'] = $pathinfo['extension'];
  83713. $param['package'] = substr($pathinfo['basename'], 0,
  83714. strlen($pathinfo['basename']) - 4);
  83715. }
  83716. // check for version
  83717. if (strpos($param['package'], '-')) {
  83718. $test = explode('-', $param['package']);
  83719. if (count($test) != 2) {
  83720. return PEAR::raiseError('parsePackageName(): only one version/state ' .
  83721. 'delimiter "-" is allowed in "' . $saveparam . '"',
  83722. 'version', null, null, $param);
  83723. }
  83724. list($param['package'], $param['version']) = $test;
  83725. }
  83726. }
  83727. // validation
  83728. $info = $this->channelExists($param['channel']);
  83729. if (PEAR::isError($info)) {
  83730. return $info;
  83731. }
  83732. if (!$info) {
  83733. return PEAR::raiseError('unknown channel "' . $param['channel'] .
  83734. '" in "' . $saveparam . '"', 'channel', null, null, $param);
  83735. }
  83736. $chan = $this->getChannel($param['channel']);
  83737. if (PEAR::isError($chan)) {
  83738. return $chan;
  83739. }
  83740. if (!$chan) {
  83741. return PEAR::raiseError("Exception: corrupt registry, could not " .
  83742. "retrieve channel " . $param['channel'] . " information",
  83743. 'registry', null, null, $param);
  83744. }
  83745. $param['channel'] = $chan->getName();
  83746. $validate = $chan->getValidationObject();
  83747. $vpackage = $chan->getValidationPackage();
  83748. // validate package name
  83749. if (!$validate->validPackageName($param['package'], $vpackage['_content'])) {
  83750. return PEAR::raiseError('parsePackageName(): invalid package name "' .
  83751. $param['package'] . '" in "' . $saveparam . '"',
  83752. 'package', null, null, $param);
  83753. }
  83754. if (isset($param['group'])) {
  83755. if (!PEAR_Validate::validGroupName($param['group'])) {
  83756. return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] .
  83757. '" is not a valid group name in "' . $saveparam . '"', 'group', null, null,
  83758. $param);
  83759. }
  83760. }
  83761. if (isset($param['state'])) {
  83762. if (!in_array(strtolower($param['state']), $validate->getValidStates())) {
  83763. return PEAR::raiseError('parsePackageName(): state "' . $param['state']
  83764. . '" is not a valid state in "' . $saveparam . '"',
  83765. 'state', null, null, $param);
  83766. }
  83767. }
  83768. if (isset($param['version'])) {
  83769. if (isset($param['state'])) {
  83770. return PEAR::raiseError('parsePackageName(): cannot contain both ' .
  83771. 'a version and a stability (state) in "' . $saveparam . '"',
  83772. 'version/state', null, null, $param);
  83773. }
  83774. // check whether version is actually a state
  83775. if (in_array(strtolower($param['version']), $validate->getValidStates())) {
  83776. $param['state'] = strtolower($param['version']);
  83777. unset($param['version']);
  83778. } else {
  83779. if (!$validate->validVersion($param['version'])) {
  83780. return PEAR::raiseError('parsePackageName(): "' . $param['version'] .
  83781. '" is neither a valid version nor a valid state in "' .
  83782. $saveparam . '"', 'version/state', null, null, $param);
  83783. }
  83784. }
  83785. }
  83786. return $param;
  83787. }
  83788. /**
  83789. * @param array
  83790. * @return string
  83791. */
  83792. function parsedPackageNameToString($parsed, $brief = false)
  83793. {
  83794. if (is_string($parsed)) {
  83795. return $parsed;
  83796. }
  83797. if (is_object($parsed)) {
  83798. $p = $parsed;
  83799. $parsed = array(
  83800. 'package' => $p->getPackage(),
  83801. 'channel' => $p->getChannel(),
  83802. 'version' => $p->getVersion(),
  83803. );
  83804. }
  83805. if (isset($parsed['uri'])) {
  83806. return $parsed['uri'];
  83807. }
  83808. if ($brief) {
  83809. if ($channel = $this->channelAlias($parsed['channel'])) {
  83810. return $channel . '/' . $parsed['package'];
  83811. }
  83812. }
  83813. $upass = '';
  83814. if (isset($parsed['user'])) {
  83815. $upass = $parsed['user'];
  83816. if (isset($parsed['pass'])) {
  83817. $upass .= ':' . $parsed['pass'];
  83818. }
  83819. $upass = "$upass@";
  83820. }
  83821. $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];
  83822. if (isset($parsed['version']) || isset($parsed['state'])) {
  83823. $ver = isset($parsed['version']) ? $parsed['version'] : '';
  83824. $ver .= isset($parsed['state']) ? $parsed['state'] : '';
  83825. $ret .= '-' . $ver;
  83826. }
  83827. if (isset($parsed['extension'])) {
  83828. $ret .= '.' . $parsed['extension'];
  83829. }
  83830. if (isset($parsed['opts'])) {
  83831. $ret .= '?';
  83832. foreach ($parsed['opts'] as $name => $value) {
  83833. $parsed['opts'][$name] = "$name=$value";
  83834. }
  83835. $ret .= implode('&', $parsed['opts']);
  83836. }
  83837. if (isset($parsed['group'])) {
  83838. $ret .= '#' . $parsed['group'];
  83839. }
  83840. return $ret;
  83841. }
  83842. }
  83843. <?php
  83844. /**
  83845. * PEAR_REST
  83846. *
  83847. * PHP versions 4 and 5
  83848. *
  83849. * @category pear
  83850. * @package PEAR
  83851. * @author Greg Beaver <cellog@php.net>
  83852. * @copyright 1997-2009 The Authors
  83853. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  83854. * @link http://pear.php.net/package/PEAR
  83855. * @since File available since Release 1.4.0a1
  83856. */
  83857. /**
  83858. * For downloading xml files
  83859. */
  83860. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  83861. require_once 'phar://go-pear.phar/' . 'PEAR/XMLParser.php';
  83862. require_once 'phar://go-pear.phar/' . 'PEAR/Proxy.php';
  83863. /**
  83864. * Intelligently retrieve data, following hyperlinks if necessary, and re-directing
  83865. * as well
  83866. * @category pear
  83867. * @package PEAR
  83868. * @author Greg Beaver <cellog@php.net>
  83869. * @copyright 1997-2009 The Authors
  83870. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  83871. * @version Release: 1.10.10
  83872. * @link http://pear.php.net/package/PEAR
  83873. * @since Class available since Release 1.4.0a1
  83874. */
  83875. class PEAR_REST
  83876. {
  83877. var $config;
  83878. var $_options;
  83879. function __construct(&$config, $options = array())
  83880. {
  83881. $this->config = &$config;
  83882. $this->_options = $options;
  83883. }
  83884. /**
  83885. * Retrieve REST data, but always retrieve the local cache if it is available.
  83886. *
  83887. * This is useful for elements that should never change, such as information on a particular
  83888. * release
  83889. * @param string full URL to this resource
  83890. * @param array|false contents of the accept-encoding header
  83891. * @param boolean if true, xml will be returned as a string, otherwise, xml will be
  83892. * parsed using PEAR_XMLParser
  83893. * @return string|array
  83894. */
  83895. function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false)
  83896. {
  83897. $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
  83898. md5($url) . 'rest.cachefile';
  83899. if (file_exists($cachefile)) {
  83900. return unserialize(implode('', file($cachefile)));
  83901. }
  83902. return $this->retrieveData($url, $accept, $forcestring, $channel);
  83903. }
  83904. /**
  83905. * Retrieve a remote REST resource
  83906. * @param string full URL to this resource
  83907. * @param array|false contents of the accept-encoding header
  83908. * @param boolean if true, xml will be returned as a string, otherwise, xml will be
  83909. * parsed using PEAR_XMLParser
  83910. * @return string|array
  83911. */
  83912. function retrieveData($url, $accept = false, $forcestring = false, $channel = false)
  83913. {
  83914. $cacheId = $this->getCacheId($url);
  83915. if ($ret = $this->useLocalCache($url, $cacheId)) {
  83916. return $ret;
  83917. }
  83918. $file = $trieddownload = false;
  83919. if (!isset($this->_options['offline'])) {
  83920. $trieddownload = true;
  83921. $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel);
  83922. }
  83923. if (PEAR::isError($file)) {
  83924. if ($file->getCode() !== -9276) {
  83925. return $file;
  83926. }
  83927. $trieddownload = false;
  83928. $file = false; // use local copy if available on socket connect error
  83929. }
  83930. if (!$file) {
  83931. $ret = $this->getCache($url);
  83932. if (!PEAR::isError($ret) && $trieddownload) {
  83933. // reset the age of the cache if the server says it was unmodified
  83934. $result = $this->saveCache($url, $ret, null, true, $cacheId);
  83935. if (PEAR::isError($result)) {
  83936. return PEAR::raiseError($result->getMessage());
  83937. }
  83938. }
  83939. return $ret;
  83940. }
  83941. if (is_array($file)) {
  83942. $headers = $file[2];
  83943. $lastmodified = $file[1];
  83944. $content = $file[0];
  83945. } else {
  83946. $headers = array();
  83947. $lastmodified = false;
  83948. $content = $file;
  83949. }
  83950. if ($forcestring) {
  83951. $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
  83952. if (PEAR::isError($result)) {
  83953. return PEAR::raiseError($result->getMessage());
  83954. }
  83955. return $content;
  83956. }
  83957. if (isset($headers['content-type'])) {
  83958. $content_type = explode(";", $headers['content-type']);
  83959. $content_type = $content_type[0];
  83960. switch ($content_type) {
  83961. case 'text/xml' :
  83962. case 'application/xml' :
  83963. case 'text/plain' :
  83964. if ($content_type === 'text/plain') {
  83965. $check = substr($content, 0, 5);
  83966. if ($check !== '<?xml') {
  83967. break;
  83968. }
  83969. }
  83970. $parser = new PEAR_XMLParser;
  83971. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  83972. $err = $parser->parse($content);
  83973. PEAR::popErrorHandling();
  83974. if (PEAR::isError($err)) {
  83975. return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' .
  83976. $err->getMessage());
  83977. }
  83978. $content = $parser->getData();
  83979. case 'text/html' :
  83980. default :
  83981. // use it as a string
  83982. }
  83983. } else {
  83984. // assume XML
  83985. $parser = new PEAR_XMLParser;
  83986. $parser->parse($content);
  83987. $content = $parser->getData();
  83988. }
  83989. $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
  83990. if (PEAR::isError($result)) {
  83991. return PEAR::raiseError($result->getMessage());
  83992. }
  83993. return $content;
  83994. }
  83995. function useLocalCache($url, $cacheid = null)
  83996. {
  83997. if (!is_array($cacheid)) {
  83998. $cacheid = $this->getCacheId($url);
  83999. }
  84000. $cachettl = $this->config->get('cache_ttl');
  84001. // If cache is newer than $cachettl seconds, we use the cache!
  84002. if (time() - $cacheid['age'] < $cachettl) {
  84003. return $this->getCache($url);
  84004. }
  84005. return false;
  84006. }
  84007. /**
  84008. * @param string $url
  84009. *
  84010. * @return bool|mixed
  84011. */
  84012. function getCacheId($url)
  84013. {
  84014. $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
  84015. md5($url) . 'rest.cacheid';
  84016. if (!file_exists($cacheidfile)) {
  84017. return false;
  84018. }
  84019. $ret = unserialize(implode('', file($cacheidfile)));
  84020. return $ret;
  84021. }
  84022. function getCache($url)
  84023. {
  84024. $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
  84025. md5($url) . 'rest.cachefile';
  84026. if (!file_exists($cachefile)) {
  84027. return PEAR::raiseError('No cached content available for "' . $url . '"');
  84028. }
  84029. return unserialize(implode('', file($cachefile)));
  84030. }
  84031. /**
  84032. * @param string full URL to REST resource
  84033. * @param string original contents of the REST resource
  84034. * @param array HTTP Last-Modified and ETag headers
  84035. * @param bool if true, then the cache id file should be regenerated to
  84036. * trigger a new time-to-live value
  84037. */
  84038. function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null)
  84039. {
  84040. $cache_dir = $this->config->get('cache_dir');
  84041. $d = $cache_dir . DIRECTORY_SEPARATOR . md5($url);
  84042. $cacheidfile = $d . 'rest.cacheid';
  84043. $cachefile = $d . 'rest.cachefile';
  84044. if (!is_dir($cache_dir)) {
  84045. if (System::mkdir(array('-p', $cache_dir)) === false) {
  84046. return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed.");
  84047. }
  84048. }
  84049. if (!is_writeable($cache_dir)) {
  84050. // If writing to the cache dir is not going to work, silently do nothing.
  84051. // An ugly hack, but retains compat with PEAR 1.9.1 where many commands
  84052. // work fine as non-root user (w/out write access to default cache dir).
  84053. return true;
  84054. }
  84055. if ($cacheid === null && $nochange) {
  84056. $cacheid = unserialize(implode('', file($cacheidfile)));
  84057. }
  84058. $idData = serialize(array(
  84059. 'age' => time(),
  84060. 'lastChange' => ($nochange ? $cacheid['lastChange'] : $lastmodified),
  84061. ));
  84062. $result = $this->saveCacheFile($cacheidfile, $idData);
  84063. if (PEAR::isError($result)) {
  84064. return $result;
  84065. } elseif ($nochange) {
  84066. return true;
  84067. }
  84068. $result = $this->saveCacheFile($cachefile, serialize($contents));
  84069. if (PEAR::isError($result)) {
  84070. if (file_exists($cacheidfile)) {
  84071. @unlink($cacheidfile);
  84072. }
  84073. return $result;
  84074. }
  84075. return true;
  84076. }
  84077. function saveCacheFile($file, $contents)
  84078. {
  84079. $len = strlen($contents);
  84080. $cachefile_fp = @fopen($file, 'xb'); // x is the O_CREAT|O_EXCL mode
  84081. if ($cachefile_fp !== false) { // create file
  84082. if (fwrite($cachefile_fp, $contents, $len) < $len) {
  84083. fclose($cachefile_fp);
  84084. return PEAR::raiseError("Could not write $file.");
  84085. }
  84086. } else { // update file
  84087. $cachefile_fp = @fopen($file, 'r+b'); // do not truncate file
  84088. if (!$cachefile_fp) {
  84089. return PEAR::raiseError("Could not open $file for writing.");
  84090. }
  84091. if (OS_WINDOWS) {
  84092. $not_symlink = !is_link($file); // see bug #18834
  84093. } else {
  84094. $cachefile_lstat = lstat($file);
  84095. $cachefile_fstat = fstat($cachefile_fp);
  84096. $not_symlink = $cachefile_lstat['mode'] == $cachefile_fstat['mode']
  84097. && $cachefile_lstat['ino'] == $cachefile_fstat['ino']
  84098. && $cachefile_lstat['dev'] == $cachefile_fstat['dev']
  84099. && $cachefile_fstat['nlink'] === 1;
  84100. }
  84101. if ($not_symlink) {
  84102. ftruncate($cachefile_fp, 0); // NOW truncate
  84103. if (fwrite($cachefile_fp, $contents, $len) < $len) {
  84104. fclose($cachefile_fp);
  84105. return PEAR::raiseError("Could not write $file.");
  84106. }
  84107. } else {
  84108. fclose($cachefile_fp);
  84109. $link = function_exists('readlink') ? readlink($file) : $file;
  84110. return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $file . ' as it is symlinked to ' . $link . ' - Possible symlink attack');
  84111. }
  84112. }
  84113. fclose($cachefile_fp);
  84114. return true;
  84115. }
  84116. /**
  84117. * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory
  84118. * This is best used for small files
  84119. *
  84120. * If an HTTP proxy has been configured (http_proxy PEAR_Config
  84121. * setting), the proxy will be used.
  84122. *
  84123. * @param string $url the URL to download
  84124. * @param string $save_dir directory to save file in
  84125. * @param false|string|array $lastmodified header values to check against for caching
  84126. * use false to return the header values from this download
  84127. * @param false|array $accept Accept headers to send
  84128. * @return string|array Returns the contents of the downloaded file or a PEAR
  84129. * error on failure. If the error is caused by
  84130. * socket-related errors, the error object will
  84131. * have the fsockopen error code available through
  84132. * getCode(). If caching is requested, then return the header
  84133. * values.
  84134. *
  84135. * @access public
  84136. */
  84137. function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false)
  84138. {
  84139. static $redirect = 0;
  84140. // always reset , so we are clean case of error
  84141. $wasredirect = $redirect;
  84142. $redirect = 0;
  84143. $info = parse_url($url);
  84144. if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
  84145. return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
  84146. }
  84147. if (!isset($info['host'])) {
  84148. return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
  84149. }
  84150. $host = isset($info['host']) ? $info['host'] : null;
  84151. $port = isset($info['port']) ? $info['port'] : null;
  84152. $path = isset($info['path']) ? $info['path'] : null;
  84153. $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
  84154. $proxy = new PEAR_Proxy($this->config);
  84155. if (empty($port)) {
  84156. $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
  84157. }
  84158. if ($proxy->isProxyConfigured() && $schema === 'http') {
  84159. $request = "GET $url HTTP/1.1\r\n";
  84160. } else {
  84161. $request = "GET $path HTTP/1.1\r\n";
  84162. }
  84163. $request .= "Host: $host\r\n";
  84164. $ifmodifiedsince = '';
  84165. if (is_array($lastmodified)) {
  84166. if (isset($lastmodified['Last-Modified'])) {
  84167. $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
  84168. }
  84169. if (isset($lastmodified['ETag'])) {
  84170. $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
  84171. }
  84172. } else {
  84173. $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
  84174. }
  84175. $request .= $ifmodifiedsince .
  84176. "User-Agent: PEAR/1.10.10/PHP/" . PHP_VERSION . "\r\n";
  84177. $username = $this->config->get('username', null, $channel);
  84178. $password = $this->config->get('password', null, $channel);
  84179. if ($username && $password) {
  84180. $tmp = base64_encode("$username:$password");
  84181. $request .= "Authorization: Basic $tmp\r\n";
  84182. }
  84183. $proxyAuth = $proxy->getProxyAuth();
  84184. if ($proxyAuth) {
  84185. $request .= 'Proxy-Authorization: Basic ' .
  84186. $proxyAuth . "\r\n";
  84187. }
  84188. if ($accept) {
  84189. $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
  84190. }
  84191. $request .= "Accept-Encoding:\r\n";
  84192. $request .= "Connection: close\r\n";
  84193. $request .= "\r\n";
  84194. $secure = ($schema == 'https');
  84195. $fp = $proxy->openSocket($host, $port, $secure);
  84196. if (PEAR::isError($fp)) {
  84197. return $fp;
  84198. }
  84199. fwrite($fp, $request);
  84200. $headers = array();
  84201. $reply = 0;
  84202. while ($line = trim(fgets($fp, 1024))) {
  84203. if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
  84204. $headers[strtolower($matches[1])] = trim($matches[2]);
  84205. } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  84206. $reply = (int)$matches[1];
  84207. if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
  84208. return false;
  84209. }
  84210. if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
  84211. return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)");
  84212. }
  84213. }
  84214. }
  84215. if ($reply != 200) {
  84216. if (!isset($headers['location'])) {
  84217. return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)");
  84218. }
  84219. if ($wasredirect > 4) {
  84220. return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)");
  84221. }
  84222. $redirect = $wasredirect + 1;
  84223. return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel);
  84224. }
  84225. $length = isset($headers['content-length']) ? $headers['content-length'] : -1;
  84226. $data = '';
  84227. while ($chunk = @fread($fp, 8192)) {
  84228. $data .= $chunk;
  84229. }
  84230. fclose($fp);
  84231. if ($lastmodified === false || $lastmodified) {
  84232. if (isset($headers['etag'])) {
  84233. $lastmodified = array('ETag' => $headers['etag']);
  84234. }
  84235. if (isset($headers['last-modified'])) {
  84236. if (is_array($lastmodified)) {
  84237. $lastmodified['Last-Modified'] = $headers['last-modified'];
  84238. } else {
  84239. $lastmodified = $headers['last-modified'];
  84240. }
  84241. }
  84242. return array($data, $lastmodified, $headers);
  84243. }
  84244. return $data;
  84245. }
  84246. }
  84247. <?php
  84248. /**
  84249. * PEAR_REST_10
  84250. *
  84251. * PHP versions 4 and 5
  84252. *
  84253. * @category pear
  84254. * @package PEAR
  84255. * @author Greg Beaver <cellog@php.net>
  84256. * @copyright 1997-2009 The Authors
  84257. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  84258. * @link http://pear.php.net/package/PEAR
  84259. * @since File available since Release 1.4.0a12
  84260. */
  84261. /**
  84262. * For downloading REST xml/txt files
  84263. */
  84264. require_once 'phar://go-pear.phar/' . 'PEAR/REST.php';
  84265. /**
  84266. * Implement REST 1.0
  84267. *
  84268. * @category pear
  84269. * @package PEAR
  84270. * @author Greg Beaver <cellog@php.net>
  84271. * @copyright 1997-2009 The Authors
  84272. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  84273. * @version Release: 1.10.10
  84274. * @link http://pear.php.net/package/PEAR
  84275. * @since Class available since Release 1.4.0a12
  84276. */
  84277. class PEAR_REST_10
  84278. {
  84279. /**
  84280. * @var PEAR_REST
  84281. */
  84282. var $_rest;
  84283. function __construct($config, $options = array())
  84284. {
  84285. $this->_rest = new PEAR_REST($config, $options);
  84286. }
  84287. /**
  84288. * Retrieve information about a remote package to be downloaded from a REST server
  84289. *
  84290. * @param string $base The uri to prepend to all REST calls
  84291. * @param array $packageinfo an array of format:
  84292. * <pre>
  84293. * array(
  84294. * 'package' => 'packagename',
  84295. * 'channel' => 'channelname',
  84296. * ['state' => 'alpha' (or valid state),]
  84297. * -or-
  84298. * ['version' => '1.whatever']
  84299. * </pre>
  84300. * @param string $prefstate Current preferred_state config variable value
  84301. * @param bool $installed the installed version of this package to compare against
  84302. * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
  84303. */
  84304. function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
  84305. {
  84306. $states = $this->betterStates($prefstate, true);
  84307. if (!$states) {
  84308. return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  84309. }
  84310. $channel = $packageinfo['channel'];
  84311. $package = $packageinfo['package'];
  84312. $state = isset($packageinfo['state']) ? $packageinfo['state'] : null;
  84313. $version = isset($packageinfo['version']) ? $packageinfo['version'] : null;
  84314. $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
  84315. $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  84316. if (PEAR::isError($info)) {
  84317. return PEAR::raiseError('No releases available for package "' .
  84318. $channel . '/' . $package . '"');
  84319. }
  84320. if (!isset($info['r'])) {
  84321. return false;
  84322. }
  84323. $release = $found = false;
  84324. if (!is_array($info['r']) || !isset($info['r'][0])) {
  84325. $info['r'] = array($info['r']);
  84326. }
  84327. foreach ($info['r'] as $release) {
  84328. if (!isset($this->_rest->_options['force']) && ($installed &&
  84329. version_compare($release['v'], $installed, '<'))) {
  84330. continue;
  84331. }
  84332. if (isset($state)) {
  84333. // try our preferred state first
  84334. if ($release['s'] == $state) {
  84335. $found = true;
  84336. break;
  84337. }
  84338. // see if there is something newer and more stable
  84339. // bug #7221
  84340. if (in_array($release['s'], $this->betterStates($state), true)) {
  84341. $found = true;
  84342. break;
  84343. }
  84344. } elseif (isset($version)) {
  84345. if ($release['v'] == $version) {
  84346. $found = true;
  84347. break;
  84348. }
  84349. } else {
  84350. if (in_array($release['s'], $states)) {
  84351. $found = true;
  84352. break;
  84353. }
  84354. }
  84355. }
  84356. return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
  84357. }
  84358. function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
  84359. $prefstate = 'stable', $installed = false, $channel = false)
  84360. {
  84361. $states = $this->betterStates($prefstate, true);
  84362. if (!$states) {
  84363. return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
  84364. }
  84365. $channel = $dependency['channel'];
  84366. $package = $dependency['name'];
  84367. $state = isset($dependency['state']) ? $dependency['state'] : null;
  84368. $version = isset($dependency['version']) ? $dependency['version'] : null;
  84369. $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
  84370. $info = $this->_rest->retrieveData($restFile, false, false, $channel);
  84371. if (PEAR::isError($info)) {
  84372. return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
  84373. . '" dependency "' . $channel . '/' . $package . '" has no releases');
  84374. }
  84375. if (!is_array($info) || !isset($info['r'])) {
  84376. return false;
  84377. }
  84378. $exclude = array();
  84379. $min = $max = $recommended = false;
  84380. if ($xsdversion == '1.0') {
  84381. switch ($dependency['rel']) {
  84382. case 'ge' :
  84383. $min = $dependency['version'];
  84384. break;
  84385. case 'gt' :
  84386. $min = $dependency['version'];
  84387. $exclude = array($dependency['version']);
  84388. break;
  84389. case 'eq' :
  84390. $recommended = $dependency['version'];
  84391. break;
  84392. case 'lt' :
  84393. $max = $dependency['version'];
  84394. $exclude = array($dependency['version']);
  84395. break;
  84396. case 'le' :
  84397. $max = $dependency['version'];
  84398. break;
  84399. case 'ne' :
  84400. $exclude = array($dependency['version']);
  84401. break;
  84402. }
  84403. } else {
  84404. $min = isset($dependency['min']) ? $dependency['min'] : false;
  84405. $max = isset($dependency['max']) ? $dependency['max'] : false;
  84406. $recommended = isset($dependency['recommended']) ?
  84407. $dependency['recommended'] : false;
  84408. if (isset($dependency['exclude'])) {
  84409. if (!isset($dependency['exclude'][0])) {
  84410. $exclude = array($dependency['exclude']);
  84411. }
  84412. }
  84413. }
  84414. $release = $found = false;
  84415. if (!is_array($info['r']) || !isset($info['r'][0])) {
  84416. $info['r'] = array($info['r']);
  84417. }
  84418. foreach ($info['r'] as $release) {
  84419. if (!isset($this->_rest->_options['force']) && ($installed &&
  84420. version_compare($release['v'], $installed, '<'))) {
  84421. continue;
  84422. }
  84423. if (in_array($release['v'], $exclude)) { // skip excluded versions
  84424. continue;
  84425. }
  84426. // allow newer releases to say "I'm OK with the dependent package"
  84427. if ($xsdversion == '2.0' && isset($release['co'])) {
  84428. if (!is_array($release['co']) || !isset($release['co'][0])) {
  84429. $release['co'] = array($release['co']);
  84430. }
  84431. foreach ($release['co'] as $entry) {
  84432. if (isset($entry['x']) && !is_array($entry['x'])) {
  84433. $entry['x'] = array($entry['x']);
  84434. } elseif (!isset($entry['x'])) {
  84435. $entry['x'] = array();
  84436. }
  84437. if ($entry['c'] == $deppackage['channel'] &&
  84438. strtolower($entry['p']) == strtolower($deppackage['package']) &&
  84439. version_compare($deppackage['version'], $entry['min'], '>=') &&
  84440. version_compare($deppackage['version'], $entry['max'], '<=') &&
  84441. !in_array($release['v'], $entry['x'])) {
  84442. $recommended = $release['v'];
  84443. break;
  84444. }
  84445. }
  84446. }
  84447. if ($recommended) {
  84448. if ($release['v'] != $recommended) { // if we want a specific
  84449. // version, then skip all others
  84450. continue;
  84451. } else {
  84452. if (!in_array($release['s'], $states)) {
  84453. // the stability is too low, but we must return the
  84454. // recommended version if possible
  84455. return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
  84456. }
  84457. }
  84458. }
  84459. if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
  84460. continue;
  84461. }
  84462. if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
  84463. continue;
  84464. }
  84465. if ($installed && version_compare($release['v'], $installed, '<')) {
  84466. continue;
  84467. }
  84468. if (in_array($release['s'], $states)) { // if in the preferred state...
  84469. $found = true; // ... then use it
  84470. break;
  84471. }
  84472. }
  84473. return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
  84474. }
  84475. /**
  84476. * Take raw data and return the array needed for processing a download URL
  84477. *
  84478. * @param string $base REST base uri
  84479. * @param string $package Package name
  84480. * @param array $release an array of format array('v' => version, 's' => state)
  84481. * describing the release to download
  84482. * @param array $info list of all releases as defined by allreleases.xml
  84483. * @param bool|null $found determines whether the release was found or this is the next
  84484. * best alternative. If null, then versions were skipped because
  84485. * of PHP dependency
  84486. * @return array|PEAR_Error
  84487. * @access private
  84488. */
  84489. function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false)
  84490. {
  84491. if (!$found) {
  84492. $release = $info['r'][0];
  84493. }
  84494. $packageLower = strtolower($package);
  84495. $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' .
  84496. 'info.xml', false, false, $channel);
  84497. if (PEAR::isError($pinfo)) {
  84498. return PEAR::raiseError('Package "' . $package .
  84499. '" does not have REST info xml available');
  84500. }
  84501. $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
  84502. $release['v'] . '.xml', false, false, $channel);
  84503. if (PEAR::isError($releaseinfo)) {
  84504. return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
  84505. '" does not have REST xml available');
  84506. }
  84507. $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
  84508. 'deps.' . $release['v'] . '.txt', false, true, $channel);
  84509. if (PEAR::isError($packagexml)) {
  84510. return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
  84511. '" does not have REST dependency information available');
  84512. }
  84513. $packagexml = unserialize($packagexml);
  84514. if (!$packagexml) {
  84515. $packagexml = array();
  84516. }
  84517. $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower .
  84518. '/allreleases.xml', false, false, $channel);
  84519. if (PEAR::isError($allinfo)) {
  84520. return $allinfo;
  84521. }
  84522. if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) {
  84523. $allinfo['r'] = array($allinfo['r']);
  84524. }
  84525. $compatible = false;
  84526. foreach ($allinfo['r'] as $release) {
  84527. if ($release['v'] != $releaseinfo['v']) {
  84528. continue;
  84529. }
  84530. if (!isset($release['co'])) {
  84531. break;
  84532. }
  84533. $compatible = array();
  84534. if (!is_array($release['co']) || !isset($release['co'][0])) {
  84535. $release['co'] = array($release['co']);
  84536. }
  84537. foreach ($release['co'] as $entry) {
  84538. $comp = array();
  84539. $comp['name'] = $entry['p'];
  84540. $comp['channel'] = $entry['c'];
  84541. $comp['min'] = $entry['min'];
  84542. $comp['max'] = $entry['max'];
  84543. if (isset($entry['x']) && !is_array($entry['x'])) {
  84544. $comp['exclude'] = $entry['x'];
  84545. }
  84546. $compatible[] = $comp;
  84547. }
  84548. if (count($compatible) == 1) {
  84549. $compatible = $compatible[0];
  84550. }
  84551. break;
  84552. }
  84553. $deprecated = false;
  84554. if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
  84555. if (is_array($pinfo['dp'])) {
  84556. $deprecated = array('channel' => (string) $pinfo['dc'],
  84557. 'package' => trim($pinfo['dp']['_content']));
  84558. } else {
  84559. $deprecated = array('channel' => (string) $pinfo['dc'],
  84560. 'package' => trim($pinfo['dp']));
  84561. }
  84562. }
  84563. $return = array(
  84564. 'version' => $releaseinfo['v'],
  84565. 'info' => $packagexml,
  84566. 'package' => $releaseinfo['p']['_content'],
  84567. 'stability' => $releaseinfo['st'],
  84568. 'compatible' => $compatible,
  84569. 'deprecated' => $deprecated,
  84570. );
  84571. if ($found) {
  84572. $return['url'] = $releaseinfo['g'];
  84573. return $return;
  84574. }
  84575. $return['php'] = $phpversion;
  84576. return $return;
  84577. }
  84578. function listPackages($base, $channel = false)
  84579. {
  84580. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  84581. if (PEAR::isError($packagelist)) {
  84582. return $packagelist;
  84583. }
  84584. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  84585. return array();
  84586. }
  84587. if (!is_array($packagelist['p'])) {
  84588. $packagelist['p'] = array($packagelist['p']);
  84589. }
  84590. return $packagelist['p'];
  84591. }
  84592. /**
  84593. * List all categories of a REST server
  84594. *
  84595. * @param string $base base URL of the server
  84596. * @return array of categorynames
  84597. */
  84598. function listCategories($base, $channel = false)
  84599. {
  84600. $categories = array();
  84601. // c/categories.xml does not exist;
  84602. // check for every package its category manually
  84603. // This is SLOOOWWWW : ///
  84604. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  84605. if (PEAR::isError($packagelist)) {
  84606. return $packagelist;
  84607. }
  84608. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  84609. $ret = array();
  84610. return $ret;
  84611. }
  84612. if (!is_array($packagelist['p'])) {
  84613. $packagelist['p'] = array($packagelist['p']);
  84614. }
  84615. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  84616. foreach ($packagelist['p'] as $package) {
  84617. $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  84618. if (PEAR::isError($inf)) {
  84619. PEAR::popErrorHandling();
  84620. return $inf;
  84621. }
  84622. $cat = $inf['ca']['_content'];
  84623. if (!isset($categories[$cat])) {
  84624. $categories[$cat] = $inf['ca'];
  84625. }
  84626. }
  84627. return array_values($categories);
  84628. }
  84629. /**
  84630. * List a category of a REST server
  84631. *
  84632. * @param string $base base URL of the server
  84633. * @param string $category name of the category
  84634. * @param boolean $info also download full package info
  84635. * @return array of packagenames
  84636. */
  84637. function listCategory($base, $category, $info = false, $channel = false)
  84638. {
  84639. // gives '404 Not Found' error when category doesn't exist
  84640. $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel);
  84641. if (PEAR::isError($packagelist)) {
  84642. return $packagelist;
  84643. }
  84644. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  84645. return array();
  84646. }
  84647. if (!is_array($packagelist['p']) ||
  84648. !isset($packagelist['p'][0])) { // only 1 pkg
  84649. $packagelist = array($packagelist['p']);
  84650. } else {
  84651. $packagelist = $packagelist['p'];
  84652. }
  84653. if ($info == true) {
  84654. // get individual package info
  84655. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  84656. foreach ($packagelist as $i => $packageitem) {
  84657. $url = sprintf('%s'.'r/%s/latest.txt',
  84658. $base,
  84659. strtolower($packageitem['_content']));
  84660. $version = $this->_rest->retrieveData($url, false, false, $channel);
  84661. if (PEAR::isError($version)) {
  84662. break; // skipit
  84663. }
  84664. $url = sprintf('%s'.'r/%s/%s.xml',
  84665. $base,
  84666. strtolower($packageitem['_content']),
  84667. $version);
  84668. $info = $this->_rest->retrieveData($url, false, false, $channel);
  84669. if (PEAR::isError($info)) {
  84670. break; // skipit
  84671. }
  84672. $packagelist[$i]['info'] = $info;
  84673. }
  84674. PEAR::popErrorHandling();
  84675. }
  84676. return $packagelist;
  84677. }
  84678. function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
  84679. {
  84680. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  84681. if (PEAR::isError($packagelist)) {
  84682. return $packagelist;
  84683. }
  84684. if ($this->_rest->config->get('verbose') > 0) {
  84685. $ui = &PEAR_Frontend::singleton();
  84686. $ui->log('Retrieving data...0%', true);
  84687. }
  84688. $ret = array();
  84689. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  84690. return $ret;
  84691. }
  84692. if (!is_array($packagelist['p'])) {
  84693. $packagelist['p'] = array($packagelist['p']);
  84694. }
  84695. // only search-packagename = quicksearch !
  84696. if ($searchpackage && (!$searchsummary || empty($searchpackage))) {
  84697. $newpackagelist = array();
  84698. foreach ($packagelist['p'] as $package) {
  84699. if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) {
  84700. $newpackagelist[] = $package;
  84701. }
  84702. }
  84703. $packagelist['p'] = $newpackagelist;
  84704. }
  84705. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  84706. $next = .1;
  84707. foreach ($packagelist['p'] as $progress => $package) {
  84708. if ($this->_rest->config->get('verbose') > 0) {
  84709. if ($progress / count($packagelist['p']) >= $next) {
  84710. if ($next == .5) {
  84711. $ui->log('50%', false);
  84712. } else {
  84713. $ui->log('.', false);
  84714. }
  84715. $next += .1;
  84716. }
  84717. }
  84718. if ($basic) { // remote-list command
  84719. if ($dostable) {
  84720. $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  84721. '/stable.txt', false, false, $channel);
  84722. } else {
  84723. $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  84724. '/latest.txt', false, false, $channel);
  84725. }
  84726. if (PEAR::isError($latest)) {
  84727. $latest = false;
  84728. }
  84729. $info = array('stable' => $latest);
  84730. } else { // list-all command
  84731. $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  84732. if (PEAR::isError($inf)) {
  84733. PEAR::popErrorHandling();
  84734. return $inf;
  84735. }
  84736. if ($searchpackage) {
  84737. $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false);
  84738. if (!$found && !(isset($searchsummary) && !empty($searchsummary)
  84739. && (stristr($inf['s'], $searchsummary) !== false
  84740. || stristr($inf['d'], $searchsummary) !== false)))
  84741. {
  84742. continue;
  84743. };
  84744. }
  84745. $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  84746. '/allreleases.xml', false, false, $channel);
  84747. if (PEAR::isError($releases)) {
  84748. continue;
  84749. }
  84750. if (!isset($releases['r'][0])) {
  84751. $releases['r'] = array($releases['r']);
  84752. }
  84753. unset($latest);
  84754. unset($unstable);
  84755. unset($stable);
  84756. unset($state);
  84757. foreach ($releases['r'] as $release) {
  84758. if (!isset($latest)) {
  84759. if ($dostable && $release['s'] == 'stable') {
  84760. $latest = $release['v'];
  84761. $state = 'stable';
  84762. }
  84763. if (!$dostable) {
  84764. $latest = $release['v'];
  84765. $state = $release['s'];
  84766. }
  84767. }
  84768. if (!isset($stable) && $release['s'] == 'stable') {
  84769. $stable = $release['v'];
  84770. if (!isset($unstable)) {
  84771. $unstable = $stable;
  84772. }
  84773. }
  84774. if (!isset($unstable) && $release['s'] != 'stable') {
  84775. $latest = $unstable = $release['v'];
  84776. $state = $release['s'];
  84777. }
  84778. if (isset($latest) && !isset($state)) {
  84779. $state = $release['s'];
  84780. }
  84781. if (isset($latest) && isset($stable) && isset($unstable)) {
  84782. break;
  84783. }
  84784. }
  84785. $deps = array();
  84786. if (!isset($unstable)) {
  84787. $unstable = false;
  84788. $state = 'stable';
  84789. if (isset($stable)) {
  84790. $latest = $unstable = $stable;
  84791. }
  84792. } else {
  84793. $latest = $unstable;
  84794. }
  84795. if (!isset($latest)) {
  84796. $latest = false;
  84797. }
  84798. if ($latest) {
  84799. $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
  84800. $latest . '.txt', false, false, $channel);
  84801. if (!PEAR::isError($d)) {
  84802. $d = unserialize($d);
  84803. if ($d) {
  84804. if (isset($d['required'])) {
  84805. if (!class_exists('PEAR_PackageFile_v2')) {
  84806. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  84807. }
  84808. if (!isset($pf)) {
  84809. $pf = new PEAR_PackageFile_v2;
  84810. }
  84811. $pf->setDeps($d);
  84812. $tdeps = $pf->getDeps();
  84813. } else {
  84814. $tdeps = $d;
  84815. }
  84816. foreach ($tdeps as $dep) {
  84817. if ($dep['type'] !== 'pkg') {
  84818. continue;
  84819. }
  84820. $deps[] = $dep;
  84821. }
  84822. }
  84823. }
  84824. }
  84825. if (!isset($stable)) {
  84826. $stable = '-n/a-';
  84827. }
  84828. if (!$searchpackage) {
  84829. $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' =>
  84830. $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
  84831. 'unstable' => $unstable, 'state' => $state);
  84832. } else {
  84833. $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' =>
  84834. $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
  84835. 'unstable' => $unstable, 'state' => $state);
  84836. }
  84837. }
  84838. $ret[$package] = $info;
  84839. }
  84840. PEAR::popErrorHandling();
  84841. return $ret;
  84842. }
  84843. function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
  84844. {
  84845. $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
  84846. if (PEAR::isError($packagelist)) {
  84847. return $packagelist;
  84848. }
  84849. $ret = array();
  84850. if (!is_array($packagelist) || !isset($packagelist['p'])) {
  84851. return $ret;
  84852. }
  84853. if (!is_array($packagelist['p'])) {
  84854. $packagelist['p'] = array($packagelist['p']);
  84855. }
  84856. foreach ($packagelist['p'] as $package) {
  84857. if (!isset($installed[strtolower($package)])) {
  84858. continue;
  84859. }
  84860. $inst_version = $reg->packageInfo($package, 'version', $channel);
  84861. $inst_state = $reg->packageInfo($package, 'release_state', $channel);
  84862. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  84863. $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  84864. '/allreleases.xml', false, false, $channel);
  84865. PEAR::popErrorHandling();
  84866. if (PEAR::isError($info)) {
  84867. continue; // no remote releases
  84868. }
  84869. if (!isset($info['r'])) {
  84870. continue;
  84871. }
  84872. $release = $found = false;
  84873. if (!is_array($info['r']) || !isset($info['r'][0])) {
  84874. $info['r'] = array($info['r']);
  84875. }
  84876. // $info['r'] is sorted by version number
  84877. usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
  84878. foreach ($info['r'] as $release) {
  84879. if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
  84880. // not newer than the one installed
  84881. break;
  84882. }
  84883. // new version > installed version
  84884. if (!$pref_state) {
  84885. // every state is a good state
  84886. $found = true;
  84887. break;
  84888. } else {
  84889. $new_state = $release['s'];
  84890. // if new state >= installed state: go
  84891. if (in_array($new_state, $this->betterStates($inst_state, true))) {
  84892. $found = true;
  84893. break;
  84894. } else {
  84895. // only allow to lower the state of package,
  84896. // if new state >= preferred state: go
  84897. if (in_array($new_state, $this->betterStates($pref_state, true))) {
  84898. $found = true;
  84899. break;
  84900. }
  84901. }
  84902. }
  84903. }
  84904. if (!$found) {
  84905. continue;
  84906. }
  84907. $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
  84908. $release['v'] . '.xml', false, false, $channel);
  84909. if (PEAR::isError($relinfo)) {
  84910. return $relinfo;
  84911. }
  84912. $ret[$package] = array(
  84913. 'version' => $release['v'],
  84914. 'state' => $release['s'],
  84915. 'filesize' => $relinfo['f'],
  84916. );
  84917. }
  84918. return $ret;
  84919. }
  84920. function packageInfo($base, $package, $channel = false)
  84921. {
  84922. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  84923. $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
  84924. if (PEAR::isError($pinfo)) {
  84925. PEAR::popErrorHandling();
  84926. return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' .
  84927. $pinfo->getMessage());
  84928. }
  84929. $releases = array();
  84930. $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
  84931. '/allreleases.xml', false, false, $channel);
  84932. if (!PEAR::isError($allreleases)) {
  84933. if (!class_exists('PEAR_PackageFile_v2')) {
  84934. require_once 'phar://go-pear.phar/' . 'PEAR/PackageFile/v2.php';
  84935. }
  84936. if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) {
  84937. $allreleases['r'] = array($allreleases['r']);
  84938. }
  84939. $pf = new PEAR_PackageFile_v2;
  84940. foreach ($allreleases['r'] as $release) {
  84941. $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
  84942. $release['v'] . '.txt', false, false, $channel);
  84943. if (PEAR::isError($ds)) {
  84944. continue;
  84945. }
  84946. if (!isset($latest)) {
  84947. $latest = $release['v'];
  84948. }
  84949. $pf->setDeps(unserialize($ds));
  84950. $ds = $pf->getDeps();
  84951. $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package)
  84952. . '/' . $release['v'] . '.xml', false, false, $channel);
  84953. if (PEAR::isError($info)) {
  84954. continue;
  84955. }
  84956. $releases[$release['v']] = array(
  84957. 'doneby' => $info['m'],
  84958. 'license' => $info['l'],
  84959. 'summary' => $info['s'],
  84960. 'description' => $info['d'],
  84961. 'releasedate' => $info['da'],
  84962. 'releasenotes' => $info['n'],
  84963. 'state' => $release['s'],
  84964. 'deps' => $ds ? $ds : array(),
  84965. );
  84966. }
  84967. } else {
  84968. $latest = '';
  84969. }
  84970. PEAR::popErrorHandling();
  84971. if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
  84972. if (is_array($pinfo['dp'])) {
  84973. $deprecated = array('channel' => (string) $pinfo['dc'],
  84974. 'package' => trim($pinfo['dp']['_content']));
  84975. } else {
  84976. $deprecated = array('channel' => (string) $pinfo['dc'],
  84977. 'package' => trim($pinfo['dp']));
  84978. }
  84979. } else {
  84980. $deprecated = false;
  84981. }
  84982. if (!isset($latest)) {
  84983. $latest = '';
  84984. }
  84985. return array(
  84986. 'name' => $pinfo['n'],
  84987. 'channel' => $pinfo['c'],
  84988. 'category' => $pinfo['ca']['_content'],
  84989. 'stable' => $latest,
  84990. 'license' => $pinfo['l'],
  84991. 'summary' => $pinfo['s'],
  84992. 'description' => $pinfo['d'],
  84993. 'releases' => $releases,
  84994. 'deprecated' => $deprecated,
  84995. );
  84996. }
  84997. /**
  84998. * Return an array containing all of the states that are more stable than
  84999. * or equal to the passed in state
  85000. *
  85001. * @param string Release state
  85002. * @param boolean Determines whether to include $state in the list
  85003. * @return false|array False if $state is not a valid release state
  85004. */
  85005. function betterStates($state, $include = false)
  85006. {
  85007. static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  85008. $i = array_search($state, $states);
  85009. if ($i === false) {
  85010. return false;
  85011. }
  85012. if ($include) {
  85013. $i--;
  85014. }
  85015. return array_slice($states, $i + 1);
  85016. }
  85017. /**
  85018. * Sort releases by version number
  85019. *
  85020. * @access private
  85021. */
  85022. function _sortReleasesByVersionNumber($a, $b)
  85023. {
  85024. if (version_compare($a['v'], $b['v'], '=')) {
  85025. return 0;
  85026. }
  85027. if (version_compare($a['v'], $b['v'], '>')) {
  85028. return -1;
  85029. }
  85030. if (version_compare($a['v'], $b['v'], '<')) {
  85031. return 1;
  85032. }
  85033. }
  85034. }
  85035. <?php
  85036. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  85037. require_once 'phar://go-pear.phar/' . 'System.php';
  85038. require_once 'phar://go-pear.phar/' . 'PEAR/Config.php';
  85039. require_once 'phar://go-pear.phar/' . 'PEAR/Command.php';
  85040. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  85041. class PEAR_Start extends PEAR
  85042. {
  85043. var $bin_dir;
  85044. var $data_dir;
  85045. var $cfg_dir;
  85046. var $www_dir;
  85047. var $man_dir;
  85048. var $install_pfc;
  85049. var $corePackages =
  85050. array(
  85051. 'Archive_Tar',
  85052. 'Console_Getopt',
  85053. 'PEAR',
  85054. 'Structures_Graph',
  85055. 'XML_Util',
  85056. );
  85057. var $local_dir = array();
  85058. var $origpwd;
  85059. var $pfc_packages = array(
  85060. 'DB',
  85061. 'Net_Socket',
  85062. 'Net_SMTP',
  85063. 'Mail',
  85064. 'XML_Parser',
  85065. 'XML_RPC',
  85066. 'PHPUnit'
  85067. );
  85068. var $php_dir;
  85069. var $php_bin;
  85070. var $pear_conf;
  85071. var $validPHPBin = false;
  85072. var $test_dir;
  85073. var $download_dir;
  85074. var $temp_dir;
  85075. var $config =
  85076. array(
  85077. 'prefix',
  85078. 'bin_dir',
  85079. 'php_dir',
  85080. 'doc_dir',
  85081. 'data_dir',
  85082. 'cfg_dir',
  85083. 'www_dir',
  85084. 'man_dir',
  85085. 'test_dir',
  85086. 'temp_dir',
  85087. 'download_dir',
  85088. 'pear_conf',
  85089. );
  85090. var $prefix;
  85091. var $progress = 0;
  85092. var $configPrompt =
  85093. array(
  85094. 'prefix' => 'Installation base ($prefix)',
  85095. 'temp_dir' => 'Temporary directory for processing',
  85096. 'download_dir' => 'Temporary directory for downloads',
  85097. 'bin_dir' => 'Binaries directory',
  85098. 'php_dir' => 'PHP code directory ($php_dir)',
  85099. 'doc_dir' => 'Documentation directory',
  85100. 'data_dir' => 'Data directory',
  85101. 'cfg_dir' => 'User-modifiable configuration files directory',
  85102. 'www_dir' => 'Public Web Files directory',
  85103. 'man_dir' => 'System manual pages directory',
  85104. 'test_dir' => 'Tests directory',
  85105. 'pear_conf' => 'Name of configuration file',
  85106. );
  85107. var $localInstall;
  85108. var $PEARConfig;
  85109. var $tarball = array();
  85110. var $ptmp;
  85111. function __construct()
  85112. {
  85113. parent::__construct();
  85114. if (OS_WINDOWS) {
  85115. $this->configPrompt['php_bin'] = 'Path to CLI php.exe';
  85116. $this->config[] = 'php_bin';
  85117. $this->prefix = getcwd();
  85118. if (!@is_dir($this->prefix)) {
  85119. if (@is_dir('c:\php5')) {
  85120. $this->prefix = 'c:\php5';
  85121. } elseif (@is_dir('c:\php4')) {
  85122. $this->prefix = 'c:\php4';
  85123. } elseif (@is_dir('c:\php')) {
  85124. $this->prefix = 'c:\php';
  85125. }
  85126. }
  85127. $slash = "\\";
  85128. if (strrpos($this->prefix, '\\') === (strlen($this->prefix) - 1)) {
  85129. $slash = '';
  85130. }
  85131. $this->localInstall = false;
  85132. $this->bin_dir = '$prefix';
  85133. $this->temp_dir = '$prefix' . $slash . 'tmp';
  85134. $this->download_dir = '$prefix' . $slash . 'tmp';
  85135. $this->php_dir = '$prefix' . $slash . 'pear';
  85136. $this->doc_dir = '$prefix' . $slash . 'docs';
  85137. $this->data_dir = '$prefix' . $slash . 'data';
  85138. $this->test_dir = '$prefix' . $slash . 'tests';
  85139. $this->www_dir = '$prefix' . $slash . 'www';
  85140. $this->man_dir = '$prefix' . $slash . 'man';
  85141. $this->cfg_dir = '$prefix' . $slash . 'cfg';
  85142. $this->pear_conf = PEAR_CONFIG_SYSCONFDIR . '\\pear.ini';
  85143. /*
  85144. * Detects php.exe
  85145. */
  85146. $this->validPHPBin = true;
  85147. if ($t = $this->safeGetenv('PHP_PEAR_PHP_BIN')) {
  85148. $this->php_bin = dirname($t);
  85149. } elseif ($t = $this->safeGetenv('PHP_BIN')) {
  85150. $this->php_bin = dirname($t);
  85151. } elseif ($t = System::which('php')) {
  85152. $this->php_bin = dirname($t);
  85153. } elseif (is_file($this->prefix . '\cli\php.exe')) {
  85154. $this->php_bin = $this->prefix . '\cli';
  85155. } elseif (is_file($this->prefix . '\php.exe')) {
  85156. $this->php_bin = $this->prefix;
  85157. }
  85158. $phpexe = OS_WINDOWS ? '\\php.exe' : '/php';
  85159. if ($this->php_bin && !is_file($this->php_bin . $phpexe)) {
  85160. $this->php_bin = '';
  85161. } else {
  85162. if (strpos($this->php_bin, ':') === 0) {
  85163. $this->php_bin = getcwd() . DIRECTORY_SEPARATOR . $this->php_bin;
  85164. }
  85165. }
  85166. if (!is_file($this->php_bin . $phpexe)) {
  85167. if (is_file('c:/php/cli/php.exe')) {
  85168. $this->php_bin = 'c"\\php\\cli';
  85169. } elseif (is_file('c:/php5/php.exe')) {
  85170. $this->php_bin = 'c:\\php5';
  85171. } elseif (is_file('c:/php4/cli/php.exe')) {
  85172. $this->php_bin = 'c:\\php4\\cli';
  85173. } else {
  85174. $this->validPHPBin = false;
  85175. }
  85176. }
  85177. } else {
  85178. $this->prefix = dirname(PHP_BINDIR);
  85179. $this->pear_conf = PEAR_CONFIG_SYSCONFDIR . '/pear.conf';
  85180. if ($this->getCurrentUser() != 'root') {
  85181. $this->prefix = $this->safeGetenv('HOME') . '/pear';
  85182. $this->pear_conf = $this->safeGetenv('HOME') . '.pearrc';
  85183. }
  85184. $this->bin_dir = '$prefix/bin';
  85185. $this->php_dir = '$prefix/share/pear';
  85186. $this->temp_dir = '/tmp/pear/install';
  85187. $this->download_dir = '/tmp/pear/install';
  85188. $this->doc_dir = '$prefix/docs';
  85189. $this->www_dir = '$prefix/www';
  85190. $this->cfg_dir = '$prefix/cfg';
  85191. $this->data_dir = '$prefix/data';
  85192. $this->test_dir = '$prefix/tests';
  85193. $this->man_dir = '$prefix/man';
  85194. // check if the user has installed PHP with PHP or GNU layout
  85195. if (@is_dir("$this->prefix/lib/php/.registry")) {
  85196. $this->php_dir = '$prefix/lib/php';
  85197. } elseif (@is_dir("$this->prefix/share/pear/lib/.registry")) {
  85198. $this->php_dir = '$prefix/share/pear/lib';
  85199. $this->doc_dir = '$prefix/share/pear/docs';
  85200. $this->data_dir = '$prefix/share/pear/data';
  85201. $this->test_dir = '$prefix/share/pear/tests';
  85202. } elseif (@is_dir("$this->prefix/share/php/.registry")) {
  85203. $this->php_dir = '$prefix/share/php';
  85204. }
  85205. }
  85206. }
  85207. /**
  85208. * Get the name of the user running the script.
  85209. * Only needed on unix for now.
  85210. *
  85211. * @return string Name of the user ("root", "cweiske")
  85212. */
  85213. function getCurrentUser()
  85214. {
  85215. if (isset($_ENV['USER'])) {
  85216. return $_ENV['USER'];
  85217. } else {
  85218. return trim(`whoami`);
  85219. }
  85220. }
  85221. function safeGetenv($var)
  85222. {
  85223. if (is_array($_ENV) && isset($_ENV[$var])) {
  85224. return $_ENV[$var];
  85225. }
  85226. return getenv($var);
  85227. }
  85228. function show($stuff)
  85229. {
  85230. print $stuff;
  85231. }
  85232. function locatePackagesToInstall()
  85233. {
  85234. $dp = @opendir(dirname(__FILE__) . '/go-pear-tarballs');
  85235. if (empty($dp)) {
  85236. return PEAR::raiseError("while locating packages to install: opendir('" .
  85237. dirname(__FILE__) . "/go-pear-tarballs') failed");
  85238. }
  85239. $potentials = array();
  85240. while (false !== ($entry = readdir($dp))) {
  85241. if ($entry[0] == '.' || !in_array(substr($entry, -4), array('.tar', '.tgz'))) {
  85242. continue;
  85243. }
  85244. $potentials[] = $entry;
  85245. }
  85246. closedir($dp);
  85247. $notfound = array();
  85248. foreach ($this->corePackages as $package) {
  85249. foreach ($potentials as $i => $candidate) {
  85250. if (preg_match('/^' . $package . '-' . _PEAR_COMMON_PACKAGE_VERSION_PREG
  85251. . '\.(tar|tgz)\\z/', $candidate)) {
  85252. $this->tarball[$package] = dirname(__FILE__) . '/go-pear-tarballs/' . $candidate;
  85253. unset($potentials[$i]);
  85254. continue 2;
  85255. }
  85256. }
  85257. $notfound[] = $package;
  85258. }
  85259. if (count($notfound)) {
  85260. return PEAR::raiseError("No tarballs found for core packages: " .
  85261. implode(', ', $notfound));
  85262. }
  85263. $this->tarball = array_merge($this->tarball, $potentials);
  85264. }
  85265. function setupTempStuff()
  85266. {
  85267. if (!($this->ptmp = System::mktemp(array('-d')))) {
  85268. $this->show("System's Tempdir failed, trying to use \$prefix/tmp ...");
  85269. $res = System::mkDir(array($this->prefix . '/tmp'));
  85270. if (!$res) {
  85271. return PEAR::raiseError('mkdir ' . $this->prefix . '/tmp ... failed');
  85272. }
  85273. $_temp = tempnam($this->prefix . '/tmp', 'gope');
  85274. System::rm(array('-rf', $_temp));
  85275. System::mkdir(array('-p','-m', '0700', $_temp));
  85276. $this->ptmp = $this->prefix . '/tmp';
  85277. $ok = @chdir($this->ptmp);
  85278. if (!$ok) { // This should not happen, really ;)
  85279. $this->bail('chdir ' . $this->ptmp . ' ... failed');
  85280. }
  85281. print "ok\n";
  85282. // Adjust TEMPDIR envvars
  85283. if (!isset($_ENV)) {
  85284. $_ENV = array();
  85285. };
  85286. $_ENV['TMPDIR'] = $_ENV['TEMP'] = $this->prefix . '/tmp';
  85287. }
  85288. return @chdir($this->ptmp);
  85289. }
  85290. /**
  85291. * Try to detect the kind of SAPI used by the
  85292. * the given php.exe.
  85293. * @author Pierrre-Alain Joye
  85294. */
  85295. function win32DetectPHPSAPI()
  85296. {
  85297. if ($this->php_bin != '') {
  85298. if (OS_WINDOWS) {
  85299. exec('"' . $this->php_bin . '\\php.exe" -v', $res);
  85300. } else {
  85301. exec('"' . $this->php_bin . '/php" -v', $res);
  85302. }
  85303. if (is_array($res)) {
  85304. if (isset($res[0]) && strpos($res[0],"(cli)")) {
  85305. return 'cli';
  85306. }
  85307. if (isset($res[0]) && strpos($res[0],"cgi")) {
  85308. return 'cgi';
  85309. }
  85310. if (isset($res[0]) && strpos($res[0],"cgi-fcgi")) {
  85311. return 'cgi';
  85312. }
  85313. return 'unknown';
  85314. }
  85315. }
  85316. return 'unknown';
  85317. }
  85318. function doInstall()
  85319. {
  85320. print "Beginning install...\n";
  85321. // finish php_bin config
  85322. if (OS_WINDOWS) {
  85323. $this->php_bin .= '\\php.exe';
  85324. } else {
  85325. $this->php_bin .= '/php';
  85326. }
  85327. $this->PEARConfig = &PEAR_Config::singleton($this->pear_conf, $this->pear_conf);
  85328. $this->PEARConfig->set('preferred_state', 'stable');
  85329. foreach ($this->config as $var) {
  85330. if ($var == 'pear_conf' || $var == 'prefix') {
  85331. continue;
  85332. }
  85333. $this->PEARConfig->set($var, $this->$var);
  85334. }
  85335. $this->PEARConfig->store();
  85336. // $this->PEARConfig->set('verbose', 6);
  85337. print "Configuration written to $this->pear_conf...\n";
  85338. $this->registry = &$this->PEARConfig->getRegistry();
  85339. print "Initialized registry...\n";
  85340. $install = &PEAR_Command::factory('install', $this->PEARConfig);
  85341. print "Preparing to install...\n";
  85342. $options = array(
  85343. 'nodeps' => true,
  85344. 'force' => true,
  85345. 'upgrade' => true,
  85346. );
  85347. foreach ($this->tarball as $pkg => $src) {
  85348. print "installing $src...\n";
  85349. }
  85350. $install->run('install', $options, array_values($this->tarball));
  85351. }
  85352. function postProcessConfigVars()
  85353. {
  85354. foreach ($this->config as $n => $var) {
  85355. for ($m = 1; $m <= count($this->config); $m++) {
  85356. $var2 = $this->config[$m];
  85357. $this->$var = str_replace('$'.$var2, $this->$var2, $this->$var);
  85358. }
  85359. }
  85360. foreach ($this->config as $var) {
  85361. $dir = $this->$var;
  85362. if (!preg_match('/_dir\\z/', $var)) {
  85363. continue;
  85364. }
  85365. if (!@is_dir($dir)) {
  85366. if (!System::mkDir(array('-p', $dir))) {
  85367. $root = OS_WINDOWS ? 'administrator' : 'root';
  85368. return PEAR::raiseError("Unable to create {$this->configPrompt[$var]} $dir.
  85369. Run this script as $root or pick another location.\n");
  85370. }
  85371. }
  85372. }
  85373. }
  85374. /**
  85375. * Get the php.ini file used with the current
  85376. * process or with the given php.exe
  85377. *
  85378. * Horrible hack, but well ;)
  85379. *
  85380. * Not used yet, will add the support later
  85381. * @author Pierre-Alain Joye <paj@pearfr.org>
  85382. */
  85383. function getPhpiniPath()
  85384. {
  85385. $pathIni = get_cfg_var('cfg_file_path');
  85386. if ($pathIni && is_file($pathIni)) {
  85387. return $pathIni;
  85388. }
  85389. // Oh well, we can keep this too :)
  85390. // I dunno if get_cfg_var() is safe on every OS
  85391. if (OS_WINDOWS) {
  85392. // on Windows, we can be pretty sure that there is a php.ini
  85393. // file somewhere
  85394. do {
  85395. $php_ini = PHP_CONFIG_FILE_PATH . DIRECTORY_SEPARATOR . 'php.ini';
  85396. if (@file_exists($php_ini)) {
  85397. break;
  85398. }
  85399. $php_ini = 'c:\winnt\php.ini';
  85400. if (@file_exists($php_ini)) {
  85401. break;
  85402. }
  85403. $php_ini = 'c:\windows\php.ini';
  85404. } while (false);
  85405. } else {
  85406. $php_ini = PHP_CONFIG_FILE_PATH . DIRECTORY_SEPARATOR . 'php.ini';
  85407. }
  85408. if (@is_file($php_ini)) {
  85409. return $php_ini;
  85410. }
  85411. // We re running in hackz&troubles :)
  85412. ob_implicit_flush(false);
  85413. ob_start();
  85414. phpinfo(INFO_GENERAL);
  85415. $strInfo = ob_get_contents();
  85416. ob_end_clean();
  85417. ob_implicit_flush(true);
  85418. if (php_sapi_name() != 'cli') {
  85419. $strInfo = strip_tags($strInfo,'<td>');
  85420. $arrayInfo = explode("</td>", $strInfo );
  85421. $cli = false;
  85422. } else {
  85423. $arrayInfo = explode("\n", $strInfo);
  85424. $cli = true;
  85425. }
  85426. foreach ($arrayInfo as $val) {
  85427. if (strpos($val,"php.ini")) {
  85428. if ($cli) {
  85429. list(,$pathIni) = explode('=>', $val);
  85430. } else {
  85431. $pathIni = strip_tags(trim($val));
  85432. }
  85433. $pathIni = trim($pathIni);
  85434. if (is_file($pathIni)) {
  85435. return $pathIni;
  85436. }
  85437. }
  85438. }
  85439. return false;
  85440. }
  85441. }
  85442. ?>
  85443. <?php
  85444. require_once 'phar://go-pear.phar/' . 'PEAR/Start.php';
  85445. class PEAR_Start_CLI extends PEAR_Start
  85446. {
  85447. var $descLength;
  85448. var $descFormat;
  85449. var $first;
  85450. var $last;
  85451. var $origpwd;
  85452. var $tty;
  85453. /**
  85454. * Path to .vbs file for directory selection
  85455. * @var string
  85456. */
  85457. var $cscript;
  85458. /**
  85459. * SAPI for selected php.exe
  85460. * @var string
  85461. */
  85462. var $php_bin_sapi;
  85463. function __construct()
  85464. {
  85465. parent::__construct();
  85466. ini_set('html_errors', 0);
  85467. define('WIN32GUI', OS_WINDOWS && php_sapi_name() == 'cli' && System::which('cscript'));
  85468. $this->tty = OS_WINDOWS ? @fopen('\con', 'r') : @fopen('/dev/tty', 'r');
  85469. if (!$this->tty) {
  85470. $this->tty = fopen('php://stdin', 'r');
  85471. }
  85472. $this->origpwd = getcwd();
  85473. $this->config = array_keys($this->configPrompt);
  85474. // make indices run from 1...
  85475. array_unshift($this->config, "");
  85476. unset($this->config[0]);
  85477. reset($this->config);
  85478. $this->descLength = max(array_map('strlen', $this->configPrompt));
  85479. $this->descFormat = "%-{$this->descLength}s";
  85480. $this->first = key($this->config);
  85481. end($this->config);
  85482. $this->last = key($this->config);
  85483. PEAR_Command::setFrontendType('CLI');
  85484. }
  85485. function _PEAR_Start_CLI()
  85486. {
  85487. if ($this->tty) {
  85488. @fclose($this->tty);
  85489. }
  85490. if ($this->cscript) {
  85491. @unlink($this->cscript);
  85492. }
  85493. }
  85494. function run()
  85495. {
  85496. if (PEAR::isError($err = $this->locatePackagesToInstall())) {
  85497. return $err;
  85498. }
  85499. $this->startupQuestion();
  85500. $this->setupTempStuff();
  85501. $this->getInstallLocations();
  85502. $this->displayPreamble();
  85503. if (PEAR::isError($err = $this->postProcessConfigVars())) {
  85504. return $err;
  85505. }
  85506. $this->doInstall();
  85507. $this->finishInstall();
  85508. }
  85509. function startupQuestion()
  85510. {
  85511. if (OS_WINDOWS) {
  85512. print "
  85513. Are you installing a system-wide PEAR or a local copy?
  85514. (system|local) [system] : ";
  85515. $tmp = trim(fgets($this->tty, 1024));
  85516. if (!empty($tmp) && strtolower($tmp) !== 'system') {
  85517. print "Please confirm local copy by typing 'yes' : ";
  85518. $tmp = trim(fgets($this->tty, 1024));
  85519. if (strtolower($tmp) == 'yes') {
  85520. $slash = "\\";
  85521. if (strrpos($this->prefix, '\\') === (strlen($this->prefix) - 1)) {
  85522. $slash = '';
  85523. }
  85524. $this->localInstall = true;
  85525. $this->pear_conf = '$prefix' . $slash . 'pear.ini';
  85526. }
  85527. }
  85528. } else {
  85529. if ($this->getCurrentUser() == 'root') {
  85530. return;
  85531. }
  85532. $this->pear_conf = $this->safeGetenv('HOME') . '/.pearrc';
  85533. }
  85534. }
  85535. function getInstallLocations()
  85536. {
  85537. while (true) {
  85538. print "
  85539. Below is a suggested file layout for your new PEAR installation. To
  85540. change individual locations, type the number in front of the
  85541. directory. Type 'all' to change all of them or simply press Enter to
  85542. accept these locations.
  85543. ";
  85544. foreach ($this->config as $n => $var) {
  85545. $fullvar = $this->$var;
  85546. foreach ($this->config as $blah => $unused) {
  85547. foreach ($this->config as $m => $var2) {
  85548. $fullvar = str_replace('$'.$var2, $this->$var2, $fullvar);
  85549. }
  85550. }
  85551. printf("%2d. $this->descFormat : %s\n", $n, $this->configPrompt[$var], $fullvar);
  85552. }
  85553. print "\n$this->first-$this->last, 'all' or Enter to continue: ";
  85554. $tmp = trim(fgets($this->tty, 1024));
  85555. if (empty($tmp)) {
  85556. if (OS_WINDOWS && !$this->validPHPBin) {
  85557. echo "**ERROR**
  85558. Please, enter the php.exe path.
  85559. ";
  85560. } else {
  85561. break;
  85562. }
  85563. }
  85564. if (isset($this->config[(int)$tmp])) {
  85565. $var = $this->config[(int)$tmp];
  85566. $desc = $this->configPrompt[$var];
  85567. $current = $this->$var;
  85568. if (WIN32GUI && $var != 'pear_conf'){
  85569. $tmp = $this->win32BrowseForFolder("Choose a Folder for $desc [$current] :");
  85570. $tmp.= '\\';
  85571. } else {
  85572. print "(Use \$prefix as a shortcut for '$this->prefix', etc.)
  85573. $desc [$current] : ";
  85574. $tmp = trim(fgets($this->tty, 1024));
  85575. }
  85576. $old = $this->$var;
  85577. $this->$var = $$var = $tmp;
  85578. if (OS_WINDOWS && $var=='php_bin') {
  85579. if ($this->validatePhpExecutable($tmp)) {
  85580. $this->php_bin = $tmp;
  85581. } else {
  85582. $this->php_bin = $old;
  85583. }
  85584. }
  85585. } elseif ($tmp == 'all') {
  85586. foreach ($this->config as $n => $var) {
  85587. $desc = $this->configPrompt[$var];
  85588. $current = $this->$var;
  85589. print "$desc [$current] : ";
  85590. $tmp = trim(fgets($this->tty, 1024));
  85591. if (!empty($tmp)) {
  85592. $this->$var = $tmp;
  85593. }
  85594. }
  85595. }
  85596. }
  85597. }
  85598. function validatePhpExecutable($tmp)
  85599. {
  85600. if (OS_WINDOWS) {
  85601. if (strpos($tmp, 'php.exe')) {
  85602. $tmp = str_replace('php.exe', '', $tmp);
  85603. }
  85604. if (file_exists($tmp . DIRECTORY_SEPARATOR . 'php.exe')) {
  85605. $tmp = $tmp . DIRECTORY_SEPARATOR . 'php.exe';
  85606. $this->php_bin_sapi = $this->win32DetectPHPSAPI();
  85607. if ($this->php_bin_sapi=='cgi'){
  85608. print "
  85609. ******************************************************************************
  85610. NOTICE! We found php.exe under $this->php_bin, it uses a $this->php_bin_sapi SAPI.
  85611. PEAR commandline tool works well with it.
  85612. If you have a CLI php.exe available, we recommend using it.
  85613. Press Enter to continue...";
  85614. $tmp = trim(fgets($this->tty, 1024));
  85615. } elseif ($this->php_bin_sapi=='unknown') {
  85616. print "
  85617. ******************************************************************************
  85618. WARNING! We found php.exe under $this->php_bin, it uses an $this->php_bin_sapi SAPI.
  85619. PEAR commandline tool has NOT been tested with it.
  85620. If you have a CLI (or CGI) php.exe available, we strongly recommend using it.
  85621. Press Enter to continue...";
  85622. $tmp = trim(fgets($this->tty, 1024));
  85623. }
  85624. echo "php.exe (sapi: $this->php_bin_sapi) found.\n\n";
  85625. return $this->validPHPBin = true;
  85626. } else {
  85627. echo "**ERROR**: not a folder, or no php.exe found in this folder.
  85628. Press Enter to continue...";
  85629. $tmp = trim(fgets($this->tty, 1024));
  85630. return $this->validPHPBin = false;
  85631. }
  85632. }
  85633. }
  85634. /**
  85635. * Create a vbs script to browse the getfolder dialog, called
  85636. * by cscript, if it's available.
  85637. * $label is the label text in the header of the dialog box
  85638. *
  85639. * TODO:
  85640. * - Do not show Control panel
  85641. * - Replace WSH with calls to w32 as soon as callbacks work
  85642. * @author Pierrre-Alain Joye
  85643. */
  85644. function win32BrowseForFolder($label)
  85645. {
  85646. $wsh_browserfolder = 'Option Explicit
  85647. Dim ArgObj, var1, var2, sa, sFld
  85648. Set ArgObj = WScript.Arguments
  85649. Const BIF_EDITBOX = &H10
  85650. Const BIF_NEWDIALOGSTYLE = &H40
  85651. Const BIF_RETURNONLYFSDIRS = &H0001
  85652. Const BIF_DONTGOBELOWDOMAIN = &H0002
  85653. Const BIF_STATUSTEXT = &H0004
  85654. Const BIF_RETURNFSANCESTORS = &H0008
  85655. Const BIF_VALIDATE = &H0020
  85656. Const BIF_BROWSEFORCOMPUTER = &H1000
  85657. Const BIF_BROWSEFORPRINTER = &H2000
  85658. Const BIF_BROWSEINCLUDEFILES = &H4000
  85659. Const OFN_LONGNAMES = &H200000
  85660. Const OFN_NOLONGNAMES = &H40000
  85661. Const ssfDRIVES = &H11
  85662. Const ssfNETWORK = &H12
  85663. Set sa = CreateObject("Shell.Application")
  85664. var1=ArgObj(0)
  85665. Set sFld = sa.BrowseForFolder(0, var1, BIF_EDITBOX + BIF_VALIDATE + BIF_BROWSEINCLUDEFILES + BIF_RETURNFSANCESTORS+BIF_NEWDIALOGSTYLE , ssfDRIVES )
  85666. if not sFld is nothing Then
  85667. if not left(sFld.items.item.path,1)=":" Then
  85668. WScript.Echo sFld.items.item.path
  85669. Else
  85670. WScript.Echo "invalid"
  85671. End If
  85672. Else
  85673. WScript.Echo "cancel"
  85674. End If
  85675. ';
  85676. if (!$this->cscript) {
  85677. $this->cscript = $this->ptmp . DIRECTORY_SEPARATOR . "bf.vbs";
  85678. // TODO: use file_put_contents()
  85679. $fh = fopen($this->cscript, "wb+");
  85680. fwrite($fh, $wsh_browserfolder, strlen($wsh_browserfolder));
  85681. fclose($fh);
  85682. }
  85683. exec('cscript ' . escapeshellarg($this->cscript) . ' "' . escapeshellarg($label) . '" //noLogo', $arPath);
  85684. if (!count($arPath) || $arPath[0]=='' || $arPath[0]=='cancel') {
  85685. return '';
  85686. } elseif ($arPath[0]=='invalid') {
  85687. echo "Invalid Path.\n";
  85688. return '';
  85689. }
  85690. return $arPath[0];
  85691. }
  85692. function displayPreamble()
  85693. {
  85694. if (OS_WINDOWS) {
  85695. /*
  85696. * Checks PHP SAPI version under windows/CLI
  85697. */
  85698. if ($this->php_bin == '') {
  85699. print "
  85700. We do not find any php.exe, please select the php.exe folder (CLI is
  85701. recommended, usually in c:\php\cli\php.exe)
  85702. ";
  85703. $this->validPHPBin = false;
  85704. } elseif (strlen($this->php_bin)) {
  85705. $this->php_bin_sapi = $this->win32DetectPHPSAPI();
  85706. $this->validPHPBin = true;
  85707. switch ($this->php_bin_sapi) {
  85708. case 'cli':
  85709. break;
  85710. case 'cgi':
  85711. case 'cgi-fcgi':
  85712. print "
  85713. *NOTICE*
  85714. We found php.exe under $this->php_bin, it uses a $this->php_bin_sapi SAPI. PEAR commandline
  85715. tool works well with it, if you have a CLI php.exe available, we
  85716. recommend using it.
  85717. ";
  85718. break;
  85719. default:
  85720. print "
  85721. *WARNING*
  85722. We found php.exe under $this->php_bin, it uses an unknown SAPI. PEAR commandline
  85723. tool has not been tested with it, if you have a CLI (or CGI) php.exe available,
  85724. we strongly recommend using it.
  85725. ";
  85726. break;
  85727. }
  85728. }
  85729. }
  85730. }
  85731. function finishInstall()
  85732. {
  85733. $sep = OS_WINDOWS ? ';' : ':';
  85734. $include_path = explode($sep, ini_get('include_path'));
  85735. if (OS_WINDOWS) {
  85736. $found = false;
  85737. $t = strtolower($this->php_dir);
  85738. foreach ($include_path as $path) {
  85739. if ($t == strtolower($path)) {
  85740. $found = true;
  85741. break;
  85742. }
  85743. }
  85744. } else {
  85745. $found = in_array($this->php_dir, $include_path);
  85746. }
  85747. if (!$found) {
  85748. print "
  85749. ******************************************************************************
  85750. WARNING! The include_path defined in the currently used php.ini does not
  85751. contain the PEAR PHP directory you just specified:
  85752. <$this->php_dir>
  85753. If the specified directory is also not in the include_path used by
  85754. your scripts, you will have problems getting any PEAR packages working.
  85755. ";
  85756. if ($php_ini = $this->getPhpiniPath()) {
  85757. print "\n\nWould you like to alter php.ini <$php_ini>? [Y/n] : ";
  85758. $alter_phpini = !stristr(fgets($this->tty, 1024), "n");
  85759. if ($alter_phpini) {
  85760. $this->alterPhpIni($php_ini);
  85761. } else {
  85762. if (OS_WINDOWS) {
  85763. print "
  85764. Please look over your php.ini file to make sure
  85765. $this->php_dir is in your include_path.";
  85766. } else {
  85767. print "
  85768. I will add a workaround for this in the 'pear' command to make sure
  85769. the installer works, but please look over your php.ini or Apache
  85770. configuration to make sure $this->php_dir is in your include_path.
  85771. ";
  85772. }
  85773. }
  85774. }
  85775. print "
  85776. Current include path : ".ini_get('include_path')."
  85777. Configured directory : $this->php_dir
  85778. Currently used php.ini (guess) : $php_ini
  85779. ";
  85780. print "Press Enter to continue: ";
  85781. fgets($this->tty, 1024);
  85782. }
  85783. $pear_cmd = $this->bin_dir . DIRECTORY_SEPARATOR . 'pear';
  85784. $pear_cmd = OS_WINDOWS ? strtolower($pear_cmd).'.bat' : $pear_cmd;
  85785. // check that the installed pear and the one in the path are the same (if any)
  85786. $pear_old = System::which(OS_WINDOWS ? 'pear.bat' : 'pear', $this->bin_dir);
  85787. if ($pear_old && ($pear_old != $pear_cmd)) {
  85788. // check if it is a link or symlink
  85789. $islink = OS_WINDOWS ? false : is_link($pear_old) ;
  85790. if ($islink && readlink($pear_old) != $pear_cmd) {
  85791. print "\n** WARNING! The link $pear_old does not point to the " .
  85792. "installed $pear_cmd\n";
  85793. } elseif (!$this->localInstall && is_writable($pear_old) && !is_dir($pear_old)) {
  85794. rename($pear_old, "{$pear_old}_old");
  85795. print "\n** WARNING! Backed up old pear to {$pear_old}_old\n";
  85796. } else {
  85797. print "\n** WARNING! Old version found at $pear_old, please remove it or ".
  85798. "be sure to use the new $pear_cmd command\n";
  85799. }
  85800. }
  85801. print "\nThe 'pear' command is now at your service at $pear_cmd\n";
  85802. // Alert the user if the pear cmd is not in PATH
  85803. $old_dir = $pear_old ? dirname($pear_old) : false;
  85804. if (!$this->which('pear', $old_dir)) {
  85805. print "
  85806. ** The 'pear' command is not currently in your PATH, so you need to
  85807. ** use '$pear_cmd' until you have added
  85808. ** '$this->bin_dir' to your PATH environment variable.
  85809. ";
  85810. print "Run it without parameters to see the available actions, try 'pear list'
  85811. to see what packages are installed, or 'pear help' for help.
  85812. For more information about PEAR, see:
  85813. http://pear.php.net/faq.php
  85814. http://pear.php.net/manual/
  85815. Thanks for using go-pear!
  85816. ";
  85817. }
  85818. if (OS_WINDOWS && !$this->localInstall) {
  85819. $this->win32CreateRegEnv();
  85820. }
  85821. }
  85822. /**
  85823. * System::which() does not allow path exclusion
  85824. */
  85825. function which($program, $dont_search_in = false)
  85826. {
  85827. if (OS_WINDOWS) {
  85828. if ($_path = $this->safeGetEnv('Path')) {
  85829. $dirs = explode(';', $_path);
  85830. } else {
  85831. $dirs = explode(';', $this->safeGetEnv('PATH'));
  85832. }
  85833. foreach ($dirs as $i => $dir) {
  85834. $dirs[$i] = strtolower(realpath($dir));
  85835. }
  85836. if ($dont_search_in) {
  85837. $dont_search_in = strtolower(realpath($dont_search_in));
  85838. }
  85839. if ($dont_search_in &&
  85840. ($key = array_search($dont_search_in, $dirs)) !== false)
  85841. {
  85842. unset($dirs[$key]);
  85843. }
  85844. foreach ($dirs as $dir) {
  85845. $dir = str_replace('\\\\', '\\', $dir);
  85846. if (!strlen($dir)) {
  85847. continue;
  85848. }
  85849. if ($dir[strlen($dir) - 1] != '\\') {
  85850. $dir .= '\\';
  85851. }
  85852. $tmp = $dir . $program;
  85853. $info = pathinfo($tmp);
  85854. if (isset($info['extension']) && in_array(strtolower($info['extension']),
  85855. array('exe', 'com', 'bat', 'cmd'))) {
  85856. if (file_exists($tmp)) {
  85857. return strtolower($tmp);
  85858. }
  85859. } elseif (file_exists($ret = $tmp . '.exe') ||
  85860. file_exists($ret = $tmp . '.com') ||
  85861. file_exists($ret = $tmp . '.bat') ||
  85862. file_exists($ret = $tmp . '.cmd')) {
  85863. return strtolower($ret);
  85864. }
  85865. }
  85866. } else {
  85867. $dirs = explode(':', $this->safeGetEnv('PATH'));
  85868. if ($dont_search_in &&
  85869. ($key = array_search($dont_search_in, $dirs)) !== false)
  85870. {
  85871. unset($dirs[$key]);
  85872. }
  85873. foreach ($dirs as $dir) {
  85874. if (is_executable("$dir/$program")) {
  85875. return "$dir/$program";
  85876. }
  85877. }
  85878. }
  85879. return false;
  85880. }
  85881. /**
  85882. * Not optimized, but seems to work, if some nice
  85883. * peardev will test it? :)
  85884. *
  85885. * @author Pierre-Alain Joye <paj@pearfr.org>
  85886. */
  85887. function alterPhpIni($pathIni='')
  85888. {
  85889. $foundAt = array();
  85890. $iniSep = OS_WINDOWS ? ';' : ':';
  85891. if ($pathIni=='') {
  85892. $pathIni = $this->getPhpiniPath();
  85893. }
  85894. $arrayIni = file($pathIni);
  85895. $i=0;
  85896. $found=0;
  85897. // Looks for each active include_path directives
  85898. foreach ($arrayIni as $iniLine) {
  85899. $iniLine = trim($iniLine);
  85900. $iniLine = str_replace(array("\n", "\r"), array('', ''), $iniLine);
  85901. if (preg_match("/^\s*include_path/", $iniLine)) {
  85902. $foundAt[] = $i;
  85903. $found++;
  85904. }
  85905. $i++;
  85906. }
  85907. if ($found) {
  85908. $includeLine = $arrayIni[$foundAt[0]];
  85909. list(, $currentPath) = explode('=', $includeLine);
  85910. $currentPath = trim($currentPath);
  85911. if (substr($currentPath,0,1) == '"') {
  85912. $currentPath = substr($currentPath, 1, strlen($currentPath) - 2);
  85913. }
  85914. $arrayPath = explode($iniSep, $currentPath);
  85915. $newPath = array();
  85916. if ($arrayPath[0]=='.') {
  85917. $newPath[0] = '.';
  85918. $newPath[1] = $this->php_dir;
  85919. array_shift($arrayPath);
  85920. } else {
  85921. $newPath[0] = $this->php_dir;
  85922. }
  85923. foreach ($arrayPath as $path) {
  85924. $newPath[]= $path;
  85925. }
  85926. } else {
  85927. $newPath = array();
  85928. $newPath[0] = '.';
  85929. $newPath[1] = $this->php_dir;
  85930. $foundAt[] = count($arrayIni); // add a new line if none is present
  85931. }
  85932. $nl = OS_WINDOWS ? "\r\n" : "\n";
  85933. $includepath = 'include_path="' . implode($iniSep,$newPath) . '"';
  85934. $newInclude = "$nl$nl;***** Added by go-pear$nl" .
  85935. $includepath .
  85936. $nl . ";*****" .
  85937. $nl . $nl;
  85938. $arrayIni[$foundAt[0]] = $newInclude;
  85939. for ($i=1; $i<$found; $i++) {
  85940. $arrayIni[$foundAt[$i]]=';' . trim($arrayIni[$foundAt[$i]]);
  85941. }
  85942. $newIni = implode("", $arrayIni);
  85943. if (!($fh = @fopen($pathIni, "wb+"))) {
  85944. $prefixIni = $this->prefix . DIRECTORY_SEPARATOR . "php.ini-gopear";
  85945. $fh = fopen($prefixIni, "wb+");
  85946. if (!$fh) {
  85947. echo "
  85948. ******************************************************************************
  85949. WARNING: Cannot write to $pathIni nor in $this->prefix/php.ini-gopear. Please
  85950. modify manually your php.ini by adding:
  85951. $includepath
  85952. ";
  85953. return false;
  85954. } else {
  85955. fwrite($fh, $newIni, strlen($newIni));
  85956. fclose($fh);
  85957. echo "
  85958. ******************************************************************************
  85959. WARNING: Cannot write to $pathIni, but php.ini was successfully created
  85960. at <$this->prefix/php.ini-gopear>. Please replace the file <$pathIni> with
  85961. <$prefixIni> or modify your php.ini by adding:
  85962. $includepath
  85963. ";
  85964. }
  85965. } else {
  85966. fwrite($fh, $newIni, strlen($newIni));
  85967. fclose($fh);
  85968. echo "
  85969. php.ini <$pathIni> include_path updated.
  85970. ";
  85971. }
  85972. return true;
  85973. }
  85974. /**
  85975. * Generates a registry addOn for Win32 platform
  85976. * This addon set PEAR environment variables
  85977. * @author Pierrre-Alain Joye
  85978. */
  85979. function win32CreateRegEnv()
  85980. {
  85981. $nl = "\r\n";
  85982. $reg ='REGEDIT4'.$nl.
  85983. '[HKEY_CURRENT_USER\Environment]'. $nl .
  85984. '"PHP_PEAR_SYSCONF_DIR"="' . addslashes($this->prefix) . '"' . $nl .
  85985. '"PHP_PEAR_INSTALL_DIR"="' . addslashes($this->php_dir) . '"' . $nl .
  85986. '"PHP_PEAR_DOC_DIR"="' . addslashes($this->doc_dir) . '"' . $nl .
  85987. '"PHP_PEAR_BIN_DIR"="' . addslashes($this->bin_dir) . '"' . $nl .
  85988. '"PHP_PEAR_DATA_DIR"="' . addslashes($this->data_dir) . '"' . $nl .
  85989. '"PHP_PEAR_PHP_BIN"="' . addslashes($this->php_bin) . '"' . $nl .
  85990. '"PHP_PEAR_TEST_DIR"="' . addslashes($this->test_dir) . '"' . $nl;
  85991. $fh = fopen($this->prefix . DIRECTORY_SEPARATOR . 'PEAR_ENV.reg', 'wb');
  85992. if($fh){
  85993. fwrite($fh, $reg, strlen($reg));
  85994. fclose($fh);
  85995. echo "
  85996. * WINDOWS ENVIRONMENT VARIABLES *
  85997. For convenience, a REG file is available under {$this->prefix}PEAR_ENV.reg .
  85998. This file creates ENV variables for the current user.
  85999. Double-click this file to add it to the current user registry.
  86000. ";
  86001. }
  86002. }
  86003. function displayHTMLProgress()
  86004. {
  86005. }
  86006. }
  86007. ?>
  86008. <?php
  86009. /**
  86010. * PEAR_Task_Common, base class for installer tasks
  86011. *
  86012. * PHP versions 4 and 5
  86013. *
  86014. * @category pear
  86015. * @package PEAR
  86016. * @author Greg Beaver <cellog@php.net>
  86017. * @copyright 1997-2009 The Authors
  86018. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86019. * @link http://pear.php.net/package/PEAR
  86020. * @since File available since Release 1.4.0a1
  86021. */
  86022. /**#@+
  86023. * Error codes for task validation routines
  86024. */
  86025. define('PEAR_TASK_ERROR_NOATTRIBS', 1);
  86026. define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2);
  86027. define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3);
  86028. define('PEAR_TASK_ERROR_INVALID', 4);
  86029. /**#@-*/
  86030. define('PEAR_TASK_PACKAGE', 1);
  86031. define('PEAR_TASK_INSTALL', 2);
  86032. define('PEAR_TASK_PACKAGEANDINSTALL', 3);
  86033. /**
  86034. * A task is an operation that manipulates the contents of a file.
  86035. *
  86036. * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been
  86037. * processed and installed, and are designed to operate on all files containing the task.
  86038. * The Post-install script task simply takes advantage of the fact that it will be run
  86039. * after installation, replace is a simple task.
  86040. *
  86041. * Combining tasks is possible, but ordering is significant.
  86042. *
  86043. * <file name="test.php" role="php">
  86044. * <tasks:replace from="@data-dir@" to="data_dir" type="pear-config"/>
  86045. * <tasks:postinstallscript/>
  86046. * </file>
  86047. *
  86048. * This will first replace any instance of @data-dir@ in the test.php file
  86049. * with the path to the current data directory. Then, it will include the
  86050. * test.php file and run the script it contains to configure the package post-installation.
  86051. *
  86052. * @category pear
  86053. * @package PEAR
  86054. * @author Greg Beaver <cellog@php.net>
  86055. * @copyright 1997-2009 The Authors
  86056. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86057. * @version Release: 1.10.10
  86058. * @link http://pear.php.net/package/PEAR
  86059. * @since Class available since Release 1.4.0a1
  86060. * @abstract
  86061. */
  86062. class PEAR_Task_Common
  86063. {
  86064. /**
  86065. * Valid types for this version are 'simple' and 'multiple'
  86066. *
  86067. * - simple tasks operate on the contents of a file and write out changes to disk
  86068. * - multiple tasks operate on the contents of many files and write out the
  86069. * changes directly to disk
  86070. *
  86071. * Child task classes must override this property.
  86072. *
  86073. * @access protected
  86074. */
  86075. protected $type = 'simple';
  86076. /**
  86077. * Determines which install phase this task is executed under
  86078. */
  86079. public $phase = PEAR_TASK_INSTALL;
  86080. /**
  86081. * @access protected
  86082. */
  86083. protected $config;
  86084. /**
  86085. * @access protected
  86086. */
  86087. protected $registry;
  86088. /**
  86089. * @access protected
  86090. */
  86091. public $logger;
  86092. /**
  86093. * @access protected
  86094. */
  86095. protected $installphase;
  86096. /**
  86097. * @param PEAR_Config
  86098. * @param PEAR_Common
  86099. */
  86100. function __construct(&$config, &$logger, $phase)
  86101. {
  86102. $this->config = &$config;
  86103. $this->registry = &$config->getRegistry();
  86104. $this->logger = &$logger;
  86105. $this->installphase = $phase;
  86106. if ($this->type == 'multiple') {
  86107. $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this;
  86108. }
  86109. }
  86110. /**
  86111. * Validate the basic contents of a task tag.
  86112. *
  86113. * @param PEAR_PackageFile_v2
  86114. * @param array
  86115. * @param PEAR_Config
  86116. * @param array the entire parsed <file> tag
  86117. *
  86118. * @return true|array On error, return an array in format:
  86119. * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...])
  86120. *
  86121. * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in
  86122. * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and
  86123. * an array of legal values in
  86124. *
  86125. * @abstract
  86126. */
  86127. public static function validateXml($pkg, $xml, $config, $fileXml)
  86128. {
  86129. }
  86130. /**
  86131. * Initialize a task instance with the parameters
  86132. *
  86133. * @param array raw, parsed xml
  86134. * @param array attributes from the <file> tag containing this task
  86135. * @param string|null last installed version of this package
  86136. * @abstract
  86137. */
  86138. public function init($xml, $fileAttributes, $lastVersion)
  86139. {
  86140. }
  86141. /**
  86142. * Begin a task processing session. All multiple tasks will be processed
  86143. * after each file has been successfully installed, all simple tasks should
  86144. * perform their task here and return any errors using the custom
  86145. * throwError() method to allow forward compatibility
  86146. *
  86147. * This method MUST NOT write out any changes to disk
  86148. *
  86149. * @param PEAR_PackageFile_v2
  86150. * @param string file contents
  86151. * @param string the eventual final file location (informational only)
  86152. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  86153. * (use $this->throwError), otherwise return the new contents
  86154. * @abstract
  86155. */
  86156. public function startSession($pkg, $contents, $dest)
  86157. {
  86158. }
  86159. /**
  86160. * This method is used to process each of the tasks for a particular
  86161. * multiple class type. Simple tasks need not implement this method.
  86162. *
  86163. * @param array an array of tasks
  86164. * @access protected
  86165. */
  86166. public static function run($tasks)
  86167. {
  86168. }
  86169. /**
  86170. * @final
  86171. */
  86172. public static function hasPostinstallTasks()
  86173. {
  86174. return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
  86175. }
  86176. /**
  86177. * @final
  86178. */
  86179. public static function runPostinstallTasks()
  86180. {
  86181. foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) {
  86182. $err = call_user_func(
  86183. array($class, 'run'),
  86184. $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]
  86185. );
  86186. if ($err) {
  86187. return PEAR_Task_Common::throwError($err);
  86188. }
  86189. }
  86190. unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
  86191. }
  86192. /**
  86193. * Determines whether a role is a script
  86194. * @return bool
  86195. */
  86196. public function isScript()
  86197. {
  86198. return $this->type == 'script';
  86199. }
  86200. public function throwError($msg, $code = -1)
  86201. {
  86202. include_once 'phar://go-pear.phar/' . 'PEAR.php';
  86203. return PEAR::raiseError($msg, $code);
  86204. }
  86205. }
  86206. <?php
  86207. /**
  86208. * <tasks:postinstallscript>
  86209. *
  86210. * PHP versions 4 and 5
  86211. *
  86212. * @category pear
  86213. * @package PEAR
  86214. * @author Greg Beaver <cellog@php.net>
  86215. * @copyright 1997-2009 The Authors
  86216. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86217. * @link http://pear.php.net/package/PEAR
  86218. * @since File available since Release 1.4.0a1
  86219. */
  86220. /**
  86221. * Base class
  86222. */
  86223. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php';
  86224. /**
  86225. * Implements the postinstallscript file task.
  86226. *
  86227. * Note that post-install scripts are handled separately from installation, by the
  86228. * "pear run-scripts" command
  86229. *
  86230. * @category pear
  86231. * @package PEAR
  86232. * @author Greg Beaver <cellog@php.net>
  86233. * @copyright 1997-2009 The Authors
  86234. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86235. * @version Release: 1.10.10
  86236. * @link http://pear.php.net/package/PEAR
  86237. * @since Class available since Release 1.4.0a1
  86238. */
  86239. class PEAR_Task_Postinstallscript extends PEAR_Task_Common
  86240. {
  86241. public $type = 'script';
  86242. public $_class;
  86243. public $_params;
  86244. public $_obj;
  86245. /**
  86246. *
  86247. * @var PEAR_PackageFile_v2
  86248. */
  86249. public $_pkg;
  86250. public $_contents;
  86251. public $phase = PEAR_TASK_INSTALL;
  86252. /**
  86253. * Validate the raw xml at parsing-time.
  86254. *
  86255. * This also attempts to validate the script to make sure it meets the criteria
  86256. * for a post-install script
  86257. *
  86258. * @param PEAR_PackageFile_v2
  86259. * @param array The XML contents of the <postinstallscript> tag
  86260. * @param PEAR_Config
  86261. * @param array the entire parsed <file> tag
  86262. */
  86263. public static function validateXml($pkg, $xml, $config, $fileXml)
  86264. {
  86265. if ($fileXml['role'] != 'php') {
  86266. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86267. $fileXml['name'].'" must be role="php"', );
  86268. }
  86269. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  86270. $file = $pkg->getFileContents($fileXml['name']);
  86271. if (PEAR::isError($file)) {
  86272. PEAR::popErrorHandling();
  86273. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86274. $fileXml['name'].'" is not valid: '.
  86275. $file->getMessage(), );
  86276. } elseif ($file === null) {
  86277. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86278. $fileXml['name'].'" could not be retrieved for processing!', );
  86279. } else {
  86280. $analysis = $pkg->analyzeSourceCode($file, true);
  86281. if (!$analysis) {
  86282. PEAR::popErrorHandling();
  86283. $warnings = '';
  86284. foreach ($pkg->getValidationWarnings() as $warn) {
  86285. $warnings .= $warn['message']."\n";
  86286. }
  86287. return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "'.
  86288. $fileXml['name'].'" failed: '.$warnings, );
  86289. }
  86290. if (count($analysis['declared_classes']) != 1) {
  86291. PEAR::popErrorHandling();
  86292. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86293. $fileXml['name'].'" must declare exactly 1 class', );
  86294. }
  86295. $class = $analysis['declared_classes'][0];
  86296. if ($class != str_replace(
  86297. array('/', '.php'), array('_', ''),
  86298. $fileXml['name']
  86299. ).'_postinstall') {
  86300. PEAR::popErrorHandling();
  86301. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86302. $fileXml['name'].'" class "'.$class.'" must be named "'.
  86303. str_replace(
  86304. array('/', '.php'), array('_', ''),
  86305. $fileXml['name']
  86306. ).'_postinstall"', );
  86307. }
  86308. if (!isset($analysis['declared_methods'][$class])) {
  86309. PEAR::popErrorHandling();
  86310. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86311. $fileXml['name'].'" must declare methods init() and run()', );
  86312. }
  86313. $methods = array('init' => 0, 'run' => 1);
  86314. foreach ($analysis['declared_methods'][$class] as $method) {
  86315. if (isset($methods[$method])) {
  86316. unset($methods[$method]);
  86317. }
  86318. }
  86319. if (count($methods)) {
  86320. PEAR::popErrorHandling();
  86321. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86322. $fileXml['name'].'" must declare methods init() and run()', );
  86323. }
  86324. }
  86325. PEAR::popErrorHandling();
  86326. $definedparams = array();
  86327. $tasksNamespace = $pkg->getTasksNs().':';
  86328. if (!isset($xml[$tasksNamespace.'paramgroup']) && isset($xml['paramgroup'])) {
  86329. // in order to support the older betas, which did not expect internal tags
  86330. // to also use the namespace
  86331. $tasksNamespace = '';
  86332. }
  86333. if (isset($xml[$tasksNamespace.'paramgroup'])) {
  86334. $params = $xml[$tasksNamespace.'paramgroup'];
  86335. if (!is_array($params) || !isset($params[0])) {
  86336. $params = array($params);
  86337. }
  86338. foreach ($params as $param) {
  86339. if (!isset($param[$tasksNamespace.'id'])) {
  86340. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86341. $fileXml['name'].'" <paramgroup> must have '.
  86342. 'an '.$tasksNamespace.'id> tag', );
  86343. }
  86344. if (isset($param[$tasksNamespace.'name'])) {
  86345. if (!in_array($param[$tasksNamespace.'name'], $definedparams)) {
  86346. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86347. $fileXml['name'].'" '.$tasksNamespace.
  86348. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  86349. '" parameter "'.$param[$tasksNamespace.'name'].
  86350. '" has not been previously defined', );
  86351. }
  86352. if (!isset($param[$tasksNamespace.'conditiontype'])) {
  86353. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86354. $fileXml['name'].'" '.$tasksNamespace.
  86355. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  86356. '" must have a '.$tasksNamespace.
  86357. 'conditiontype> tag containing either "=", '.
  86358. '"!=", or "preg_match"', );
  86359. }
  86360. if (!in_array(
  86361. $param[$tasksNamespace.'conditiontype'],
  86362. array('=', '!=', 'preg_match')
  86363. )) {
  86364. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86365. $fileXml['name'].'" '.$tasksNamespace.
  86366. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  86367. '" must have a '.$tasksNamespace.
  86368. 'conditiontype> tag containing either "=", '.
  86369. '"!=", or "preg_match"', );
  86370. }
  86371. if (!isset($param[$tasksNamespace.'value'])) {
  86372. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86373. $fileXml['name'].'" '.$tasksNamespace.
  86374. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  86375. '" must have a '.$tasksNamespace.
  86376. 'value> tag containing expected parameter value', );
  86377. }
  86378. }
  86379. if (isset($param[$tasksNamespace.'instructions'])) {
  86380. if (!is_string($param[$tasksNamespace.'instructions'])) {
  86381. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86382. $fileXml['name'].'" '.$tasksNamespace.
  86383. 'paramgroup> id "'.$param[$tasksNamespace.'id'].
  86384. '" '.$tasksNamespace.'instructions> must be simple text', );
  86385. }
  86386. }
  86387. if (!isset($param[$tasksNamespace.'param'])) {
  86388. continue; // <param> is no longer required
  86389. }
  86390. $subparams = $param[$tasksNamespace.'param'];
  86391. if (!is_array($subparams) || !isset($subparams[0])) {
  86392. $subparams = array($subparams);
  86393. }
  86394. foreach ($subparams as $subparam) {
  86395. if (!isset($subparam[$tasksNamespace.'name'])) {
  86396. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86397. $fileXml['name'].'" parameter for '.
  86398. $tasksNamespace.'paramgroup> id "'.
  86399. $param[$tasksNamespace.'id'].'" must have '.
  86400. 'a '.$tasksNamespace.'name> tag', );
  86401. }
  86402. if (!preg_match(
  86403. '/[a-zA-Z0-9]+/',
  86404. $subparam[$tasksNamespace.'name']
  86405. )) {
  86406. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86407. $fileXml['name'].'" parameter "'.
  86408. $subparam[$tasksNamespace.'name'].
  86409. '" for '.$tasksNamespace.'paramgroup> id "'.
  86410. $param[$tasksNamespace.'id'].
  86411. '" is not a valid name. Must contain only alphanumeric characters', );
  86412. }
  86413. if (!isset($subparam[$tasksNamespace.'prompt'])) {
  86414. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86415. $fileXml['name'].'" parameter "'.
  86416. $subparam[$tasksNamespace.'name'].
  86417. '" for '.$tasksNamespace.'paramgroup> id "'.
  86418. $param[$tasksNamespace.'id'].
  86419. '" must have a '.$tasksNamespace.'prompt> tag', );
  86420. }
  86421. if (!isset($subparam[$tasksNamespace.'type'])) {
  86422. return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
  86423. $fileXml['name'].'" parameter "'.
  86424. $subparam[$tasksNamespace.'name'].
  86425. '" for '.$tasksNamespace.'paramgroup> id "'.
  86426. $param[$tasksNamespace.'id'].
  86427. '" must have a '.$tasksNamespace.'type> tag', );
  86428. }
  86429. $definedparams[] = $param[$tasksNamespace.'id'].'::'.
  86430. $subparam[$tasksNamespace.'name'];
  86431. }
  86432. }
  86433. }
  86434. return true;
  86435. }
  86436. /**
  86437. * Initialize a task instance with the parameters
  86438. * @param array $xml raw, parsed xml
  86439. * @param array $fileattribs attributes from the <file> tag containing
  86440. * this task
  86441. * @param string|null $lastversion last installed version of this package,
  86442. * if any (useful for upgrades)
  86443. */
  86444. public function init($xml, $fileattribs, $lastversion)
  86445. {
  86446. $this->_class = str_replace('/', '_', $fileattribs['name']);
  86447. $this->_filename = $fileattribs['name'];
  86448. $this->_class = str_replace('.php', '', $this->_class).'_postinstall';
  86449. $this->_params = $xml;
  86450. $this->_lastversion = $lastversion;
  86451. }
  86452. /**
  86453. * Strip the tasks: namespace from internal params
  86454. *
  86455. * @access private
  86456. */
  86457. public function _stripNamespace($params = null)
  86458. {
  86459. if ($params === null) {
  86460. $params = array();
  86461. if (!is_array($this->_params)) {
  86462. return;
  86463. }
  86464. foreach ($this->_params as $i => $param) {
  86465. if (is_array($param)) {
  86466. $param = $this->_stripNamespace($param);
  86467. }
  86468. $params[str_replace($this->_pkg->getTasksNs().':', '', $i)] = $param;
  86469. }
  86470. $this->_params = $params;
  86471. } else {
  86472. $newparams = array();
  86473. foreach ($params as $i => $param) {
  86474. if (is_array($param)) {
  86475. $param = $this->_stripNamespace($param);
  86476. }
  86477. $newparams[str_replace($this->_pkg->getTasksNs().':', '', $i)] = $param;
  86478. }
  86479. return $newparams;
  86480. }
  86481. }
  86482. /**
  86483. * Unlike other tasks, the installed file name is passed in instead of the
  86484. * file contents, because this task is handled post-installation
  86485. *
  86486. * @param mixed $pkg PEAR_PackageFile_v1|PEAR_PackageFile_v2
  86487. * @param string $contents file name
  86488. * @param string $dest the eventual final file location (informational only)
  86489. *
  86490. * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail
  86491. * (use $this->throwError)
  86492. */
  86493. public function startSession($pkg, $contents, $dest)
  86494. {
  86495. if ($this->installphase != PEAR_TASK_INSTALL) {
  86496. return false;
  86497. }
  86498. // remove the tasks: namespace if present
  86499. $this->_pkg = $pkg;
  86500. $this->_stripNamespace();
  86501. $this->logger->log(
  86502. 0, 'Including external post-installation script "'.
  86503. $contents.'" - any errors are in this script'
  86504. );
  86505. include_once 'phar://go-pear.phar/' . $contents;
  86506. if (class_exists($this->_class)) {
  86507. $this->logger->log(0, 'Inclusion succeeded');
  86508. } else {
  86509. return $this->throwError(
  86510. 'init of post-install script class "'.$this->_class
  86511. .'" failed'
  86512. );
  86513. }
  86514. $this->_obj = new $this->_class();
  86515. $this->logger->log(1, 'running post-install script "'.$this->_class.'->init()"');
  86516. PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  86517. $res = $this->_obj->init($this->config, $pkg, $this->_lastversion);
  86518. PEAR::popErrorHandling();
  86519. if ($res) {
  86520. $this->logger->log(0, 'init succeeded');
  86521. } else {
  86522. return $this->throwError(
  86523. 'init of post-install script "'.$this->_class.
  86524. '->init()" failed'
  86525. );
  86526. }
  86527. $this->_contents = $contents;
  86528. return true;
  86529. }
  86530. /**
  86531. * No longer used
  86532. *
  86533. * @see PEAR_PackageFile_v2::runPostinstallScripts()
  86534. * @param array an array of tasks
  86535. * @param string install or upgrade
  86536. * @access protected
  86537. */
  86538. public static function run($tasks)
  86539. {
  86540. }
  86541. }
  86542. <?php
  86543. /**
  86544. * <tasks:postinstallscript> - read/write version
  86545. *
  86546. * PHP versions 4 and 5
  86547. *
  86548. * @category pear
  86549. * @package PEAR
  86550. * @author Greg Beaver <cellog@php.net>
  86551. * @copyright 1997-2009 The Authors
  86552. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86553. * @link http://pear.php.net/package/PEAR
  86554. * @since File available since Release 1.4.0a10
  86555. */
  86556. /**
  86557. * Base class
  86558. */
  86559. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Postinstallscript.php';
  86560. /**
  86561. * Abstracts the postinstallscript file task xml.
  86562. * @category pear
  86563. * @package PEAR
  86564. * @author Greg Beaver <cellog@php.net>
  86565. * @copyright 1997-2009 The Authors
  86566. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86567. * @version Release: 1.10.10
  86568. * @link http://pear.php.net/package/PEAR
  86569. * @since Class available since Release 1.4.0a10
  86570. */
  86571. class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript
  86572. {
  86573. /**
  86574. * parent package file object
  86575. *
  86576. * @var PEAR_PackageFile_v2_rw
  86577. */
  86578. public $_pkg;
  86579. /**
  86580. * Enter description here...
  86581. *
  86582. * @param PEAR_PackageFile_v2_rw $pkg Package
  86583. * @param PEAR_Config $config Config
  86584. * @param PEAR_Frontend $logger Logger
  86585. * @param array $fileXml XML
  86586. *
  86587. * @return PEAR_Task_Postinstallscript_rw
  86588. */
  86589. function __construct(&$pkg, &$config, &$logger, $fileXml)
  86590. {
  86591. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  86592. $this->_contents = $fileXml;
  86593. $this->_pkg = &$pkg;
  86594. $this->_params = array();
  86595. }
  86596. public function validate()
  86597. {
  86598. return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
  86599. }
  86600. public function getName()
  86601. {
  86602. return 'postinstallscript';
  86603. }
  86604. /**
  86605. * add a simple <paramgroup> to the post-install script
  86606. *
  86607. * Order is significant, so call this method in the same
  86608. * sequence the users should see the paramgroups. The $params
  86609. * parameter should either be the result of a call to {@link getParam()}
  86610. * or an array of calls to getParam().
  86611. *
  86612. * Use {@link addConditionTypeGroup()} to add a <paramgroup> containing
  86613. * a <conditiontype> tag
  86614. *
  86615. * @param string $id <paramgroup> id as seen by the script
  86616. * @param array|false $params array of getParam() calls, or false for no params
  86617. * @param string|false $instructions
  86618. */
  86619. public function addParamGroup($id, $params = false, $instructions = false)
  86620. {
  86621. if ($params && isset($params[0]) && !isset($params[1])) {
  86622. $params = $params[0];
  86623. }
  86624. $stuff =
  86625. array(
  86626. $this->_pkg->getTasksNs().':id' => $id,
  86627. );
  86628. if ($instructions) {
  86629. $stuff[$this->_pkg->getTasksNs().':instructions'] = $instructions;
  86630. }
  86631. if ($params) {
  86632. $stuff[$this->_pkg->getTasksNs().':param'] = $params;
  86633. }
  86634. $this->_params[$this->_pkg->getTasksNs().':paramgroup'][] = $stuff;
  86635. }
  86636. /**
  86637. * Add a complex <paramgroup> to the post-install script with conditions
  86638. *
  86639. * This inserts a <paramgroup> with
  86640. *
  86641. * Order is significant, so call this method in the same
  86642. * sequence the users should see the paramgroups. The $params
  86643. * parameter should either be the result of a call to {@link getParam()}
  86644. * or an array of calls to getParam().
  86645. *
  86646. * Use {@link addParamGroup()} to add a simple <paramgroup>
  86647. *
  86648. * @param string $id <paramgroup> id as seen by the script
  86649. * @param string $oldgroup <paramgroup> id of the section referenced by
  86650. * <conditiontype>
  86651. * @param string $param name of the <param> from the older section referenced
  86652. * by <contitiontype>
  86653. * @param string $value value to match of the parameter
  86654. * @param string $conditiontype one of '=', '!=', 'preg_match'
  86655. * @param array|false $params array of getParam() calls, or false for no params
  86656. * @param string|false $instructions
  86657. */
  86658. public function addConditionTypeGroup($id,
  86659. $oldgroup,
  86660. $param,
  86661. $value,
  86662. $conditiontype = '=',
  86663. $params = false,
  86664. $instructions = false
  86665. ) {
  86666. if ($params && isset($params[0]) && !isset($params[1])) {
  86667. $params = $params[0];
  86668. }
  86669. $stuff = array(
  86670. $this->_pkg->getTasksNs().':id' => $id,
  86671. );
  86672. if ($instructions) {
  86673. $stuff[$this->_pkg->getTasksNs().':instructions'] = $instructions;
  86674. }
  86675. $stuff[$this->_pkg->getTasksNs().':name'] = $oldgroup.'::'.$param;
  86676. $stuff[$this->_pkg->getTasksNs().':conditiontype'] = $conditiontype;
  86677. $stuff[$this->_pkg->getTasksNs().':value'] = $value;
  86678. if ($params) {
  86679. $stuff[$this->_pkg->getTasksNs().':param'] = $params;
  86680. }
  86681. $this->_params[$this->_pkg->getTasksNs().':paramgroup'][] = $stuff;
  86682. }
  86683. public function getXml()
  86684. {
  86685. return $this->_params;
  86686. }
  86687. /**
  86688. * Use to set up a param tag for use in creating a paramgroup
  86689. *
  86690. * @param mixed $name Name of parameter
  86691. * @param mixed $prompt Prompt
  86692. * @param string $type Type, defaults to 'string'
  86693. * @param mixed $default Default value
  86694. *
  86695. * @return array
  86696. */
  86697. public function getParam(
  86698. $name, $prompt, $type = 'string', $default = null
  86699. ) {
  86700. if ($default !== null) {
  86701. return
  86702. array(
  86703. $this->_pkg->getTasksNs().':name' => $name,
  86704. $this->_pkg->getTasksNs().':prompt' => $prompt,
  86705. $this->_pkg->getTasksNs().':type' => $type,
  86706. $this->_pkg->getTasksNs().':default' => $default,
  86707. );
  86708. }
  86709. return
  86710. array(
  86711. $this->_pkg->getTasksNs().':name' => $name,
  86712. $this->_pkg->getTasksNs().':prompt' => $prompt,
  86713. $this->_pkg->getTasksNs().':type' => $type,
  86714. );
  86715. }
  86716. }
  86717. <?php
  86718. /**
  86719. * <tasks:replace>
  86720. *
  86721. * PHP versions 4 and 5
  86722. *
  86723. * @category pear
  86724. * @package PEAR
  86725. * @author Greg Beaver <cellog@php.net>
  86726. * @copyright 1997-2009 The Authors
  86727. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86728. * @link http://pear.php.net/package/PEAR
  86729. * @since File available since Release 1.4.0a1
  86730. */
  86731. /**
  86732. * Base class
  86733. */
  86734. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php';
  86735. /**
  86736. * Implements the replace file task.
  86737. * @category pear
  86738. * @package PEAR
  86739. * @author Greg Beaver <cellog@php.net>
  86740. * @copyright 1997-2009 The Authors
  86741. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86742. * @version Release: 1.10.10
  86743. * @link http://pear.php.net/package/PEAR
  86744. * @since Class available since Release 1.4.0a1
  86745. */
  86746. class PEAR_Task_Replace extends PEAR_Task_Common
  86747. {
  86748. public $type = 'simple';
  86749. public $phase = PEAR_TASK_PACKAGEANDINSTALL;
  86750. public $_replacements;
  86751. /**
  86752. * Validate the raw xml at parsing-time.
  86753. *
  86754. * @param PEAR_PackageFile_v2
  86755. * @param array raw, parsed xml
  86756. * @param PEAR_Config
  86757. */
  86758. public static function validateXml($pkg, $xml, $config, $fileXml)
  86759. {
  86760. if (!isset($xml['attribs'])) {
  86761. return array(PEAR_TASK_ERROR_NOATTRIBS);
  86762. }
  86763. if (!isset($xml['attribs']['type'])) {
  86764. return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type');
  86765. }
  86766. if (!isset($xml['attribs']['to'])) {
  86767. return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to');
  86768. }
  86769. if (!isset($xml['attribs']['from'])) {
  86770. return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from');
  86771. }
  86772. if ($xml['attribs']['type'] == 'pear-config') {
  86773. if (!in_array($xml['attribs']['to'], $config->getKeys())) {
  86774. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
  86775. $config->getKeys(), );
  86776. }
  86777. } elseif ($xml['attribs']['type'] == 'php-const') {
  86778. if (defined($xml['attribs']['to'])) {
  86779. return true;
  86780. } else {
  86781. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
  86782. array('valid PHP constant'), );
  86783. }
  86784. } elseif ($xml['attribs']['type'] == 'package-info') {
  86785. if (in_array(
  86786. $xml['attribs']['to'],
  86787. array('name', 'summary', 'channel', 'notes', 'extends', 'description',
  86788. 'release_notes', 'license', 'release-license', 'license-uri',
  86789. 'version', 'api-version', 'state', 'api-state', 'release_date',
  86790. 'date', 'time', )
  86791. )) {
  86792. return true;
  86793. } else {
  86794. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
  86795. array('name', 'summary', 'channel', 'notes', 'extends', 'description',
  86796. 'release_notes', 'license', 'release-license', 'license-uri',
  86797. 'version', 'api-version', 'state', 'api-state', 'release_date',
  86798. 'date', 'time', ), );
  86799. }
  86800. } else {
  86801. return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'],
  86802. array('pear-config', 'package-info', 'php-const'), );
  86803. }
  86804. return true;
  86805. }
  86806. /**
  86807. * Initialize a task instance with the parameters
  86808. * @param array raw, parsed xml
  86809. * @param unused
  86810. * @param unused
  86811. */
  86812. public function init($xml, $attribs, $lastVersion = null)
  86813. {
  86814. $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml;
  86815. }
  86816. /**
  86817. * Do a package.xml 1.0 replacement, with additional package-info fields available
  86818. *
  86819. * See validateXml() source for the complete list of allowed fields
  86820. *
  86821. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  86822. * @param string file contents
  86823. * @param string the eventual final file location (informational only)
  86824. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  86825. * (use $this->throwError), otherwise return the new contents
  86826. */
  86827. public function startSession($pkg, $contents, $dest)
  86828. {
  86829. $subst_from = $subst_to = array();
  86830. foreach ($this->_replacements as $a) {
  86831. $a = $a['attribs'];
  86832. $to = '';
  86833. if ($a['type'] == 'pear-config') {
  86834. if ($this->installphase == PEAR_TASK_PACKAGE) {
  86835. return false;
  86836. }
  86837. if ($a['to'] == 'master_server') {
  86838. $chan = $this->registry->getChannel($pkg->getChannel());
  86839. if (!PEAR::isError($chan)) {
  86840. $to = $chan->getServer();
  86841. } else {
  86842. $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
  86843. return false;
  86844. }
  86845. } else {
  86846. if ($this->config->isDefinedLayer('ftp')) {
  86847. // try the remote config file first
  86848. $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel());
  86849. if (is_null($to)) {
  86850. // then default to local
  86851. $to = $this->config->get($a['to'], null, $pkg->getChannel());
  86852. }
  86853. } else {
  86854. $to = $this->config->get($a['to'], null, $pkg->getChannel());
  86855. }
  86856. }
  86857. if (is_null($to)) {
  86858. $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
  86859. return false;
  86860. }
  86861. } elseif ($a['type'] == 'php-const') {
  86862. if ($this->installphase == PEAR_TASK_PACKAGE) {
  86863. return false;
  86864. }
  86865. if (defined($a['to'])) {
  86866. $to = constant($a['to']);
  86867. } else {
  86868. $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]");
  86869. return false;
  86870. }
  86871. } else {
  86872. if ($t = $pkg->packageInfo($a['to'])) {
  86873. $to = $t;
  86874. } else {
  86875. $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]");
  86876. return false;
  86877. }
  86878. }
  86879. if (!is_null($to)) {
  86880. $subst_from[] = $a['from'];
  86881. $subst_to[] = $to;
  86882. }
  86883. }
  86884. $this->logger->log(
  86885. 3, "doing ".sizeof($subst_from).
  86886. " substitution(s) for $dest"
  86887. );
  86888. if (sizeof($subst_from)) {
  86889. $contents = str_replace($subst_from, $subst_to, $contents);
  86890. }
  86891. return $contents;
  86892. }
  86893. }
  86894. <?php
  86895. /**
  86896. * <tasks:replace> - read/write version
  86897. *
  86898. * PHP versions 4 and 5
  86899. *
  86900. * @category pear
  86901. * @package PEAR
  86902. * @author Greg Beaver <cellog@php.net>
  86903. * @copyright 1997-2009 The Authors
  86904. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86905. * @link http://pear.php.net/package/PEAR
  86906. * @since File available since Release 1.4.0a10
  86907. */
  86908. /**
  86909. * Base class
  86910. */
  86911. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Replace.php';
  86912. /**
  86913. * Abstracts the replace task xml.
  86914. * @category pear
  86915. * @package PEAR
  86916. * @author Greg Beaver <cellog@php.net>
  86917. * @copyright 1997-2009 The Authors
  86918. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86919. * @version Release: 1.10.10
  86920. * @link http://pear.php.net/package/PEAR
  86921. * @since Class available since Release 1.4.0a10
  86922. */
  86923. class PEAR_Task_Replace_rw extends PEAR_Task_Replace
  86924. {
  86925. public function __construct(&$pkg, &$config, &$logger, $fileXml)
  86926. {
  86927. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  86928. $this->_contents = $fileXml;
  86929. $this->_pkg = &$pkg;
  86930. $this->_params = array();
  86931. }
  86932. public function validate()
  86933. {
  86934. return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
  86935. }
  86936. public function setInfo($from, $to, $type)
  86937. {
  86938. $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type));
  86939. }
  86940. public function getName()
  86941. {
  86942. return 'replace';
  86943. }
  86944. public function getXml()
  86945. {
  86946. return $this->_params;
  86947. }
  86948. }
  86949. <?php
  86950. /**
  86951. * <tasks:unixeol>
  86952. *
  86953. * PHP versions 4 and 5
  86954. *
  86955. * @category pear
  86956. * @package PEAR
  86957. * @author Greg Beaver <cellog@php.net>
  86958. * @copyright 1997-2009 The Authors
  86959. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86960. * @link http://pear.php.net/package/PEAR
  86961. * @since File available since Release 1.4.0a1
  86962. */
  86963. /**
  86964. * Base class
  86965. */
  86966. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php';
  86967. /**
  86968. * Implements the unix line endings file task.
  86969. * @category pear
  86970. * @package PEAR
  86971. * @author Greg Beaver <cellog@php.net>
  86972. * @copyright 1997-2009 The Authors
  86973. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  86974. * @version Release: 1.10.10
  86975. * @link http://pear.php.net/package/PEAR
  86976. * @since Class available since Release 1.4.0a1
  86977. */
  86978. class PEAR_Task_Unixeol extends PEAR_Task_Common
  86979. {
  86980. public $type = 'simple';
  86981. public $phase = PEAR_TASK_PACKAGE;
  86982. public $_replacements;
  86983. /**
  86984. * Validate the raw xml at parsing-time.
  86985. *
  86986. * @param PEAR_PackageFile_v2
  86987. * @param array raw, parsed xml
  86988. * @param PEAR_Config
  86989. */
  86990. public static function validateXml($pkg, $xml, $config, $fileXml)
  86991. {
  86992. if ($xml != '') {
  86993. return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
  86994. }
  86995. return true;
  86996. }
  86997. /**
  86998. * Initialize a task instance with the parameters
  86999. * @param array raw, parsed xml
  87000. * @param unused
  87001. * @param unused
  87002. */
  87003. public function init($xml, $attribs, $lastVersion = null)
  87004. {
  87005. }
  87006. /**
  87007. * Replace all line endings with line endings customized for the current OS
  87008. *
  87009. * See validateXml() source for the complete list of allowed fields
  87010. *
  87011. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  87012. * @param string file contents
  87013. * @param string the eventual final file location (informational only)
  87014. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  87015. * (use $this->throwError), otherwise return the new contents
  87016. */
  87017. public function startSession($pkg, $contents, $dest)
  87018. {
  87019. $this->logger->log(3, "replacing all line endings with \\n in $dest");
  87020. return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents);
  87021. }
  87022. }
  87023. <?php
  87024. /**
  87025. * <tasks:unixeol> - read/write version
  87026. *
  87027. * PHP versions 4 and 5
  87028. *
  87029. * @category pear
  87030. * @package PEAR
  87031. * @author Greg Beaver <cellog@php.net>
  87032. * @copyright 1997-2009 The Authors
  87033. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87034. * @link http://pear.php.net/package/PEAR
  87035. * @since File available since Release 1.4.0a10
  87036. */
  87037. /**
  87038. * Base class
  87039. */
  87040. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Unixeol.php';
  87041. /**
  87042. * Abstracts the unixeol task xml.
  87043. * @category pear
  87044. * @package PEAR
  87045. * @author Greg Beaver <cellog@php.net>
  87046. * @copyright 1997-2009 The Authors
  87047. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87048. * @version Release: 1.10.10
  87049. * @link http://pear.php.net/package/PEAR
  87050. * @since Class available since Release 1.4.0a10
  87051. */
  87052. class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol
  87053. {
  87054. function __construct(&$pkg, &$config, &$logger, $fileXml)
  87055. {
  87056. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  87057. $this->_contents = $fileXml;
  87058. $this->_pkg = &$pkg;
  87059. $this->_params = array();
  87060. }
  87061. public function validate()
  87062. {
  87063. return true;
  87064. }
  87065. public function getName()
  87066. {
  87067. return 'unixeol';
  87068. }
  87069. public function getXml()
  87070. {
  87071. return '';
  87072. }
  87073. }
  87074. ?>
  87075. <?php
  87076. /**
  87077. * <tasks:windowseol>
  87078. *
  87079. * PHP versions 4 and 5
  87080. *
  87081. * @category pear
  87082. * @package PEAR
  87083. * @author Greg Beaver <cellog@php.net>
  87084. * @copyright 1997-2009 The Authors
  87085. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87086. * @link http://pear.php.net/package/PEAR
  87087. * @since File available since Release 1.4.0a1
  87088. */
  87089. /**
  87090. * Base class
  87091. */
  87092. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Common.php';
  87093. /**
  87094. * Implements the windows line endsings file task.
  87095. *
  87096. * @category pear
  87097. * @package PEAR
  87098. * @author Greg Beaver <cellog@php.net>
  87099. * @copyright 1997-2009 The Authors
  87100. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87101. * @version Release: 1.10.10
  87102. * @link http://pear.php.net/package/PEAR
  87103. * @since Class available since Release 1.4.0a1
  87104. */
  87105. class PEAR_Task_Windowseol extends PEAR_Task_Common
  87106. {
  87107. public $type = 'simple';
  87108. public $phase = PEAR_TASK_PACKAGE;
  87109. public $_replacements;
  87110. /**
  87111. * Validate the raw xml at parsing-time.
  87112. *
  87113. * @param PEAR_PackageFile_v2
  87114. * @param array raw, parsed xml
  87115. * @param PEAR_Config
  87116. */
  87117. public static function validateXml($pkg, $xml, $config, $fileXml)
  87118. {
  87119. if ($xml != '') {
  87120. return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
  87121. }
  87122. return true;
  87123. }
  87124. /**
  87125. * Initialize a task instance with the parameters
  87126. * @param array raw, parsed xml
  87127. * @param unused
  87128. * @param unused
  87129. */
  87130. public function init($xml, $attribs, $lastVersion = null)
  87131. {
  87132. }
  87133. /**
  87134. * Replace all line endings with windows line endings
  87135. *
  87136. * See validateXml() source for the complete list of allowed fields
  87137. *
  87138. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  87139. * @param string file contents
  87140. * @param string the eventual final file location (informational only)
  87141. * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
  87142. * (use $this->throwError), otherwise return the new contents
  87143. */
  87144. public function startSession($pkg, $contents, $dest)
  87145. {
  87146. $this->logger->log(3, "replacing all line endings with \\r\\n in $dest");
  87147. return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents);
  87148. }
  87149. }
  87150. <?php
  87151. /**
  87152. * <tasks:windowseol> - read/write version
  87153. *
  87154. * PHP versions 4 and 5
  87155. *
  87156. * @category pear
  87157. * @package PEAR
  87158. * @author Greg Beaver <cellog@php.net>
  87159. * @copyright 1997-2009 The Authors
  87160. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87161. * @link http://pear.php.net/package/PEAR
  87162. * @since File available since Release 1.4.0a10
  87163. */
  87164. /**
  87165. * Base class
  87166. */
  87167. require_once 'phar://go-pear.phar/' . 'PEAR/Task/Windowseol.php';
  87168. /**
  87169. * Abstracts the windowseol task xml.
  87170. *
  87171. * @category pear
  87172. * @package PEAR
  87173. * @author Greg Beaver <cellog@php.net>
  87174. * @copyright 1997-2009 The Authors
  87175. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87176. * @version Release: 1.10.10
  87177. * @link http://pear.php.net/package/PEAR
  87178. * @since Class available since Release 1.4.0a10
  87179. */
  87180. class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol
  87181. {
  87182. function __construct(&$pkg, &$config, &$logger, $fileXml)
  87183. {
  87184. parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
  87185. $this->_contents = $fileXml;
  87186. $this->_pkg = &$pkg;
  87187. $this->_params = array();
  87188. }
  87189. public function validate()
  87190. {
  87191. return true;
  87192. }
  87193. public function getName()
  87194. {
  87195. return 'windowseol';
  87196. }
  87197. public function getXml()
  87198. {
  87199. return '';
  87200. }
  87201. }
  87202. ?>
  87203. <?php
  87204. /**
  87205. * PEAR_Validate
  87206. *
  87207. * PHP versions 4 and 5
  87208. *
  87209. * @category pear
  87210. * @package PEAR
  87211. * @author Greg Beaver <cellog@php.net>
  87212. * @copyright 1997-2009 The Authors
  87213. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87214. * @link http://pear.php.net/package/PEAR
  87215. * @since File available since Release 1.4.0a1
  87216. */
  87217. /**#@+
  87218. * Constants for install stage
  87219. */
  87220. define('PEAR_VALIDATE_INSTALLING', 1);
  87221. define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others
  87222. define('PEAR_VALIDATE_NORMAL', 3);
  87223. define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others
  87224. define('PEAR_VALIDATE_PACKAGING', 7);
  87225. /**#@-*/
  87226. require_once 'phar://go-pear.phar/' . 'PEAR/Common.php';
  87227. require_once 'phar://go-pear.phar/' . 'PEAR/Validator/PECL.php';
  87228. /**
  87229. * Validation class for package.xml - channel-level advanced validation
  87230. * @category pear
  87231. * @package PEAR
  87232. * @author Greg Beaver <cellog@php.net>
  87233. * @copyright 1997-2009 The Authors
  87234. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87235. * @version Release: 1.10.10
  87236. * @link http://pear.php.net/package/PEAR
  87237. * @since Class available since Release 1.4.0a1
  87238. */
  87239. class PEAR_Validate
  87240. {
  87241. var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG;
  87242. /**
  87243. * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2
  87244. */
  87245. var $_packagexml;
  87246. /**
  87247. * @var int one of the PEAR_VALIDATE_* constants
  87248. */
  87249. var $_state = PEAR_VALIDATE_NORMAL;
  87250. /**
  87251. * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same)
  87252. * @var array
  87253. * @access private
  87254. */
  87255. var $_failures = array('error' => array(), 'warning' => array());
  87256. /**
  87257. * Override this method to handle validation of normal package names
  87258. * @param string
  87259. * @return bool
  87260. * @access protected
  87261. */
  87262. function _validPackageName($name)
  87263. {
  87264. return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name);
  87265. }
  87266. /**
  87267. * @param string package name to validate
  87268. * @param string name of channel-specific validation package
  87269. * @final
  87270. */
  87271. function validPackageName($name, $validatepackagename = false)
  87272. {
  87273. if ($validatepackagename) {
  87274. if (strtolower($name) == strtolower($validatepackagename)) {
  87275. return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name);
  87276. }
  87277. }
  87278. return $this->_validPackageName($name);
  87279. }
  87280. /**
  87281. * This validates a bundle name, and bundle names must conform
  87282. * to the PEAR naming convention, so the method is final and static.
  87283. * @param string
  87284. * @final
  87285. */
  87286. public static function validGroupName($name)
  87287. {
  87288. return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name);
  87289. }
  87290. /**
  87291. * Determine whether $state represents a valid stability level
  87292. * @param string
  87293. * @return bool
  87294. * @final
  87295. */
  87296. public static function validState($state)
  87297. {
  87298. return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable'));
  87299. }
  87300. /**
  87301. * Get a list of valid stability levels
  87302. * @return array
  87303. * @final
  87304. */
  87305. public static function getValidStates()
  87306. {
  87307. return array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  87308. }
  87309. /**
  87310. * Determine whether a version is a properly formatted version number that can be used
  87311. * by version_compare
  87312. * @param string
  87313. * @return bool
  87314. * @final
  87315. */
  87316. public static function validVersion($ver)
  87317. {
  87318. return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
  87319. }
  87320. /**
  87321. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  87322. */
  87323. function setPackageFile(&$pf)
  87324. {
  87325. $this->_packagexml = &$pf;
  87326. }
  87327. /**
  87328. * @access private
  87329. */
  87330. function _addFailure($field, $reason)
  87331. {
  87332. $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason);
  87333. }
  87334. /**
  87335. * @access private
  87336. */
  87337. function _addWarning($field, $reason)
  87338. {
  87339. $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason);
  87340. }
  87341. function getFailures()
  87342. {
  87343. $failures = $this->_failures;
  87344. $this->_failures = array('warnings' => array(), 'errors' => array());
  87345. return $failures;
  87346. }
  87347. /**
  87348. * @param int one of the PEAR_VALIDATE_* constants
  87349. */
  87350. function validate($state = null)
  87351. {
  87352. if (!isset($this->_packagexml)) {
  87353. return false;
  87354. }
  87355. if ($state !== null) {
  87356. $this->_state = $state;
  87357. }
  87358. $this->_failures = array('warnings' => array(), 'errors' => array());
  87359. $this->validatePackageName();
  87360. $this->validateVersion();
  87361. $this->validateMaintainers();
  87362. $this->validateDate();
  87363. $this->validateSummary();
  87364. $this->validateDescription();
  87365. $this->validateLicense();
  87366. $this->validateNotes();
  87367. if ($this->_packagexml->getPackagexmlVersion() == '1.0') {
  87368. $this->validateState();
  87369. $this->validateFilelist();
  87370. } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' ||
  87371. $this->_packagexml->getPackagexmlVersion() == '2.1') {
  87372. $this->validateTime();
  87373. $this->validateStability();
  87374. $this->validateDeps();
  87375. $this->validateMainFilelist();
  87376. $this->validateReleaseFilelist();
  87377. //$this->validateGlobalTasks();
  87378. $this->validateChangelog();
  87379. }
  87380. return !((bool) count($this->_failures['errors']));
  87381. }
  87382. /**
  87383. * @access protected
  87384. */
  87385. function validatePackageName()
  87386. {
  87387. if ($this->_state == PEAR_VALIDATE_PACKAGING ||
  87388. $this->_state == PEAR_VALIDATE_NORMAL) {
  87389. if (($this->_packagexml->getPackagexmlVersion() == '2.0' ||
  87390. $this->_packagexml->getPackagexmlVersion() == '2.1') &&
  87391. $this->_packagexml->getExtends()) {
  87392. $version = $this->_packagexml->getVersion() . '';
  87393. $name = $this->_packagexml->getPackage();
  87394. $a = explode('.', $version);
  87395. $test = array_shift($a);
  87396. if ($test == '0') {
  87397. return true;
  87398. }
  87399. $vlen = strlen($test);
  87400. $majver = substr($name, strlen($name) - $vlen);
  87401. while ($majver && !is_numeric($majver[0])) {
  87402. $majver = substr($majver, 1);
  87403. }
  87404. if ($majver != $test) {
  87405. $this->_addWarning('package', "package $name extends package " .
  87406. $this->_packagexml->getExtends() . ' and so the name should ' .
  87407. 'have a postfix equal to the major version like "' .
  87408. $this->_packagexml->getExtends() . $test . '"');
  87409. return true;
  87410. } elseif (substr($name, 0, strlen($name) - $vlen) !=
  87411. $this->_packagexml->getExtends()) {
  87412. $this->_addWarning('package', "package $name extends package " .
  87413. $this->_packagexml->getExtends() . ' and so the name must ' .
  87414. 'be an extension like "' . $this->_packagexml->getExtends() .
  87415. $test . '"');
  87416. return true;
  87417. }
  87418. }
  87419. }
  87420. if (!$this->validPackageName($this->_packagexml->getPackage())) {
  87421. $this->_addFailure('name', 'package name "' .
  87422. $this->_packagexml->getPackage() . '" is invalid');
  87423. return false;
  87424. }
  87425. }
  87426. /**
  87427. * @access protected
  87428. */
  87429. function validateVersion()
  87430. {
  87431. if ($this->_state != PEAR_VALIDATE_PACKAGING) {
  87432. if (!$this->validVersion($this->_packagexml->getVersion())) {
  87433. $this->_addFailure('version',
  87434. 'Invalid version number "' . $this->_packagexml->getVersion() . '"');
  87435. }
  87436. return false;
  87437. }
  87438. $version = $this->_packagexml->getVersion();
  87439. $versioncomponents = explode('.', $version);
  87440. if (count($versioncomponents) != 3) {
  87441. $this->_addWarning('version',
  87442. 'A version number should have 3 decimals (x.y.z)');
  87443. return true;
  87444. }
  87445. $name = $this->_packagexml->getPackage();
  87446. // version must be based upon state
  87447. switch ($this->_packagexml->getState()) {
  87448. case 'snapshot' :
  87449. return true;
  87450. case 'devel' :
  87451. if ($versioncomponents[0] . 'a' == '0a') {
  87452. return true;
  87453. }
  87454. if ($versioncomponents[0] == 0) {
  87455. $versioncomponents[0] = '0';
  87456. $this->_addWarning('version',
  87457. 'version "' . $version . '" should be "' .
  87458. implode('.' ,$versioncomponents) . '"');
  87459. } else {
  87460. $this->_addWarning('version',
  87461. 'packages with devel stability must be < version 1.0.0');
  87462. }
  87463. return true;
  87464. break;
  87465. case 'alpha' :
  87466. case 'beta' :
  87467. // check for a package that extends a package,
  87468. // like Foo and Foo2
  87469. if ($this->_state == PEAR_VALIDATE_PACKAGING) {
  87470. if (substr($versioncomponents[2], 1, 2) == 'rc') {
  87471. $this->_addFailure('version', 'Release Candidate versions ' .
  87472. 'must have capital RC, not lower-case rc');
  87473. return false;
  87474. }
  87475. }
  87476. if (!$this->_packagexml->getExtends()) {
  87477. if ($versioncomponents[0] == '1') {
  87478. if ($versioncomponents[2][0] == '0') {
  87479. if ($versioncomponents[2] == '0') {
  87480. // version 1.*.0000
  87481. $this->_addWarning('version',
  87482. 'version 1.' . $versioncomponents[1] .
  87483. '.0 probably should not be alpha or beta');
  87484. return true;
  87485. } elseif (strlen($versioncomponents[2]) > 1) {
  87486. // version 1.*.0RC1 or 1.*.0beta24 etc.
  87487. return true;
  87488. } else {
  87489. // version 1.*.0
  87490. $this->_addWarning('version',
  87491. 'version 1.' . $versioncomponents[1] .
  87492. '.0 probably should not be alpha or beta');
  87493. return true;
  87494. }
  87495. } else {
  87496. $this->_addWarning('version',
  87497. 'bugfix versions (1.3.x where x > 0) probably should ' .
  87498. 'not be alpha or beta');
  87499. return true;
  87500. }
  87501. } elseif ($versioncomponents[0] != '0') {
  87502. $this->_addWarning('version',
  87503. 'major versions greater than 1 are not allowed for packages ' .
  87504. 'without an <extends> tag or an identical postfix (foo2 v2.0.0)');
  87505. return true;
  87506. }
  87507. if ($versioncomponents[0] . 'a' == '0a') {
  87508. return true;
  87509. }
  87510. if ($versioncomponents[0] == 0) {
  87511. $versioncomponents[0] = '0';
  87512. $this->_addWarning('version',
  87513. 'version "' . $version . '" should be "' .
  87514. implode('.' ,$versioncomponents) . '"');
  87515. }
  87516. } else {
  87517. $vlen = strlen($versioncomponents[0] . '');
  87518. $majver = substr($name, strlen($name) - $vlen);
  87519. while ($majver && !is_numeric($majver[0])) {
  87520. $majver = substr($majver, 1);
  87521. }
  87522. if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
  87523. $this->_addWarning('version', 'first version number "' .
  87524. $versioncomponents[0] . '" must match the postfix of ' .
  87525. 'package name "' . $name . '" (' .
  87526. $majver . ')');
  87527. return true;
  87528. }
  87529. if ($versioncomponents[0] == $majver) {
  87530. if ($versioncomponents[2][0] == '0') {
  87531. if ($versioncomponents[2] == '0') {
  87532. // version 2.*.0000
  87533. $this->_addWarning('version',
  87534. "version $majver." . $versioncomponents[1] .
  87535. '.0 probably should not be alpha or beta');
  87536. return false;
  87537. } elseif (strlen($versioncomponents[2]) > 1) {
  87538. // version 2.*.0RC1 or 2.*.0beta24 etc.
  87539. return true;
  87540. } else {
  87541. // version 2.*.0
  87542. $this->_addWarning('version',
  87543. "version $majver." . $versioncomponents[1] .
  87544. '.0 cannot be alpha or beta');
  87545. return true;
  87546. }
  87547. } else {
  87548. $this->_addWarning('version',
  87549. "bugfix versions ($majver.x.y where y > 0) should " .
  87550. 'not be alpha or beta');
  87551. return true;
  87552. }
  87553. } elseif ($versioncomponents[0] != '0') {
  87554. $this->_addWarning('version',
  87555. "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases");
  87556. return true;
  87557. }
  87558. if ($versioncomponents[0] . 'a' == '0a') {
  87559. return true;
  87560. }
  87561. if ($versioncomponents[0] == 0) {
  87562. $versioncomponents[0] = '0';
  87563. $this->_addWarning('version',
  87564. 'version "' . $version . '" should be "' .
  87565. implode('.' ,$versioncomponents) . '"');
  87566. }
  87567. }
  87568. return true;
  87569. break;
  87570. case 'stable' :
  87571. if ($versioncomponents[0] == '0') {
  87572. $this->_addWarning('version', 'versions less than 1.0.0 cannot ' .
  87573. 'be stable');
  87574. return true;
  87575. }
  87576. if (!is_numeric($versioncomponents[2])) {
  87577. if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i',
  87578. $versioncomponents[2])) {
  87579. $this->_addWarning('version', 'version "' . $version . '" or any ' .
  87580. 'RC/beta/alpha version cannot be stable');
  87581. return true;
  87582. }
  87583. }
  87584. // check for a package that extends a package,
  87585. // like Foo and Foo2
  87586. if ($this->_packagexml->getExtends()) {
  87587. $vlen = strlen($versioncomponents[0] . '');
  87588. $majver = substr($name, strlen($name) - $vlen);
  87589. while ($majver && !is_numeric($majver[0])) {
  87590. $majver = substr($majver, 1);
  87591. }
  87592. if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) {
  87593. $this->_addWarning('version', 'first version number "' .
  87594. $versioncomponents[0] . '" must match the postfix of ' .
  87595. 'package name "' . $name . '" (' .
  87596. $majver . ')');
  87597. return true;
  87598. }
  87599. } elseif ($versioncomponents[0] > 1) {
  87600. $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' .
  87601. '1 for any package that does not have an <extends> tag');
  87602. }
  87603. return true;
  87604. break;
  87605. default :
  87606. return false;
  87607. break;
  87608. }
  87609. }
  87610. /**
  87611. * @access protected
  87612. */
  87613. function validateMaintainers()
  87614. {
  87615. // maintainers can only be truly validated server-side for most channels
  87616. // but allow this customization for those who wish it
  87617. return true;
  87618. }
  87619. /**
  87620. * @access protected
  87621. */
  87622. function validateDate()
  87623. {
  87624. if ($this->_state == PEAR_VALIDATE_NORMAL ||
  87625. $this->_state == PEAR_VALIDATE_PACKAGING) {
  87626. if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/',
  87627. $this->_packagexml->getDate(), $res) ||
  87628. count($res) < 4
  87629. || !checkdate($res[2], $res[3], $res[1])
  87630. ) {
  87631. $this->_addFailure('date', 'invalid release date "' .
  87632. $this->_packagexml->getDate() . '"');
  87633. return false;
  87634. }
  87635. if ($this->_state == PEAR_VALIDATE_PACKAGING &&
  87636. $this->_packagexml->getDate() != date('Y-m-d')) {
  87637. $this->_addWarning('date', 'Release Date "' .
  87638. $this->_packagexml->getDate() . '" is not today');
  87639. }
  87640. }
  87641. return true;
  87642. }
  87643. /**
  87644. * @access protected
  87645. */
  87646. function validateTime()
  87647. {
  87648. if (!$this->_packagexml->getTime()) {
  87649. // default of no time value set
  87650. return true;
  87651. }
  87652. // packager automatically sets time, so only validate if pear validate is called
  87653. if ($this->_state = PEAR_VALIDATE_NORMAL) {
  87654. if (!preg_match('/\d\d:\d\d:\d\d/',
  87655. $this->_packagexml->getTime())) {
  87656. $this->_addFailure('time', 'invalid release time "' .
  87657. $this->_packagexml->getTime() . '"');
  87658. return false;
  87659. }
  87660. $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches);
  87661. if ($result === false || empty($matches)) {
  87662. $this->_addFailure('time', 'invalid release time "' .
  87663. $this->_packagexml->getTime() . '"');
  87664. return false;
  87665. }
  87666. }
  87667. return true;
  87668. }
  87669. /**
  87670. * @access protected
  87671. */
  87672. function validateState()
  87673. {
  87674. // this is the closest to "final" php4 can get
  87675. if (!PEAR_Validate::validState($this->_packagexml->getState())) {
  87676. if (strtolower($this->_packagexml->getState() == 'rc')) {
  87677. $this->_addFailure('state', 'RC is not a state, it is a version ' .
  87678. 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta');
  87679. }
  87680. $this->_addFailure('state', 'invalid release state "' .
  87681. $this->_packagexml->getState() . '", must be one of: ' .
  87682. implode(', ', PEAR_Validate::getValidStates()));
  87683. return false;
  87684. }
  87685. return true;
  87686. }
  87687. /**
  87688. * @access protected
  87689. */
  87690. function validateStability()
  87691. {
  87692. $ret = true;
  87693. $packagestability = $this->_packagexml->getState();
  87694. $apistability = $this->_packagexml->getState('api');
  87695. if (!PEAR_Validate::validState($packagestability)) {
  87696. $this->_addFailure('state', 'invalid release stability "' .
  87697. $this->_packagexml->getState() . '", must be one of: ' .
  87698. implode(', ', PEAR_Validate::getValidStates()));
  87699. $ret = false;
  87700. }
  87701. $apistates = PEAR_Validate::getValidStates();
  87702. array_shift($apistates); // snapshot is not allowed
  87703. if (!in_array($apistability, $apistates)) {
  87704. $this->_addFailure('state', 'invalid API stability "' .
  87705. $this->_packagexml->getState('api') . '", must be one of: ' .
  87706. implode(', ', $apistates));
  87707. $ret = false;
  87708. }
  87709. return $ret;
  87710. }
  87711. /**
  87712. * @access protected
  87713. */
  87714. function validateSummary()
  87715. {
  87716. return true;
  87717. }
  87718. /**
  87719. * @access protected
  87720. */
  87721. function validateDescription()
  87722. {
  87723. return true;
  87724. }
  87725. /**
  87726. * @access protected
  87727. */
  87728. function validateLicense()
  87729. {
  87730. return true;
  87731. }
  87732. /**
  87733. * @access protected
  87734. */
  87735. function validateNotes()
  87736. {
  87737. return true;
  87738. }
  87739. /**
  87740. * for package.xml 2.0 only - channels can't use package.xml 1.0
  87741. * @access protected
  87742. */
  87743. function validateDependencies()
  87744. {
  87745. return true;
  87746. }
  87747. /**
  87748. * for package.xml 1.0 only
  87749. * @access private
  87750. */
  87751. function _validateFilelist()
  87752. {
  87753. return true; // placeholder for now
  87754. }
  87755. /**
  87756. * for package.xml 2.0 only
  87757. * @access protected
  87758. */
  87759. function validateMainFilelist()
  87760. {
  87761. return true; // placeholder for now
  87762. }
  87763. /**
  87764. * for package.xml 2.0 only
  87765. * @access protected
  87766. */
  87767. function validateReleaseFilelist()
  87768. {
  87769. return true; // placeholder for now
  87770. }
  87771. /**
  87772. * @access protected
  87773. */
  87774. function validateChangelog()
  87775. {
  87776. return true;
  87777. }
  87778. /**
  87779. * @access protected
  87780. */
  87781. function validateFilelist()
  87782. {
  87783. return true;
  87784. }
  87785. /**
  87786. * @access protected
  87787. */
  87788. function validateDeps()
  87789. {
  87790. return true;
  87791. }
  87792. }<?php
  87793. /**
  87794. * Channel Validator for the pecl.php.net channel
  87795. *
  87796. * PHP 4 and PHP 5
  87797. *
  87798. * @category pear
  87799. * @package PEAR
  87800. * @author Greg Beaver <cellog@php.net>
  87801. * @copyright 1997-2006 The PHP Group
  87802. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87803. * @link http://pear.php.net/package/PEAR
  87804. * @since File available since Release 1.4.0a5
  87805. */
  87806. /**
  87807. * This is the parent class for all validators
  87808. */
  87809. require_once 'phar://go-pear.phar/' . 'PEAR/Validate.php';
  87810. /**
  87811. * Channel Validator for the pecl.php.net channel
  87812. * @category pear
  87813. * @package PEAR
  87814. * @author Greg Beaver <cellog@php.net>
  87815. * @copyright 1997-2009 The Authors
  87816. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  87817. * @version Release: 1.10.10
  87818. * @link http://pear.php.net/package/PEAR
  87819. * @since Class available since Release 1.4.0a5
  87820. */
  87821. class PEAR_Validator_PECL extends PEAR_Validate
  87822. {
  87823. function validateVersion()
  87824. {
  87825. if ($this->_state == PEAR_VALIDATE_PACKAGING) {
  87826. $version = $this->_packagexml->getVersion();
  87827. $versioncomponents = explode('.', $version);
  87828. $last = array_pop($versioncomponents);
  87829. if (substr($last, 1, 2) == 'rc') {
  87830. $this->_addFailure('version', 'Release Candidate versions must have ' .
  87831. 'upper-case RC, not lower-case rc');
  87832. return false;
  87833. }
  87834. }
  87835. return true;
  87836. }
  87837. function validatePackageName()
  87838. {
  87839. $ret = parent::validatePackageName();
  87840. if ($this->_packagexml->getPackageType() == 'extsrc' ||
  87841. $this->_packagexml->getPackageType() == 'zendextsrc') {
  87842. if (strtolower($this->_packagexml->getPackage()) !=
  87843. strtolower($this->_packagexml->getProvidesExtension())) {
  87844. $this->_addWarning('providesextension', 'package name "' .
  87845. $this->_packagexml->getPackage() . '" is different from extension name "' .
  87846. $this->_packagexml->getProvidesExtension() . '"');
  87847. }
  87848. }
  87849. return $ret;
  87850. }
  87851. }
  87852. ?><?php
  87853. /**
  87854. * PEAR_XMLParser
  87855. *
  87856. * PHP versions 4 and 5
  87857. *
  87858. * @category pear
  87859. * @package PEAR
  87860. * @author Greg Beaver <cellog@php.net>
  87861. * @author Stephan Schmidt (original XML_Unserializer code)
  87862. * @copyright 1997-2009 The Authors
  87863. * @license http://opensource.org/licenses/bsd-license New BSD License
  87864. * @link http://pear.php.net/package/PEAR
  87865. * @since File available since Release 1.4.0a1
  87866. */
  87867. /**
  87868. * Parser for any xml file
  87869. * @category pear
  87870. * @package PEAR
  87871. * @author Greg Beaver <cellog@php.net>
  87872. * @author Stephan Schmidt (original XML_Unserializer code)
  87873. * @copyright 1997-2009 The Authors
  87874. * @license http://opensource.org/licenses/bsd-license New BSD License
  87875. * @version Release: 1.10.10
  87876. * @link http://pear.php.net/package/PEAR
  87877. * @since Class available since Release 1.4.0a1
  87878. */
  87879. class PEAR_XMLParser
  87880. {
  87881. /**
  87882. * unserilialized data
  87883. * @var string $_serializedData
  87884. */
  87885. var $_unserializedData = null;
  87886. /**
  87887. * name of the root tag
  87888. * @var string $_root
  87889. */
  87890. var $_root = null;
  87891. /**
  87892. * stack for all data that is found
  87893. * @var array $_dataStack
  87894. */
  87895. var $_dataStack = array();
  87896. /**
  87897. * stack for all values that are generated
  87898. * @var array $_valStack
  87899. */
  87900. var $_valStack = array();
  87901. /**
  87902. * current tag depth
  87903. * @var int $_depth
  87904. */
  87905. var $_depth = 0;
  87906. /**
  87907. * The XML encoding to use
  87908. * @var string $encoding
  87909. */
  87910. var $encoding = 'ISO-8859-1';
  87911. /**
  87912. * @return array
  87913. */
  87914. function getData()
  87915. {
  87916. return $this->_unserializedData;
  87917. }
  87918. /**
  87919. * @param string xml content
  87920. * @return true|PEAR_Error
  87921. */
  87922. function parse($data)
  87923. {
  87924. if (!extension_loaded('xml')) {
  87925. include_once 'phar://go-pear.phar/' . 'PEAR.php';
  87926. return PEAR::raiseError("XML Extension not found", 1);
  87927. }
  87928. $this->_dataStack = $this->_valStack = array();
  87929. $this->_depth = 0;
  87930. if (
  87931. strpos($data, 'encoding="UTF-8"')
  87932. || strpos($data, 'encoding="utf-8"')
  87933. || strpos($data, "encoding='UTF-8'")
  87934. || strpos($data, "encoding='utf-8'")
  87935. ) {
  87936. $this->encoding = 'UTF-8';
  87937. }
  87938. $xp = xml_parser_create($this->encoding);
  87939. xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0);
  87940. xml_set_object($xp, $this);
  87941. xml_set_element_handler($xp, 'startHandler', 'endHandler');
  87942. xml_set_character_data_handler($xp, 'cdataHandler');
  87943. if (!xml_parse($xp, $data)) {
  87944. $msg = xml_error_string(xml_get_error_code($xp));
  87945. $line = xml_get_current_line_number($xp);
  87946. xml_parser_free($xp);
  87947. include_once 'phar://go-pear.phar/' . 'PEAR.php';
  87948. return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2);
  87949. }
  87950. xml_parser_free($xp);
  87951. return true;
  87952. }
  87953. /**
  87954. * Start element handler for XML parser
  87955. *
  87956. * @access private
  87957. * @param object $parser XML parser object
  87958. * @param string $element XML element
  87959. * @param array $attribs attributes of XML tag
  87960. * @return void
  87961. */
  87962. function startHandler($parser, $element, $attribs)
  87963. {
  87964. $this->_depth++;
  87965. $this->_dataStack[$this->_depth] = null;
  87966. $val = array(
  87967. 'name' => $element,
  87968. 'value' => null,
  87969. 'type' => 'string',
  87970. 'childrenKeys' => array(),
  87971. 'aggregKeys' => array()
  87972. );
  87973. if (count($attribs) > 0) {
  87974. $val['children'] = array();
  87975. $val['type'] = 'array';
  87976. $val['children']['attribs'] = $attribs;
  87977. }
  87978. array_push($this->_valStack, $val);
  87979. }
  87980. /**
  87981. * post-process data
  87982. *
  87983. * @param string $data
  87984. * @param string $element element name
  87985. */
  87986. function postProcess($data, $element)
  87987. {
  87988. return trim($data);
  87989. }
  87990. /**
  87991. * End element handler for XML parser
  87992. *
  87993. * @access private
  87994. * @param object XML parser object
  87995. * @param string
  87996. * @return void
  87997. */
  87998. function endHandler($parser, $element)
  87999. {
  88000. $value = array_pop($this->_valStack);
  88001. $data = $this->postProcess($this->_dataStack[$this->_depth], $element);
  88002. // adjust type of the value
  88003. switch (strtolower($value['type'])) {
  88004. // unserialize an array
  88005. case 'array':
  88006. if ($data !== '') {
  88007. $value['children']['_content'] = $data;
  88008. }
  88009. $value['value'] = isset($value['children']) ? $value['children'] : array();
  88010. break;
  88011. /*
  88012. * unserialize a null value
  88013. */
  88014. case 'null':
  88015. $data = null;
  88016. break;
  88017. /*
  88018. * unserialize any scalar value
  88019. */
  88020. default:
  88021. settype($data, $value['type']);
  88022. $value['value'] = $data;
  88023. break;
  88024. }
  88025. $parent = array_pop($this->_valStack);
  88026. if ($parent === null) {
  88027. $this->_unserializedData = &$value['value'];
  88028. $this->_root = &$value['name'];
  88029. return true;
  88030. }
  88031. // parent has to be an array
  88032. if (!isset($parent['children']) || !is_array($parent['children'])) {
  88033. $parent['children'] = array();
  88034. if ($parent['type'] != 'array') {
  88035. $parent['type'] = 'array';
  88036. }
  88037. }
  88038. if (!empty($value['name'])) {
  88039. // there already has been a tag with this name
  88040. if (in_array($value['name'], $parent['childrenKeys'])) {
  88041. // no aggregate has been created for this tag
  88042. if (!in_array($value['name'], $parent['aggregKeys'])) {
  88043. if (isset($parent['children'][$value['name']])) {
  88044. $parent['children'][$value['name']] = array($parent['children'][$value['name']]);
  88045. } else {
  88046. $parent['children'][$value['name']] = array();
  88047. }
  88048. array_push($parent['aggregKeys'], $value['name']);
  88049. }
  88050. array_push($parent['children'][$value['name']], $value['value']);
  88051. } else {
  88052. $parent['children'][$value['name']] = &$value['value'];
  88053. array_push($parent['childrenKeys'], $value['name']);
  88054. }
  88055. } else {
  88056. array_push($parent['children'],$value['value']);
  88057. }
  88058. array_push($this->_valStack, $parent);
  88059. $this->_depth--;
  88060. }
  88061. /**
  88062. * Handler for character data
  88063. *
  88064. * @access private
  88065. * @param object XML parser object
  88066. * @param string CDATA
  88067. * @return void
  88068. */
  88069. function cdataHandler($parser, $cdata)
  88070. {
  88071. $this->_dataStack[$this->_depth] .= $cdata;
  88072. }
  88073. }<?php
  88074. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  88075. // +-----------------------------------------------------------------------------+
  88076. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  88077. // +-----------------------------------------------------------------------------+
  88078. // | This file is part of Structures_Graph. |
  88079. // | |
  88080. // | Structures_Graph is free software; you can redistribute it and/or modify |
  88081. // | it under the terms of the GNU Lesser General Public License as published by |
  88082. // | the Free Software Foundation; either version 2.1 of the License, or |
  88083. // | (at your option) any later version. |
  88084. // | |
  88085. // | Structures_Graph is distributed in the hope that it will be useful, |
  88086. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  88087. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  88088. // | GNU Lesser General Public License for more details. |
  88089. // | |
  88090. // | You should have received a copy of the GNU Lesser General Public License |
  88091. // | along with Structures_Graph; if not, write to the Free Software |
  88092. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  88093. // | 02111-1307 USA |
  88094. // +-----------------------------------------------------------------------------+
  88095. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  88096. // +-----------------------------------------------------------------------------+
  88097. //
  88098. /**
  88099. * The Graph.php file contains the definition of the Structures_Graph class
  88100. *
  88101. * @package Structures_Graph
  88102. */
  88103. /* dependencies {{{ */
  88104. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  88105. require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php';
  88106. /* }}} */
  88107. define('STRUCTURES_GRAPH_ERROR_GENERIC', 100);
  88108. /* class Structures_Graph {{{ */
  88109. /**
  88110. * The Structures_Graph class represents a graph data structure.
  88111. *
  88112. * A Graph is a data structure composed by a set of nodes, connected by arcs.
  88113. * Graphs may either be directed or undirected. In a directed graph, arcs are
  88114. * directional, and can be traveled only one way. In an undirected graph, arcs
  88115. * are bidirectional, and can be traveled both ways.
  88116. *
  88117. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  88118. * @copyright (c) 2004 by Sérgio Carvalho
  88119. * @package Structures_Graph
  88120. */
  88121. /* }}} */
  88122. class Structures_Graph
  88123. {
  88124. /**
  88125. * List of node objects in this graph
  88126. * @access private
  88127. */
  88128. var $_nodes = array();
  88129. /**
  88130. * If the graph is directed or not
  88131. * @access private
  88132. */
  88133. var $_directed = false;
  88134. /**
  88135. * Constructor
  88136. *
  88137. * @param boolean $directed Set to true if the graph is directed.
  88138. * Set to false if it is not directed.
  88139. */
  88140. public function __construct($directed = true)
  88141. {
  88142. $this->_directed = $directed;
  88143. }
  88144. /**
  88145. * Old constructor (PHP4-style; kept for BC with extending classes)
  88146. *
  88147. * @param boolean $directed Set to true if the graph is directed.
  88148. * Set to false if it is not directed.
  88149. *
  88150. * @return void
  88151. */
  88152. public function Structures_Graph($directed = true)
  88153. {
  88154. $this->__construct($directed);
  88155. }
  88156. /**
  88157. * Return true if a graph is directed
  88158. *
  88159. * @return boolean true if the graph is directed
  88160. */
  88161. public function isDirected()
  88162. {
  88163. return (boolean) $this->_directed;
  88164. }
  88165. /**
  88166. * Add a Node to the Graph
  88167. *
  88168. * @param Structures_Graph_Node $newNode The node to be added.
  88169. *
  88170. * @return void
  88171. */
  88172. public function addNode(&$newNode)
  88173. {
  88174. // We only add nodes
  88175. if (!is_a($newNode, 'Structures_Graph_Node')) {
  88176. return Pear::raiseError(
  88177. 'Structures_Graph::addNode received an object that is not'
  88178. . ' a Structures_Graph_Node',
  88179. STRUCTURES_GRAPH_ERROR_GENERIC
  88180. );
  88181. }
  88182. //Graphs are node *sets*, so duplicates are forbidden.
  88183. // We allow nodes that are exactly equal, but disallow equal references.
  88184. foreach ($this->_nodes as $key => $node) {
  88185. /*
  88186. ZE1 equality operators choke on the recursive cycle introduced
  88187. by the _graph field in the Node object.
  88188. So, we'll check references the hard way
  88189. (change $this->_nodes[$key] and check if the change reflects in
  88190. $node)
  88191. */
  88192. $savedData = $this->_nodes[$key];
  88193. $referenceIsEqualFlag = false;
  88194. $this->_nodes[$key] = true;
  88195. if ($node === true) {
  88196. $this->_nodes[$key] = false;
  88197. if ($node === false) {
  88198. $referenceIsEqualFlag = true;
  88199. }
  88200. }
  88201. $this->_nodes[$key] = $savedData;
  88202. if ($referenceIsEqualFlag) {
  88203. return Pear::raiseError(
  88204. 'Structures_Graph::addNode received an object that is'
  88205. . ' a duplicate for this dataset',
  88206. STRUCTURES_GRAPH_ERROR_GENERIC
  88207. );
  88208. }
  88209. }
  88210. $this->_nodes[] =& $newNode;
  88211. $newNode->setGraph($this);
  88212. }
  88213. /**
  88214. * Remove a Node from the Graph
  88215. *
  88216. * @param Structures_Graph_Node $node The node to be removed from the graph
  88217. *
  88218. * @return void
  88219. * @todo This is unimplemented
  88220. */
  88221. public function removeNode(&$node)
  88222. {
  88223. }
  88224. /**
  88225. * Return the node set, in no particular order.
  88226. * For ordered node sets, use a Graph Manipulator insted.
  88227. *
  88228. * @return array The set of nodes in this graph
  88229. * @see Structures_Graph_Manipulator_TopologicalSorter
  88230. */
  88231. public function &getNodes()
  88232. {
  88233. return $this->_nodes;
  88234. }
  88235. }
  88236. ?>
  88237. <?php
  88238. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  88239. // +-----------------------------------------------------------------------------+
  88240. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  88241. // +-----------------------------------------------------------------------------+
  88242. // | This file is part of Structures_Graph. |
  88243. // | |
  88244. // | Structures_Graph is free software; you can redistribute it and/or modify |
  88245. // | it under the terms of the GNU Lesser General Public License as published by |
  88246. // | the Free Software Foundation; either version 2.1 of the License, or |
  88247. // | (at your option) any later version. |
  88248. // | |
  88249. // | Structures_Graph is distributed in the hope that it will be useful, |
  88250. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  88251. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  88252. // | GNU Lesser General Public License for more details. |
  88253. // | |
  88254. // | You should have received a copy of the GNU Lesser General Public License |
  88255. // | along with Structures_Graph; if not, write to the Free Software |
  88256. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  88257. // | 02111-1307 USA |
  88258. // +-----------------------------------------------------------------------------+
  88259. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  88260. // +-----------------------------------------------------------------------------+
  88261. //
  88262. /**
  88263. * This file contains the definition of the Structures_Graph_Manipulator_AcyclicTest graph manipulator.
  88264. *
  88265. * @see Structures_Graph_Manipulator_AcyclicTest
  88266. * @package Structures_Graph
  88267. */
  88268. /* dependencies {{{ */
  88269. /** */
  88270. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  88271. /** */
  88272. require_once 'phar://go-pear.phar/' . 'Structures/Graph.php';
  88273. /** */
  88274. require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php';
  88275. /* }}} */
  88276. /* class Structures_Graph_Manipulator_AcyclicTest {{{ */
  88277. /**
  88278. * The Structures_Graph_Manipulator_AcyclicTest is a graph manipulator
  88279. * which tests whether a graph contains a cycle.
  88280. *
  88281. * The definition of an acyclic graph used in this manipulator is that of a
  88282. * DAG. The graph must be directed, or else it is considered cyclic, even when
  88283. * there are no arcs.
  88284. *
  88285. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  88286. * @copyright (c) 2004 by Sérgio Carvalho
  88287. * @package Structures_Graph
  88288. */
  88289. class Structures_Graph_Manipulator_AcyclicTest {
  88290. /* _nonVisitedInDegree {{{ */
  88291. /**
  88292. *
  88293. * This is a variant of Structures_Graph::inDegree which does
  88294. * not count nodes marked as visited.
  88295. *
  88296. * @return integer Number of non-visited nodes that link to this one
  88297. */
  88298. protected static function _nonVisitedInDegree(&$node) {
  88299. $result = 0;
  88300. $graphNodes =& $node->_graph->getNodes();
  88301. foreach (array_keys($graphNodes) as $key) {
  88302. if ((!$graphNodes[$key]->getMetadata('acyclic-test-visited')) && $graphNodes[$key]->connectsTo($node)) $result++;
  88303. }
  88304. return $result;
  88305. }
  88306. /* }}} */
  88307. /* _isAcyclic {{{ */
  88308. /**
  88309. * Check if the graph is acyclic
  88310. */
  88311. protected static function _isAcyclic(&$graph) {
  88312. // Mark every node as not visited
  88313. $nodes =& $graph->getNodes();
  88314. $nodeKeys = array_keys($nodes);
  88315. $refGenerator = array();
  88316. foreach($nodeKeys as $key) {
  88317. $refGenerator[] = false;
  88318. $nodes[$key]->setMetadata('acyclic-test-visited', $refGenerator[sizeof($refGenerator) - 1]);
  88319. }
  88320. // Iteratively peel off leaf nodes
  88321. do {
  88322. // Find out which nodes are leafs (excluding visited nodes)
  88323. $leafNodes = array();
  88324. foreach($nodeKeys as $key) {
  88325. if ((!$nodes[$key]->getMetadata('acyclic-test-visited')) && Structures_Graph_Manipulator_AcyclicTest::_nonVisitedInDegree($nodes[$key]) == 0) {
  88326. $leafNodes[] =& $nodes[$key];
  88327. }
  88328. }
  88329. // Mark leafs as visited
  88330. for ($i=sizeof($leafNodes) - 1; $i>=0; $i--) {
  88331. $visited =& $leafNodes[$i]->getMetadata('acyclic-test-visited');
  88332. $visited = true;
  88333. $leafNodes[$i]->setMetadata('acyclic-test-visited', $visited);
  88334. }
  88335. } while (sizeof($leafNodes) > 0);
  88336. // If graph is a DAG, there should be no non-visited nodes. Let's try to prove otherwise
  88337. $result = true;
  88338. foreach($nodeKeys as $key) if (!$nodes[$key]->getMetadata('acyclic-test-visited')) $result = false;
  88339. // Cleanup visited marks
  88340. foreach($nodeKeys as $key) $nodes[$key]->unsetMetadata('acyclic-test-visited');
  88341. return $result;
  88342. }
  88343. /* }}} */
  88344. /* isAcyclic {{{ */
  88345. /**
  88346. *
  88347. * isAcyclic returns true if a graph contains no cycles, false otherwise.
  88348. *
  88349. * @return boolean true iff graph is acyclic
  88350. */
  88351. public static function isAcyclic(&$graph) {
  88352. // We only test graphs
  88353. if (!is_a($graph, 'Structures_Graph')) return Pear::raiseError('Structures_Graph_Manipulator_AcyclicTest::isAcyclic received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  88354. if (!$graph->isDirected()) return false; // Only directed graphs may be acyclic
  88355. return Structures_Graph_Manipulator_AcyclicTest::_isAcyclic($graph);
  88356. }
  88357. /* }}} */
  88358. }
  88359. /* }}} */
  88360. ?>
  88361. <?php
  88362. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  88363. // +-----------------------------------------------------------------------------+
  88364. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  88365. // +-----------------------------------------------------------------------------+
  88366. // | This file is part of Structures_Graph. |
  88367. // | |
  88368. // | Structures_Graph is free software; you can redistribute it and/or modify |
  88369. // | it under the terms of the GNU Lesser General Public License as published by |
  88370. // | the Free Software Foundation; either version 2.1 of the License, or |
  88371. // | (at your option) any later version. |
  88372. // | |
  88373. // | Structures_Graph is distributed in the hope that it will be useful, |
  88374. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  88375. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  88376. // | GNU Lesser General Public License for more details. |
  88377. // | |
  88378. // | You should have received a copy of the GNU Lesser General Public License |
  88379. // | along with Structures_Graph; if not, write to the Free Software |
  88380. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  88381. // | 02111-1307 USA |
  88382. // +-----------------------------------------------------------------------------+
  88383. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  88384. // +-----------------------------------------------------------------------------+
  88385. //
  88386. /**
  88387. * This file contains the definition of the Structures_Graph_Manipulator_TopologicalSorter class.
  88388. *
  88389. * @package Structures_Graph
  88390. */
  88391. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  88392. require_once 'phar://go-pear.phar/' . 'Structures/Graph.php';
  88393. require_once 'phar://go-pear.phar/' . 'Structures/Graph/Node.php';
  88394. require_once 'phar://go-pear.phar/' . 'Structures/Graph/Manipulator/AcyclicTest.php';
  88395. /**
  88396. * The Structures_Graph_Manipulator_TopologicalSorter is a manipulator
  88397. * which is able to return the set of nodes in a graph, sorted by topological
  88398. * order.
  88399. *
  88400. * A graph may only be sorted topologically iff it's a DAG. You can test it
  88401. * with the Structures_Graph_Manipulator_AcyclicTest.
  88402. *
  88403. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  88404. * @copyright (c) 2004 by Sérgio Carvalho
  88405. * @see Structures_Graph_Manipulator_AcyclicTest
  88406. * @package Structures_Graph
  88407. */
  88408. class Structures_Graph_Manipulator_TopologicalSorter
  88409. {
  88410. /**
  88411. * This is a variant of Structures_Graph::inDegree which does
  88412. * not count nodes marked as visited.
  88413. *
  88414. * @param object $node Node to check
  88415. *
  88416. * @return integer Number of non-visited nodes that link to this one
  88417. */
  88418. protected static function _nonVisitedInDegree(&$node)
  88419. {
  88420. $result = 0;
  88421. $graphNodes =& $node->_graph->getNodes();
  88422. foreach (array_keys($graphNodes) as $key) {
  88423. if ((!$graphNodes[$key]->getMetadata('topological-sort-visited'))
  88424. && $graphNodes[$key]->connectsTo($node)
  88425. ) {
  88426. $result++;
  88427. }
  88428. }
  88429. return $result;
  88430. }
  88431. /**
  88432. * Sort implementation
  88433. *
  88434. * @param object $graph Graph to sort
  88435. *
  88436. * @return void
  88437. */
  88438. protected static function _sort(&$graph)
  88439. {
  88440. // Mark every node as not visited
  88441. $nodes =& $graph->getNodes();
  88442. $nodeKeys = array_keys($nodes);
  88443. $refGenerator = array();
  88444. foreach ($nodeKeys as $key) {
  88445. $refGenerator[] = false;
  88446. $nodes[$key]->setMetadata(
  88447. 'topological-sort-visited',
  88448. $refGenerator[sizeof($refGenerator) - 1]
  88449. );
  88450. }
  88451. // Iteratively peel off leaf nodes
  88452. $topologicalLevel = 0;
  88453. do {
  88454. // Find out which nodes are leafs (excluding visited nodes)
  88455. $leafNodes = array();
  88456. foreach ($nodeKeys as $key) {
  88457. if ((!$nodes[$key]->getMetadata('topological-sort-visited'))
  88458. && static::_nonVisitedInDegree($nodes[$key]) == 0
  88459. ) {
  88460. $leafNodes[] =& $nodes[$key];
  88461. }
  88462. }
  88463. // Mark leafs as visited
  88464. $refGenerator[] = $topologicalLevel;
  88465. for ($i = sizeof($leafNodes) - 1; $i>=0; $i--) {
  88466. $visited =& $leafNodes[$i]->getMetadata('topological-sort-visited');
  88467. $visited = true;
  88468. $leafNodes[$i]->setMetadata('topological-sort-visited', $visited);
  88469. $leafNodes[$i]->setMetadata(
  88470. 'topological-sort-level',
  88471. $refGenerator[sizeof($refGenerator) - 1]
  88472. );
  88473. }
  88474. $topologicalLevel++;
  88475. } while (sizeof($leafNodes) > 0);
  88476. // Cleanup visited marks
  88477. foreach ($nodeKeys as $key) {
  88478. $nodes[$key]->unsetMetadata('topological-sort-visited');
  88479. }
  88480. }
  88481. /**
  88482. * Sort returns the graph's nodes, sorted by topological order.
  88483. *
  88484. * The result is an array with as many entries as topological levels.
  88485. * Each entry in this array is an array of nodes within
  88486. * the given topological level.
  88487. *
  88488. * @param object $graph Graph to sort
  88489. *
  88490. * @return array The graph's nodes, sorted by topological order.
  88491. */
  88492. public static function sort(&$graph)
  88493. {
  88494. // We only sort graphs
  88495. if (!is_a($graph, 'Structures_Graph')) {
  88496. return Pear::raiseError(
  88497. 'Structures_Graph_Manipulator_TopologicalSorter::sort received'
  88498. . ' an object that is not a Structures_Graph',
  88499. STRUCTURES_GRAPH_ERROR_GENERIC
  88500. );
  88501. }
  88502. if (!Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph)) {
  88503. return Pear::raiseError(
  88504. 'Structures_Graph_Manipulator_TopologicalSorter::sort'
  88505. . ' received an graph that has cycles',
  88506. STRUCTURES_GRAPH_ERROR_GENERIC
  88507. );
  88508. }
  88509. Structures_Graph_Manipulator_TopologicalSorter::_sort($graph);
  88510. $result = array();
  88511. // Fill out result array
  88512. $nodes =& $graph->getNodes();
  88513. $nodeKeys = array_keys($nodes);
  88514. foreach ($nodeKeys as $key) {
  88515. if (!array_key_exists($nodes[$key]->getMetadata('topological-sort-level'), $result)) {
  88516. $result[$nodes[$key]->getMetadata('topological-sort-level')]
  88517. = array();
  88518. }
  88519. $result[$nodes[$key]->getMetadata('topological-sort-level')][]
  88520. =& $nodes[$key];
  88521. $nodes[$key]->unsetMetadata('topological-sort-level');
  88522. }
  88523. return $result;
  88524. }
  88525. }
  88526. ?>
  88527. <?php
  88528. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  88529. // +-----------------------------------------------------------------------------+
  88530. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  88531. // +-----------------------------------------------------------------------------+
  88532. // | This file is part of Structures_Graph. |
  88533. // | |
  88534. // | Structures_Graph is free software; you can redistribute it and/or modify |
  88535. // | it under the terms of the GNU Lesser General Public License as published by |
  88536. // | the Free Software Foundation; either version 2.1 of the License, or |
  88537. // | (at your option) any later version. |
  88538. // | |
  88539. // | Structures_Graph is distributed in the hope that it will be useful, |
  88540. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  88541. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  88542. // | GNU Lesser General Public License for more details. |
  88543. // | |
  88544. // | You should have received a copy of the GNU Lesser General Public License |
  88545. // | along with Structures_Graph; if not, write to the Free Software |
  88546. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  88547. // | 02111-1307 USA |
  88548. // +-----------------------------------------------------------------------------+
  88549. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  88550. // +-----------------------------------------------------------------------------+
  88551. //
  88552. /**
  88553. * This file contains the definition of the Structures_Graph_Node class
  88554. *
  88555. * @see Structures_Graph_Node
  88556. * @package Structures_Graph
  88557. */
  88558. /* dependencies {{{ */
  88559. /** */
  88560. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  88561. /** */
  88562. require_once 'phar://go-pear.phar/' . 'Structures/Graph.php';
  88563. /* }}} */
  88564. /* class Structures_Graph_Node {{{ */
  88565. /**
  88566. * The Structures_Graph_Node class represents a Node that can be member of a
  88567. * graph node set.
  88568. *
  88569. * A graph node can contain data. Under this API, the node contains default data,
  88570. * and key index data. It behaves, thus, both as a regular data node, and as a
  88571. * dictionary (or associative array) node.
  88572. *
  88573. * Regular data is accessed via getData and setData. Key indexed data is accessed
  88574. * via getMetadata and setMetadata.
  88575. *
  88576. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  88577. * @copyright (c) 2004 by Sérgio Carvalho
  88578. * @package Structures_Graph
  88579. */
  88580. /* }}} */
  88581. class Structures_Graph_Node {
  88582. /* fields {{{ */
  88583. /**
  88584. * @access private
  88585. */
  88586. var $_data = null;
  88587. /** @access private */
  88588. var $_metadata = array();
  88589. /** @access private */
  88590. var $_arcs = array();
  88591. /** @access private */
  88592. var $_graph = null;
  88593. /* }}} */
  88594. /* Constructor {{{ */
  88595. /**
  88596. *
  88597. * Constructor
  88598. *
  88599. * @access public
  88600. */
  88601. function __construct() {
  88602. }
  88603. /* }}} */
  88604. /* getGraph {{{ */
  88605. /**
  88606. *
  88607. * Node graph getter
  88608. *
  88609. * @return Structures_Graph Graph where node is stored
  88610. * @access public
  88611. */
  88612. function &getGraph() {
  88613. return $this->_graph;
  88614. }
  88615. /* }}} */
  88616. /* setGraph {{{ */
  88617. /**
  88618. *
  88619. * Node graph setter. This method should not be called directly. Use Graph::addNode instead.
  88620. *
  88621. * @param Structures_Graph Set the graph for this node.
  88622. * @see Structures_Graph::addNode()
  88623. * @access public
  88624. */
  88625. function setGraph(&$graph) {
  88626. $this->_graph =& $graph;
  88627. }
  88628. /* }}} */
  88629. /* getData {{{ */
  88630. /**
  88631. *
  88632. * Node data getter.
  88633. *
  88634. * Each graph node can contain a reference to one variable. This is the getter for that reference.
  88635. *
  88636. * @return mixed Data stored in node
  88637. * @access public
  88638. */
  88639. function &getData() {
  88640. return $this->_data;
  88641. }
  88642. /* }}} */
  88643. /* setData {{{ */
  88644. /**
  88645. *
  88646. * Node data setter
  88647. *
  88648. * Each graph node can contain a reference to one variable. This is the setter for that reference.
  88649. *
  88650. * @return mixed Data to store in node
  88651. * @access public
  88652. */
  88653. function setData(&$data) {
  88654. $this->_data =& $data;
  88655. }
  88656. /* }}} */
  88657. /* metadataKeyExists {{{ */
  88658. /**
  88659. *
  88660. * Test for existence of metadata under a given key.
  88661. *
  88662. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  88663. * associative array or in a dictionary. This method tests whether a given metadata key exists for this node.
  88664. *
  88665. * @param string Key to test
  88666. * @return boolean
  88667. * @access public
  88668. */
  88669. function metadataKeyExists($key) {
  88670. return array_key_exists($key, $this->_metadata);
  88671. }
  88672. /* }}} */
  88673. /* getMetadata {{{ */
  88674. /**
  88675. *
  88676. * Node metadata getter
  88677. *
  88678. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  88679. * associative array or in a dictionary. This method gets the data under the given key. If the key does
  88680. * not exist, an error will be thrown, so testing using metadataKeyExists might be needed.
  88681. *
  88682. * @param string Key
  88683. * @param boolean nullIfNonexistent (defaults to false).
  88684. * @return mixed Metadata Data stored in node under given key
  88685. * @see metadataKeyExists
  88686. * @access public
  88687. */
  88688. function &getMetadata($key, $nullIfNonexistent = false) {
  88689. if (array_key_exists($key, $this->_metadata)) {
  88690. return $this->_metadata[$key];
  88691. } else {
  88692. if ($nullIfNonexistent) {
  88693. $a = null;
  88694. return $a;
  88695. } else {
  88696. $a = Pear::raiseError('Structures_Graph_Node::getMetadata: Requested key does not exist', STRUCTURES_GRAPH_ERROR_GENERIC);
  88697. return $a;
  88698. }
  88699. }
  88700. }
  88701. /* }}} */
  88702. /* unsetMetadata {{{ */
  88703. /**
  88704. *
  88705. * Delete metadata by key
  88706. *
  88707. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  88708. * associative array or in a dictionary. This method removes any data that might be stored under the provided key.
  88709. * If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence.
  88710. *
  88711. * @param string Key
  88712. * @access public
  88713. */
  88714. function unsetMetadata($key) {
  88715. if (array_key_exists($key, $this->_metadata)) unset($this->_metadata[$key]);
  88716. }
  88717. /* }}} */
  88718. /* setMetadata {{{ */
  88719. /**
  88720. *
  88721. * Node metadata setter
  88722. *
  88723. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  88724. * associative array or in a dictionary. This method stores data under the given key. If the key already exists,
  88725. * previously stored data is discarded.
  88726. *
  88727. * @param string Key
  88728. * @param mixed Data
  88729. * @access public
  88730. */
  88731. function setMetadata($key, &$data) {
  88732. $this->_metadata[$key] =& $data;
  88733. }
  88734. /* }}} */
  88735. /* _connectTo {{{ */
  88736. /** @access private */
  88737. function _connectTo(&$destinationNode) {
  88738. $this->_arcs[] =& $destinationNode;
  88739. }
  88740. /* }}} */
  88741. /* connectTo {{{ */
  88742. /**
  88743. *
  88744. * Connect this node to another one.
  88745. *
  88746. * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.
  88747. *
  88748. * @param Structures_Graph_Node Node to connect to
  88749. * @access public
  88750. */
  88751. function connectTo(&$destinationNode) {
  88752. // We only connect to nodes
  88753. if (!is_a($destinationNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph_Node::connectTo received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC);
  88754. // Nodes must already be in graphs to be connected
  88755. if ($this->_graph == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  88756. if ($destinationNode->getGraph() == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect to a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  88757. // Connect here
  88758. $this->_connectTo($destinationNode);
  88759. // If graph is undirected, connect back
  88760. if (!$this->_graph->isDirected()) {
  88761. $destinationNode->_connectTo($this);
  88762. }
  88763. }
  88764. /* }}} */
  88765. /* getNeighbours {{{ */
  88766. /**
  88767. *
  88768. * Return nodes connected to this one.
  88769. *
  88770. * @return array Array of nodes
  88771. * @access public
  88772. */
  88773. function getNeighbours() {
  88774. return $this->_arcs;
  88775. }
  88776. /* }}} */
  88777. /* connectsTo {{{ */
  88778. /**
  88779. *
  88780. * Test wether this node has an arc to the target node
  88781. *
  88782. * @return boolean True if the two nodes are connected
  88783. * @access public
  88784. */
  88785. function connectsTo(&$target) {
  88786. if (version_compare(PHP_VERSION, '5.0.0') >= 0) {
  88787. return in_array($target, $this->getNeighbours(), true);
  88788. }
  88789. $copy = $target;
  88790. $arcKeys = array_keys($this->_arcs);
  88791. foreach($arcKeys as $key) {
  88792. /* ZE1 chokes on this expression:
  88793. if ($target === $arc) return true;
  88794. so, we'll use more convoluted stuff
  88795. */
  88796. $arc =& $this->_arcs[$key];
  88797. $target = true;
  88798. if ($arc === true) {
  88799. $target = false;
  88800. if ($arc === false) {
  88801. $target = $copy;
  88802. return true;
  88803. }
  88804. }
  88805. }
  88806. $target = $copy;
  88807. return false;
  88808. }
  88809. /* }}} */
  88810. /* inDegree {{{ */
  88811. /**
  88812. *
  88813. * Calculate the in degree of the node.
  88814. *
  88815. * The indegree for a node is the number of arcs entering the node. For non directed graphs,
  88816. * the indegree is equal to the outdegree.
  88817. *
  88818. * @return integer In degree of the node
  88819. * @access public
  88820. */
  88821. function inDegree() {
  88822. if ($this->_graph == null) return 0;
  88823. if (!$this->_graph->isDirected()) return $this->outDegree();
  88824. $result = 0;
  88825. $graphNodes =& $this->_graph->getNodes();
  88826. foreach (array_keys($graphNodes) as $key) {
  88827. if ($graphNodes[$key]->connectsTo($this)) $result++;
  88828. }
  88829. return $result;
  88830. }
  88831. /* }}} */
  88832. /* outDegree {{{ */
  88833. /**
  88834. *
  88835. * Calculate the out degree of the node.
  88836. *
  88837. * The outdegree for a node is the number of arcs exiting the node. For non directed graphs,
  88838. * the outdegree is always equal to the indegree.
  88839. *
  88840. * @return integer Out degree of the node
  88841. * @access public
  88842. */
  88843. function outDegree() {
  88844. if ($this->_graph == null) return 0;
  88845. return sizeof($this->_arcs);
  88846. }
  88847. /* }}} */
  88848. }
  88849. ?>
  88850. <?php
  88851. /**
  88852. * File/Directory manipulation
  88853. *
  88854. * PHP versions 4 and 5
  88855. *
  88856. * @category pear
  88857. * @package System
  88858. * @author Tomas V.V.Cox <cox@idecnet.com>
  88859. * @copyright 1997-2009 The Authors
  88860. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  88861. * @link http://pear.php.net/package/PEAR
  88862. * @since File available since Release 0.1
  88863. */
  88864. /**
  88865. * base class
  88866. */
  88867. require_once 'phar://go-pear.phar/' . 'PEAR.php';
  88868. require_once 'phar://go-pear.phar/' . 'Console/Getopt.php';
  88869. $GLOBALS['_System_temp_files'] = array();
  88870. /**
  88871. * System offers cross platform compatible system functions
  88872. *
  88873. * Static functions for different operations. Should work under
  88874. * Unix and Windows. The names and usage has been taken from its respectively
  88875. * GNU commands. The functions will return (bool) false on error and will
  88876. * trigger the error with the PHP trigger_error() function (you can silence
  88877. * the error by prefixing a '@' sign after the function call, but this
  88878. * is not recommended practice. Instead use an error handler with
  88879. * {@link set_error_handler()}).
  88880. *
  88881. * Documentation on this class you can find in:
  88882. * http://pear.php.net/manual/
  88883. *
  88884. * Example usage:
  88885. * if (!@System::rm('-r file1 dir1')) {
  88886. * print "could not delete file1 or dir1";
  88887. * }
  88888. *
  88889. * In case you need to to pass file names with spaces,
  88890. * pass the params as an array:
  88891. *
  88892. * System::rm(array('-r', $file1, $dir1));
  88893. *
  88894. * @category pear
  88895. * @package System
  88896. * @author Tomas V.V. Cox <cox@idecnet.com>
  88897. * @copyright 1997-2006 The PHP Group
  88898. * @license http://opensource.org/licenses/bsd-license.php New BSD License
  88899. * @version Release: 1.10.10
  88900. * @link http://pear.php.net/package/PEAR
  88901. * @since Class available since Release 0.1
  88902. * @static
  88903. */
  88904. class System
  88905. {
  88906. /**
  88907. * returns the commandline arguments of a function
  88908. *
  88909. * @param string $argv the commandline
  88910. * @param string $short_options the allowed option short-tags
  88911. * @param string $long_options the allowed option long-tags
  88912. * @return array the given options and there values
  88913. */
  88914. public static function _parseArgs($argv, $short_options, $long_options = null)
  88915. {
  88916. if (!is_array($argv) && $argv !== null) {
  88917. /*
  88918. // Quote all items that are a short option
  88919. $av = preg_split('/(\A| )--?[a-z0-9]+[ =]?((?<!\\\\)((,\s*)|((?<!,)\s+))?)/i', $argv, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
  88920. $offset = 0;
  88921. foreach ($av as $a) {
  88922. $b = trim($a[0]);
  88923. if ($b[0] == '"' || $b[0] == "'") {
  88924. continue;
  88925. }
  88926. $escape = escapeshellarg($b);
  88927. $pos = $a[1] + $offset;
  88928. $argv = substr_replace($argv, $escape, $pos, strlen($b));
  88929. $offset += 2;
  88930. }
  88931. */
  88932. // Find all items, quoted or otherwise
  88933. preg_match_all("/(?:[\"'])(.*?)(?:['\"])|([^\s]+)/", $argv, $av);
  88934. $argv = $av[1];
  88935. foreach ($av[2] as $k => $a) {
  88936. if (empty($a)) {
  88937. continue;
  88938. }
  88939. $argv[$k] = trim($a) ;
  88940. }
  88941. }
  88942. return Console_Getopt::getopt2($argv, $short_options, $long_options);
  88943. }
  88944. /**
  88945. * Output errors with PHP trigger_error(). You can silence the errors
  88946. * with prefixing a "@" sign to the function call: @System::mkdir(..);
  88947. *
  88948. * @param mixed $error a PEAR error or a string with the error message
  88949. * @return bool false
  88950. */
  88951. protected static function raiseError($error)
  88952. {
  88953. if (PEAR::isError($error)) {
  88954. $error = $error->getMessage();
  88955. }
  88956. trigger_error($error, E_USER_WARNING);
  88957. return false;
  88958. }
  88959. /**
  88960. * Creates a nested array representing the structure of a directory
  88961. *
  88962. * System::_dirToStruct('dir1', 0) =>
  88963. * Array
  88964. * (
  88965. * [dirs] => Array
  88966. * (
  88967. * [0] => dir1
  88968. * )
  88969. *
  88970. * [files] => Array
  88971. * (
  88972. * [0] => dir1/file2
  88973. * [1] => dir1/file3
  88974. * )
  88975. * )
  88976. * @param string $sPath Name of the directory
  88977. * @param integer $maxinst max. deep of the lookup
  88978. * @param integer $aktinst starting deep of the lookup
  88979. * @param bool $silent if true, do not emit errors.
  88980. * @return array the structure of the dir
  88981. */
  88982. protected static function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
  88983. {
  88984. $struct = array('dirs' => array(), 'files' => array());
  88985. if (($dir = @opendir($sPath)) === false) {
  88986. if (!$silent) {
  88987. System::raiseError("Could not open dir $sPath");
  88988. }
  88989. return $struct; // XXX could not open error
  88990. }
  88991. $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
  88992. $list = array();
  88993. while (false !== ($file = readdir($dir))) {
  88994. if ($file != '.' && $file != '..') {
  88995. $list[] = $file;
  88996. }
  88997. }
  88998. closedir($dir);
  88999. natsort($list);
  89000. if ($aktinst < $maxinst || $maxinst == 0) {
  89001. foreach ($list as $val) {
  89002. $path = $sPath . DIRECTORY_SEPARATOR . $val;
  89003. if (is_dir($path) && !is_link($path)) {
  89004. $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
  89005. $struct = array_merge_recursive($struct, $tmp);
  89006. } else {
  89007. $struct['files'][] = $path;
  89008. }
  89009. }
  89010. }
  89011. return $struct;
  89012. }
  89013. /**
  89014. * Creates a nested array representing the structure of a directory and files
  89015. *
  89016. * @param array $files Array listing files and dirs
  89017. * @return array
  89018. * @static
  89019. * @see System::_dirToStruct()
  89020. */
  89021. protected static function _multipleToStruct($files)
  89022. {
  89023. $struct = array('dirs' => array(), 'files' => array());
  89024. settype($files, 'array');
  89025. foreach ($files as $file) {
  89026. if (is_dir($file) && !is_link($file)) {
  89027. $tmp = System::_dirToStruct($file, 0);
  89028. $struct = array_merge_recursive($tmp, $struct);
  89029. } else {
  89030. if (!in_array($file, $struct['files'])) {
  89031. $struct['files'][] = $file;
  89032. }
  89033. }
  89034. }
  89035. return $struct;
  89036. }
  89037. /**
  89038. * The rm command for removing files.
  89039. * Supports multiple files and dirs and also recursive deletes
  89040. *
  89041. * @param string $args the arguments for rm
  89042. * @return mixed PEAR_Error or true for success
  89043. * @static
  89044. * @access public
  89045. */
  89046. public static function rm($args)
  89047. {
  89048. $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
  89049. if (PEAR::isError($opts)) {
  89050. return System::raiseError($opts);
  89051. }
  89052. foreach ($opts[0] as $opt) {
  89053. if ($opt[0] == 'r') {
  89054. $do_recursive = true;
  89055. }
  89056. }
  89057. $ret = true;
  89058. if (isset($do_recursive)) {
  89059. $struct = System::_multipleToStruct($opts[1]);
  89060. foreach ($struct['files'] as $file) {
  89061. if (!@unlink($file)) {
  89062. $ret = false;
  89063. }
  89064. }
  89065. rsort($struct['dirs']);
  89066. foreach ($struct['dirs'] as $dir) {
  89067. if (!@rmdir($dir)) {
  89068. $ret = false;
  89069. }
  89070. }
  89071. } else {
  89072. foreach ($opts[1] as $file) {
  89073. $delete = (is_dir($file)) ? 'rmdir' : 'unlink';
  89074. if (!@$delete($file)) {
  89075. $ret = false;
  89076. }
  89077. }
  89078. }
  89079. return $ret;
  89080. }
  89081. /**
  89082. * Make directories.
  89083. *
  89084. * The -p option will create parent directories
  89085. * @param string $args the name of the director(y|ies) to create
  89086. * @return bool True for success
  89087. */
  89088. public static function mkDir($args)
  89089. {
  89090. $opts = System::_parseArgs($args, 'pm:');
  89091. if (PEAR::isError($opts)) {
  89092. return System::raiseError($opts);
  89093. }
  89094. $mode = 0777; // default mode
  89095. foreach ($opts[0] as $opt) {
  89096. if ($opt[0] == 'p') {
  89097. $create_parents = true;
  89098. } elseif ($opt[0] == 'm') {
  89099. // if the mode is clearly an octal number (starts with 0)
  89100. // convert it to decimal
  89101. if (strlen($opt[1]) && $opt[1][0] == '0') {
  89102. $opt[1] = octdec($opt[1]);
  89103. } else {
  89104. // convert to int
  89105. $opt[1] += 0;
  89106. }
  89107. $mode = $opt[1];
  89108. }
  89109. }
  89110. $ret = true;
  89111. if (isset($create_parents)) {
  89112. foreach ($opts[1] as $dir) {
  89113. $dirstack = array();
  89114. while ((!file_exists($dir) || !is_dir($dir)) &&
  89115. $dir != DIRECTORY_SEPARATOR) {
  89116. array_unshift($dirstack, $dir);
  89117. $dir = dirname($dir);
  89118. }
  89119. while ($newdir = array_shift($dirstack)) {
  89120. if (!is_writeable(dirname($newdir))) {
  89121. $ret = false;
  89122. break;
  89123. }
  89124. if (!mkdir($newdir, $mode)) {
  89125. $ret = false;
  89126. }
  89127. }
  89128. }
  89129. } else {
  89130. foreach($opts[1] as $dir) {
  89131. if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
  89132. $ret = false;
  89133. }
  89134. }
  89135. }
  89136. return $ret;
  89137. }
  89138. /**
  89139. * Concatenate files
  89140. *
  89141. * Usage:
  89142. * 1) $var = System::cat('sample.txt test.txt');
  89143. * 2) System::cat('sample.txt test.txt > final.txt');
  89144. * 3) System::cat('sample.txt test.txt >> final.txt');
  89145. *
  89146. * Note: as the class use fopen, urls should work also
  89147. *
  89148. * @param string $args the arguments
  89149. * @return boolean true on success
  89150. */
  89151. public static function &cat($args)
  89152. {
  89153. $ret = null;
  89154. $files = array();
  89155. if (!is_array($args)) {
  89156. $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
  89157. }
  89158. $count_args = count($args);
  89159. for ($i = 0; $i < $count_args; $i++) {
  89160. if ($args[$i] == '>') {
  89161. $mode = 'wb';
  89162. $outputfile = $args[$i+1];
  89163. break;
  89164. } elseif ($args[$i] == '>>') {
  89165. $mode = 'ab+';
  89166. $outputfile = $args[$i+1];
  89167. break;
  89168. } else {
  89169. $files[] = $args[$i];
  89170. }
  89171. }
  89172. $outputfd = false;
  89173. if (isset($mode)) {
  89174. if (!$outputfd = fopen($outputfile, $mode)) {
  89175. $err = System::raiseError("Could not open $outputfile");
  89176. return $err;
  89177. }
  89178. $ret = true;
  89179. }
  89180. foreach ($files as $file) {
  89181. if (!$fd = fopen($file, 'r')) {
  89182. System::raiseError("Could not open $file");
  89183. continue;
  89184. }
  89185. while ($cont = fread($fd, 2048)) {
  89186. if (is_resource($outputfd)) {
  89187. fwrite($outputfd, $cont);
  89188. } else {
  89189. $ret .= $cont;
  89190. }
  89191. }
  89192. fclose($fd);
  89193. }
  89194. if (is_resource($outputfd)) {
  89195. fclose($outputfd);
  89196. }
  89197. return $ret;
  89198. }
  89199. /**
  89200. * Creates temporary files or directories. This function will remove
  89201. * the created files when the scripts finish its execution.
  89202. *
  89203. * Usage:
  89204. * 1) $tempfile = System::mktemp("prefix");
  89205. * 2) $tempdir = System::mktemp("-d prefix");
  89206. * 3) $tempfile = System::mktemp();
  89207. * 4) $tempfile = System::mktemp("-t /var/tmp prefix");
  89208. *
  89209. * prefix -> The string that will be prepended to the temp name
  89210. * (defaults to "tmp").
  89211. * -d -> A temporary dir will be created instead of a file.
  89212. * -t -> The target dir where the temporary (file|dir) will be created. If
  89213. * this param is missing by default the env vars TMP on Windows or
  89214. * TMPDIR in Unix will be used. If these vars are also missing
  89215. * c:\windows\temp or /tmp will be used.
  89216. *
  89217. * @param string $args The arguments
  89218. * @return mixed the full path of the created (file|dir) or false
  89219. * @see System::tmpdir()
  89220. */
  89221. public static function mktemp($args = null)
  89222. {
  89223. static $first_time = true;
  89224. $opts = System::_parseArgs($args, 't:d');
  89225. if (PEAR::isError($opts)) {
  89226. return System::raiseError($opts);
  89227. }
  89228. foreach ($opts[0] as $opt) {
  89229. if ($opt[0] == 'd') {
  89230. $tmp_is_dir = true;
  89231. } elseif ($opt[0] == 't') {
  89232. $tmpdir = $opt[1];
  89233. }
  89234. }
  89235. $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
  89236. if (!isset($tmpdir)) {
  89237. $tmpdir = System::tmpdir();
  89238. }
  89239. if (!System::mkDir(array('-p', $tmpdir))) {
  89240. return false;
  89241. }
  89242. $tmp = tempnam($tmpdir, $prefix);
  89243. if (isset($tmp_is_dir)) {
  89244. unlink($tmp); // be careful possible race condition here
  89245. if (!mkdir($tmp, 0700)) {
  89246. return System::raiseError("Unable to create temporary directory $tmpdir");
  89247. }
  89248. }
  89249. $GLOBALS['_System_temp_files'][] = $tmp;
  89250. if (isset($tmp_is_dir)) {
  89251. //$GLOBALS['_System_temp_files'][] = dirname($tmp);
  89252. }
  89253. if ($first_time) {
  89254. PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
  89255. $first_time = false;
  89256. }
  89257. return $tmp;
  89258. }
  89259. /**
  89260. * Remove temporary files created my mkTemp. This function is executed
  89261. * at script shutdown time
  89262. */
  89263. public static function _removeTmpFiles()
  89264. {
  89265. if (count($GLOBALS['_System_temp_files'])) {
  89266. $delete = $GLOBALS['_System_temp_files'];
  89267. array_unshift($delete, '-r');
  89268. System::rm($delete);
  89269. $GLOBALS['_System_temp_files'] = array();
  89270. }
  89271. }
  89272. /**
  89273. * Get the path of the temporal directory set in the system
  89274. * by looking in its environments variables.
  89275. * Note: php.ini-recommended removes the "E" from the variables_order setting,
  89276. * making unavaible the $_ENV array, that s why we do tests with _ENV
  89277. *
  89278. * @return string The temporary directory on the system
  89279. */
  89280. public static function tmpdir()
  89281. {
  89282. if (OS_WINDOWS) {
  89283. if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
  89284. return $var;
  89285. }
  89286. if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
  89287. return $var;
  89288. }
  89289. if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
  89290. return $var;
  89291. }
  89292. if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
  89293. return $var;
  89294. }
  89295. return getenv('SystemRoot') . '\temp';
  89296. }
  89297. if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
  89298. return $var;
  89299. }
  89300. return realpath(function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '/tmp');
  89301. }
  89302. /**
  89303. * The "which" command (show the full path of a command)
  89304. *
  89305. * @param string $program The command to search for
  89306. * @param mixed $fallback Value to return if $program is not found
  89307. *
  89308. * @return mixed A string with the full path or false if not found
  89309. * @author Stig Bakken <ssb@php.net>
  89310. */
  89311. public static function which($program, $fallback = false)
  89312. {
  89313. // enforce API
  89314. if (!is_string($program) || '' == $program) {
  89315. return $fallback;
  89316. }
  89317. // full path given
  89318. if (basename($program) != $program) {
  89319. $path_elements[] = dirname($program);
  89320. $program = basename($program);
  89321. } else {
  89322. $path = getenv('PATH');
  89323. if (!$path) {
  89324. $path = getenv('Path'); // some OSes are just stupid enough to do this
  89325. }
  89326. $path_elements = explode(PATH_SEPARATOR, $path);
  89327. }
  89328. if (OS_WINDOWS) {
  89329. $exe_suffixes = getenv('PATHEXT')
  89330. ? explode(PATH_SEPARATOR, getenv('PATHEXT'))
  89331. : array('.exe','.bat','.cmd','.com');
  89332. // allow passing a command.exe param
  89333. if (strpos($program, '.') !== false) {
  89334. array_unshift($exe_suffixes, '');
  89335. }
  89336. } else {
  89337. $exe_suffixes = array('');
  89338. }
  89339. foreach ($exe_suffixes as $suff) {
  89340. foreach ($path_elements as $dir) {
  89341. $file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
  89342. // It's possible to run a .bat on Windows that is_executable
  89343. // would return false for. The is_executable check is meaningless...
  89344. if (OS_WINDOWS) {
  89345. return $file;
  89346. } else {
  89347. if (is_executable($file)) {
  89348. return $file;
  89349. }
  89350. }
  89351. }
  89352. }
  89353. return $fallback;
  89354. }
  89355. /**
  89356. * The "find" command
  89357. *
  89358. * Usage:
  89359. *
  89360. * System::find($dir);
  89361. * System::find("$dir -type d");
  89362. * System::find("$dir -type f");
  89363. * System::find("$dir -name *.php");
  89364. * System::find("$dir -name *.php -name *.htm*");
  89365. * System::find("$dir -maxdepth 1");
  89366. *
  89367. * Params implemented:
  89368. * $dir -> Start the search at this directory
  89369. * -type d -> return only directories
  89370. * -type f -> return only files
  89371. * -maxdepth <n> -> max depth of recursion
  89372. * -name <pattern> -> search pattern (bash style). Multiple -name param allowed
  89373. *
  89374. * @param mixed Either array or string with the command line
  89375. * @return array Array of found files
  89376. */
  89377. public static function find($args)
  89378. {
  89379. if (!is_array($args)) {
  89380. $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
  89381. }
  89382. $dir = realpath(array_shift($args));
  89383. if (!$dir) {
  89384. return array();
  89385. }
  89386. $patterns = array();
  89387. $depth = 0;
  89388. $do_files = $do_dirs = true;
  89389. $args_count = count($args);
  89390. for ($i = 0; $i < $args_count; $i++) {
  89391. switch ($args[$i]) {
  89392. case '-type':
  89393. if (in_array($args[$i+1], array('d', 'f'))) {
  89394. if ($args[$i+1] == 'd') {
  89395. $do_files = false;
  89396. } else {
  89397. $do_dirs = false;
  89398. }
  89399. }
  89400. $i++;
  89401. break;
  89402. case '-name':
  89403. $name = preg_quote($args[$i+1], '#');
  89404. // our magic characters ? and * have just been escaped,
  89405. // so now we change the escaped versions to PCRE operators
  89406. $name = strtr($name, array('\?' => '.', '\*' => '.*'));
  89407. $patterns[] = '('.$name.')';
  89408. $i++;
  89409. break;
  89410. case '-maxdepth':
  89411. $depth = $args[$i+1];
  89412. break;
  89413. }
  89414. }
  89415. $path = System::_dirToStruct($dir, $depth, 0, true);
  89416. if ($do_files && $do_dirs) {
  89417. $files = array_merge($path['files'], $path['dirs']);
  89418. } elseif ($do_dirs) {
  89419. $files = $path['dirs'];
  89420. } else {
  89421. $files = $path['files'];
  89422. }
  89423. if (count($patterns)) {
  89424. $dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
  89425. $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#';
  89426. $ret = array();
  89427. $files_count = count($files);
  89428. for ($i = 0; $i < $files_count; $i++) {
  89429. // only search in the part of the file below the current directory
  89430. $filepart = basename($files[$i]);
  89431. if (preg_match($pattern, $filepart)) {
  89432. $ret[] = $files[$i];
  89433. }
  89434. }
  89435. return $ret;
  89436. }
  89437. return $files;
  89438. }
  89439. }
  89440. <?php
  89441. /**
  89442. * XML_Util
  89443. *
  89444. * XML Utilities package
  89445. *
  89446. * PHP versions 4 and 5
  89447. *
  89448. * LICENSE:
  89449. *
  89450. * Copyright (c) 2003-2008 Stephan Schmidt <schst@php.net>
  89451. * All rights reserved.
  89452. *
  89453. * Redistribution and use in source and binary forms, with or without
  89454. * modification, are permitted provided that the following conditions
  89455. * are met:
  89456. *
  89457. * * Redistributions of source code must retain the above copyright
  89458. * notice, this list of conditions and the following disclaimer.
  89459. * * Redistributions in binary form must reproduce the above copyright
  89460. * notice, this list of conditions and the following disclaimer in the
  89461. * documentation and/or other materials provided with the distribution.
  89462. * * The name of the author may not be used to endorse or promote products
  89463. * derived from this software without specific prior written permission.
  89464. *
  89465. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  89466. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  89467. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  89468. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  89469. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  89470. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  89471. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  89472. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  89473. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  89474. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  89475. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  89476. *
  89477. * @category XML
  89478. * @package XML_Util
  89479. * @author Stephan Schmidt <schst@php.net>
  89480. * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
  89481. * @license http://opensource.org/licenses/bsd-license New BSD License
  89482. * @version CVS: $Id$
  89483. * @link http://pear.php.net/package/XML_Util
  89484. */
  89485. /**
  89486. * Error code for invalid chars in XML name
  89487. */
  89488. define('XML_UTIL_ERROR_INVALID_CHARS', 51);
  89489. /**
  89490. * Error code for invalid chars in XML name
  89491. */
  89492. define('XML_UTIL_ERROR_INVALID_START', 52);
  89493. /**
  89494. * Error code for non-scalar tag content
  89495. */
  89496. define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60);
  89497. /**
  89498. * Error code for missing tag name
  89499. */
  89500. define('XML_UTIL_ERROR_NO_TAG_NAME', 61);
  89501. /**
  89502. * Replace XML entities
  89503. */
  89504. define('XML_UTIL_REPLACE_ENTITIES', 1);
  89505. /**
  89506. * Embedd content in a CData Section
  89507. */
  89508. define('XML_UTIL_CDATA_SECTION', 5);
  89509. /**
  89510. * Do not replace entitites
  89511. */
  89512. define('XML_UTIL_ENTITIES_NONE', 0);
  89513. /**
  89514. * Replace all XML entitites
  89515. * This setting will replace <, >, ", ' and &
  89516. */
  89517. define('XML_UTIL_ENTITIES_XML', 1);
  89518. /**
  89519. * Replace only required XML entitites
  89520. * This setting will replace <, " and &
  89521. */
  89522. define('XML_UTIL_ENTITIES_XML_REQUIRED', 2);
  89523. /**
  89524. * Replace HTML entitites
  89525. * @link http://www.php.net/htmlentities
  89526. */
  89527. define('XML_UTIL_ENTITIES_HTML', 3);
  89528. /**
  89529. * Do not collapse any empty tags.
  89530. */
  89531. define('XML_UTIL_COLLAPSE_NONE', 0);
  89532. /**
  89533. * Collapse all empty tags.
  89534. */
  89535. define('XML_UTIL_COLLAPSE_ALL', 1);
  89536. /**
  89537. * Collapse only empty XHTML tags that have no end tag.
  89538. */
  89539. define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2);
  89540. /**
  89541. * Utility class for working with XML documents
  89542. *
  89543. * @category XML
  89544. * @package XML_Util
  89545. * @author Stephan Schmidt <schst@php.net>
  89546. * @copyright 2003-2008 Stephan Schmidt <schst@php.net>
  89547. * @license http://opensource.org/licenses/bsd-license New BSD License
  89548. * @version Release: 1.4.3
  89549. * @link http://pear.php.net/package/XML_Util
  89550. */
  89551. class XML_Util
  89552. {
  89553. /**
  89554. * Return API version
  89555. *
  89556. * @return string $version API version
  89557. */
  89558. public static function apiVersion()
  89559. {
  89560. return '1.4';
  89561. }
  89562. /**
  89563. * Replace XML entities
  89564. *
  89565. * With the optional second parameter, you may select, which
  89566. * entities should be replaced.
  89567. *
  89568. * <code>
  89569. * require_once 'XML/Util.php';
  89570. *
  89571. * // replace XML entites:
  89572. * $string = XML_Util::replaceEntities('This string contains < & >.');
  89573. * </code>
  89574. *
  89575. * With the optional third parameter, you may pass the character encoding
  89576. * <code>
  89577. * require_once 'XML/Util.php';
  89578. *
  89579. * // replace XML entites in UTF-8:
  89580. * $string = XML_Util::replaceEntities(
  89581. * 'This string contains < & > as well as ä, ö, ß, à and ê',
  89582. * XML_UTIL_ENTITIES_HTML,
  89583. * 'UTF-8'
  89584. * );
  89585. * </code>
  89586. *
  89587. * @param string $string string where XML special chars
  89588. * should be replaced
  89589. * @param int $replaceEntities setting for entities in attribute values
  89590. * (one of XML_UTIL_ENTITIES_XML,
  89591. * XML_UTIL_ENTITIES_XML_REQUIRED,
  89592. * XML_UTIL_ENTITIES_HTML)
  89593. * @param string $encoding encoding value (if any)...
  89594. * must be a valid encoding as determined
  89595. * by the htmlentities() function
  89596. *
  89597. * @return string string with replaced chars
  89598. * @see reverseEntities()
  89599. */
  89600. public static function replaceEntities(
  89601. $string, $replaceEntities = XML_UTIL_ENTITIES_XML, $encoding = 'ISO-8859-1'
  89602. ) {
  89603. switch ($replaceEntities) {
  89604. case XML_UTIL_ENTITIES_XML:
  89605. return strtr(
  89606. $string,
  89607. array(
  89608. '&' => '&amp;',
  89609. '>' => '&gt;',
  89610. '<' => '&lt;',
  89611. '"' => '&quot;',
  89612. '\'' => '&apos;'
  89613. )
  89614. );
  89615. break;
  89616. case XML_UTIL_ENTITIES_XML_REQUIRED:
  89617. return strtr(
  89618. $string,
  89619. array(
  89620. '&' => '&amp;',
  89621. '<' => '&lt;',
  89622. '"' => '&quot;'
  89623. )
  89624. );
  89625. break;
  89626. case XML_UTIL_ENTITIES_HTML:
  89627. return htmlentities($string, ENT_COMPAT, $encoding);
  89628. break;
  89629. }
  89630. return $string;
  89631. }
  89632. /**
  89633. * Reverse XML entities
  89634. *
  89635. * With the optional second parameter, you may select, which
  89636. * entities should be reversed.
  89637. *
  89638. * <code>
  89639. * require_once 'XML/Util.php';
  89640. *
  89641. * // reverse XML entites:
  89642. * $string = XML_Util::reverseEntities('This string contains &lt; &amp; &gt;.');
  89643. * </code>
  89644. *
  89645. * With the optional third parameter, you may pass the character encoding
  89646. * <code>
  89647. * require_once 'XML/Util.php';
  89648. *
  89649. * // reverse XML entites in UTF-8:
  89650. * $string = XML_Util::reverseEntities(
  89651. * 'This string contains &lt; &amp; &gt; as well as'
  89652. * . ' &auml;, &ouml;, &szlig;, &agrave; and &ecirc;',
  89653. * XML_UTIL_ENTITIES_HTML,
  89654. * 'UTF-8'
  89655. * );
  89656. * </code>
  89657. *
  89658. * @param string $string string where XML special chars
  89659. * should be replaced
  89660. * @param int $replaceEntities setting for entities in attribute values
  89661. * (one of XML_UTIL_ENTITIES_XML,
  89662. * XML_UTIL_ENTITIES_XML_REQUIRED,
  89663. * XML_UTIL_ENTITIES_HTML)
  89664. * @param string $encoding encoding value (if any)...
  89665. * must be a valid encoding as determined
  89666. * by the html_entity_decode() function
  89667. *
  89668. * @return string string with replaced chars
  89669. * @see replaceEntities()
  89670. */
  89671. public static function reverseEntities(
  89672. $string, $replaceEntities = XML_UTIL_ENTITIES_XML, $encoding = 'ISO-8859-1'
  89673. ) {
  89674. switch ($replaceEntities) {
  89675. case XML_UTIL_ENTITIES_XML:
  89676. return strtr(
  89677. $string,
  89678. array(
  89679. '&amp;' => '&',
  89680. '&gt;' => '>',
  89681. '&lt;' => '<',
  89682. '&quot;' => '"',
  89683. '&apos;' => '\''
  89684. )
  89685. );
  89686. break;
  89687. case XML_UTIL_ENTITIES_XML_REQUIRED:
  89688. return strtr(
  89689. $string,
  89690. array(
  89691. '&amp;' => '&',
  89692. '&lt;' => '<',
  89693. '&quot;' => '"'
  89694. )
  89695. );
  89696. break;
  89697. case XML_UTIL_ENTITIES_HTML:
  89698. return html_entity_decode($string, ENT_COMPAT, $encoding);
  89699. break;
  89700. }
  89701. return $string;
  89702. }
  89703. /**
  89704. * Build an xml declaration
  89705. *
  89706. * <code>
  89707. * require_once 'XML/Util.php';
  89708. *
  89709. * // get an XML declaration:
  89710. * $xmlDecl = XML_Util::getXMLDeclaration('1.0', 'UTF-8', true);
  89711. * </code>
  89712. *
  89713. * @param string $version xml version
  89714. * @param string $encoding character encoding
  89715. * @param bool $standalone document is standalone (or not)
  89716. *
  89717. * @return string xml declaration
  89718. * @uses attributesToString() to serialize the attributes of the
  89719. * XML declaration
  89720. */
  89721. public static function getXMLDeclaration(
  89722. $version = '1.0', $encoding = null, $standalone = null
  89723. ) {
  89724. $attributes = array(
  89725. 'version' => $version,
  89726. );
  89727. // add encoding
  89728. if ($encoding !== null) {
  89729. $attributes['encoding'] = $encoding;
  89730. }
  89731. // add standalone, if specified
  89732. if ($standalone !== null) {
  89733. $attributes['standalone'] = $standalone ? 'yes' : 'no';
  89734. }
  89735. return sprintf(
  89736. '<?xml%s?>',
  89737. XML_Util::attributesToString($attributes, false)
  89738. );
  89739. }
  89740. /**
  89741. * Build a document type declaration
  89742. *
  89743. * <code>
  89744. * require_once 'XML/Util.php';
  89745. *
  89746. * // get a doctype declaration:
  89747. * $xmlDecl = XML_Util::getDocTypeDeclaration('rootTag','myDocType.dtd');
  89748. * </code>
  89749. *
  89750. * @param string $root name of the root tag
  89751. * @param string $uri uri of the doctype definition
  89752. * (or array with uri and public id)
  89753. * @param string $internalDtd internal dtd entries
  89754. *
  89755. * @return string doctype declaration
  89756. * @since 0.2
  89757. */
  89758. public static function getDocTypeDeclaration(
  89759. $root, $uri = null, $internalDtd = null
  89760. ) {
  89761. if (is_array($uri)) {
  89762. $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']);
  89763. } elseif (!empty($uri)) {
  89764. $ref = sprintf(' SYSTEM "%s"', $uri);
  89765. } else {
  89766. $ref = '';
  89767. }
  89768. if (empty($internalDtd)) {
  89769. return sprintf('<!DOCTYPE %s%s>', $root, $ref);
  89770. } else {
  89771. return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
  89772. }
  89773. }
  89774. /**
  89775. * Create string representation of an attribute list
  89776. *
  89777. * <code>
  89778. * require_once 'XML/Util.php';
  89779. *
  89780. * // build an attribute string
  89781. * $att = array(
  89782. * 'foo' => 'bar',
  89783. * 'argh' => 'tomato'
  89784. * );
  89785. *
  89786. * $attList = XML_Util::attributesToString($att);
  89787. * </code>
  89788. *
  89789. * @param array $attributes attribute array
  89790. * @param bool|array $sort sort attribute list alphabetically,
  89791. * may also be an assoc array containing
  89792. * the keys 'sort', 'multiline', 'indent',
  89793. * 'linebreak' and 'entities'
  89794. * @param bool $multiline use linebreaks, if more than
  89795. * one attribute is given
  89796. * @param string $indent string used for indentation of
  89797. * multiline attributes
  89798. * @param string $linebreak string used for linebreaks of
  89799. * multiline attributes
  89800. * @param int $entities setting for entities in attribute values
  89801. * (one of XML_UTIL_ENTITIES_NONE,
  89802. * XML_UTIL_ENTITIES_XML,
  89803. * XML_UTIL_ENTITIES_XML_REQUIRED,
  89804. * XML_UTIL_ENTITIES_HTML)
  89805. *
  89806. * @return string string representation of the attributes
  89807. * @uses replaceEntities() to replace XML entities in attribute values
  89808. * @todo allow sort also to be an options array
  89809. */
  89810. public static function attributesToString(
  89811. $attributes, $sort = true, $multiline = false,
  89812. $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML
  89813. ) {
  89814. /*
  89815. * second parameter may be an array
  89816. */
  89817. if (is_array($sort)) {
  89818. if (isset($sort['multiline'])) {
  89819. $multiline = $sort['multiline'];
  89820. }
  89821. if (isset($sort['indent'])) {
  89822. $indent = $sort['indent'];
  89823. }
  89824. if (isset($sort['linebreak'])) {
  89825. $multiline = $sort['linebreak'];
  89826. }
  89827. if (isset($sort['entities'])) {
  89828. $entities = $sort['entities'];
  89829. }
  89830. if (isset($sort['sort'])) {
  89831. $sort = $sort['sort'];
  89832. } else {
  89833. $sort = true;
  89834. }
  89835. }
  89836. $string = '';
  89837. if (is_array($attributes) && !empty($attributes)) {
  89838. if ($sort) {
  89839. ksort($attributes);
  89840. }
  89841. if (!$multiline || count($attributes) == 1) {
  89842. foreach ($attributes as $key => $value) {
  89843. if ($entities != XML_UTIL_ENTITIES_NONE) {
  89844. if ($entities === XML_UTIL_CDATA_SECTION) {
  89845. $entities = XML_UTIL_ENTITIES_XML;
  89846. }
  89847. $value = XML_Util::replaceEntities($value, $entities);
  89848. }
  89849. $string .= ' ' . $key . '="' . $value . '"';
  89850. }
  89851. } else {
  89852. $first = true;
  89853. foreach ($attributes as $key => $value) {
  89854. if ($entities != XML_UTIL_ENTITIES_NONE) {
  89855. $value = XML_Util::replaceEntities($value, $entities);
  89856. }
  89857. if ($first) {
  89858. $string .= ' ' . $key . '="' . $value . '"';
  89859. $first = false;
  89860. } else {
  89861. $string .= $linebreak . $indent . $key . '="' . $value . '"';
  89862. }
  89863. }
  89864. }
  89865. }
  89866. return $string;
  89867. }
  89868. /**
  89869. * Collapses empty tags.
  89870. *
  89871. * @param string $xml XML
  89872. * @param int $mode Whether to collapse all empty tags (XML_UTIL_COLLAPSE_ALL)
  89873. * or only XHTML (XML_UTIL_COLLAPSE_XHTML_ONLY) ones.
  89874. *
  89875. * @return string XML
  89876. */
  89877. public static function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL)
  89878. {
  89879. if (preg_match('~<([^>])+/>~s', $xml, $matches)) {
  89880. // it's already an empty tag
  89881. return $xml;
  89882. }
  89883. switch ($mode) {
  89884. case XML_UTIL_COLLAPSE_ALL:
  89885. $preg1 =
  89886. '~<' .
  89887. '(?:' .
  89888. '(https?://[^:\s]+:\w+)' . // <http://foo.com:bar ($1)
  89889. '|(\w+:\w+)' . // <foo:bar ($2)
  89890. '|(\w+)' . // <foo ($3)
  89891. ')+' .
  89892. '([^>]*)' . // attributes ($4)
  89893. '>' .
  89894. '<\/(\1|\2|\3)>' . // 1, 2, or 3 again ($5)
  89895. '~s'
  89896. ;
  89897. $preg2 =
  89898. '<' .
  89899. '${1}${2}${3}' . // tag (only one should have been populated)
  89900. '${4}' . // attributes
  89901. ' />'
  89902. ;
  89903. return (preg_replace($preg1, $preg2, $xml)?:$xml);
  89904. break;
  89905. case XML_UTIL_COLLAPSE_XHTML_ONLY:
  89906. return (
  89907. preg_replace(
  89908. '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|'
  89909. . 'param)([^>]*)><\/\\1>/s',
  89910. '<\\1\\2 />',
  89911. $xml
  89912. ) ?: $xml
  89913. );
  89914. break;
  89915. case XML_UTIL_COLLAPSE_NONE:
  89916. // fall thru
  89917. default:
  89918. return $xml;
  89919. }
  89920. }
  89921. /**
  89922. * Create a tag
  89923. *
  89924. * This method will call XML_Util::createTagFromArray(), which
  89925. * is more flexible.
  89926. *
  89927. * <code>
  89928. * require_once 'XML/Util.php';
  89929. *
  89930. * // create an XML tag:
  89931. * $tag = XML_Util::createTag('myNs:myTag',
  89932. * array('foo' => 'bar'),
  89933. * 'This is inside the tag',
  89934. * 'http://www.w3c.org/myNs#');
  89935. * </code>
  89936. *
  89937. * @param string $qname qualified tagname (including namespace)
  89938. * @param array $attributes array containg attributes
  89939. * @param mixed $content the content
  89940. * @param string $namespaceUri URI of the namespace
  89941. * @param int $replaceEntities whether to replace XML special chars in
  89942. * content, embedd it in a CData section
  89943. * or none of both
  89944. * @param bool $multiline whether to create a multiline tag where
  89945. * each attribute gets written to a single line
  89946. * @param string $indent string used to indent attributes
  89947. * (_auto indents attributes so they start
  89948. * at the same column)
  89949. * @param string $linebreak string used for linebreaks
  89950. * @param bool $sortAttributes Whether to sort the attributes or not
  89951. * @param int $collapseTagMode How to handle a content-less, and thus collapseable, tag
  89952. *
  89953. * @return string XML tag
  89954. * @see createTagFromArray()
  89955. * @uses createTagFromArray() to create the tag
  89956. */
  89957. public static function createTag(
  89958. $qname, $attributes = array(), $content = null,
  89959. $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
  89960. $multiline = false, $indent = '_auto', $linebreak = "\n",
  89961. $sortAttributes = true, $collapseTagMode = XML_UTIL_COLLAPSE_ALL
  89962. ) {
  89963. $tag = array(
  89964. 'qname' => $qname,
  89965. 'attributes' => $attributes
  89966. );
  89967. // add tag content
  89968. if ($content !== null) {
  89969. $tag['content'] = $content;
  89970. }
  89971. // add namespace Uri
  89972. if ($namespaceUri !== null) {
  89973. $tag['namespaceUri'] = $namespaceUri;
  89974. }
  89975. return XML_Util::createTagFromArray(
  89976. $tag, $replaceEntities, $multiline,
  89977. $indent, $linebreak, $sortAttributes,
  89978. $collapseTagMode
  89979. );
  89980. }
  89981. /**
  89982. * Create a tag from an array.
  89983. * This method awaits an array in the following format
  89984. * <pre>
  89985. * array(
  89986. * // qualified name of the tag
  89987. * 'qname' => $qname
  89988. *
  89989. * // namespace prefix (optional, if qname is specified or no namespace)
  89990. * 'namespace' => $namespace
  89991. *
  89992. * // local part of the tagname (optional, if qname is specified)
  89993. * 'localpart' => $localpart,
  89994. *
  89995. * // array containing all attributes (optional)
  89996. * 'attributes' => array(),
  89997. *
  89998. * // tag content (optional)
  89999. * 'content' => $content,
  90000. *
  90001. * // namespaceUri for the given namespace (optional)
  90002. * 'namespaceUri' => $namespaceUri
  90003. * )
  90004. * </pre>
  90005. *
  90006. * <code>
  90007. * require_once 'XML/Util.php';
  90008. *
  90009. * $tag = array(
  90010. * 'qname' => 'foo:bar',
  90011. * 'namespaceUri' => 'http://foo.com',
  90012. * 'attributes' => array('key' => 'value', 'argh' => 'fruit&vegetable'),
  90013. * 'content' => 'I\'m inside the tag',
  90014. * );
  90015. * // creating a tag with qualified name and namespaceUri
  90016. * $string = XML_Util::createTagFromArray($tag);
  90017. * </code>
  90018. *
  90019. * @param array $tag tag definition
  90020. * @param int $replaceEntities whether to replace XML special chars in
  90021. * content, embedd it in a CData section
  90022. * or none of both
  90023. * @param bool $multiline whether to create a multiline tag where each
  90024. * attribute gets written to a single line
  90025. * @param string $indent string used to indent attributes
  90026. * (_auto indents attributes so they start
  90027. * at the same column)
  90028. * @param string $linebreak string used for linebreaks
  90029. * @param bool $sortAttributes Whether to sort the attributes or not
  90030. * @param int $collapseTagMode How to handle a content-less, and thus collapseable, tag
  90031. *
  90032. * @return string XML tag
  90033. *
  90034. * @see createTag()
  90035. * @uses attributesToString() to serialize the attributes of the tag
  90036. * @uses splitQualifiedName() to get local part and namespace of a qualified name
  90037. * @uses createCDataSection()
  90038. * @uses collapseEmptyTags()
  90039. * @uses raiseError()
  90040. */
  90041. public static function createTagFromArray(
  90042. $tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
  90043. $multiline = false, $indent = '_auto', $linebreak = "\n",
  90044. $sortAttributes = true, $collapseTagMode = XML_UTIL_COLLAPSE_ALL
  90045. ) {
  90046. if (isset($tag['content']) && !is_scalar($tag['content'])) {
  90047. return XML_Util::raiseError(
  90048. 'Supplied non-scalar value as tag content',
  90049. XML_UTIL_ERROR_NON_SCALAR_CONTENT
  90050. );
  90051. }
  90052. if (!isset($tag['qname']) && !isset($tag['localPart'])) {
  90053. return XML_Util::raiseError(
  90054. 'You must either supply a qualified name '
  90055. . '(qname) or local tag name (localPart).',
  90056. XML_UTIL_ERROR_NO_TAG_NAME
  90057. );
  90058. }
  90059. // if no attributes hav been set, use empty attributes
  90060. if (!isset($tag['attributes']) || !is_array($tag['attributes'])) {
  90061. $tag['attributes'] = array();
  90062. }
  90063. if (isset($tag['namespaces'])) {
  90064. foreach ($tag['namespaces'] as $ns => $uri) {
  90065. $tag['attributes']['xmlns:' . $ns] = $uri;
  90066. }
  90067. }
  90068. if (!isset($tag['qname'])) {
  90069. // qualified name is not given
  90070. // check for namespace
  90071. if (isset($tag['namespace']) && !empty($tag['namespace'])) {
  90072. $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart'];
  90073. } else {
  90074. $tag['qname'] = $tag['localPart'];
  90075. }
  90076. } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) {
  90077. // namespace URI is set, but no namespace
  90078. $parts = XML_Util::splitQualifiedName($tag['qname']);
  90079. $tag['localPart'] = $parts['localPart'];
  90080. if (isset($parts['namespace'])) {
  90081. $tag['namespace'] = $parts['namespace'];
  90082. }
  90083. }
  90084. if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) {
  90085. // is a namespace given
  90086. if (isset($tag['namespace']) && !empty($tag['namespace'])) {
  90087. $tag['attributes']['xmlns:' . $tag['namespace']]
  90088. = $tag['namespaceUri'];
  90089. } else {
  90090. // define this Uri as the default namespace
  90091. $tag['attributes']['xmlns'] = $tag['namespaceUri'];
  90092. }
  90093. }
  90094. if (!array_key_exists('content', $tag)) {
  90095. $tag['content'] = '';
  90096. }
  90097. // check for multiline attributes
  90098. if ($multiline === true) {
  90099. if ($indent === '_auto') {
  90100. $indent = str_repeat(' ', (strlen($tag['qname'])+2));
  90101. }
  90102. }
  90103. // create attribute list
  90104. $attList = XML_Util::attributesToString(
  90105. $tag['attributes'],
  90106. $sortAttributes, $multiline, $indent, $linebreak
  90107. );
  90108. switch ($replaceEntities) {
  90109. case XML_UTIL_ENTITIES_NONE:
  90110. break;
  90111. case XML_UTIL_CDATA_SECTION:
  90112. $tag['content'] = XML_Util::createCDataSection($tag['content']);
  90113. break;
  90114. default:
  90115. $tag['content'] = XML_Util::replaceEntities(
  90116. $tag['content'], $replaceEntities
  90117. );
  90118. break;
  90119. }
  90120. $tag = sprintf(
  90121. '<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'],
  90122. $tag['qname']
  90123. );
  90124. return self::collapseEmptyTags($tag, $collapseTagMode);
  90125. }
  90126. /**
  90127. * Create a start element
  90128. *
  90129. * <code>
  90130. * require_once 'XML/Util.php';
  90131. *
  90132. * // create an XML start element:
  90133. * $tag = XML_Util::createStartElement('myNs:myTag',
  90134. * array('foo' => 'bar') ,'http://www.w3c.org/myNs#');
  90135. * </code>
  90136. *
  90137. * @param string $qname qualified tagname (including namespace)
  90138. * @param array $attributes array containg attributes
  90139. * @param string $namespaceUri URI of the namespace
  90140. * @param bool $multiline whether to create a multiline tag where each
  90141. * attribute gets written to a single line
  90142. * @param string $indent string used to indent attributes (_auto indents
  90143. * attributes so they start at the same column)
  90144. * @param string $linebreak string used for linebreaks
  90145. * @param bool $sortAttributes Whether to sort the attributes or not
  90146. *
  90147. * @return string XML start element
  90148. * @see createEndElement(), createTag()
  90149. */
  90150. public static function createStartElement(
  90151. $qname, $attributes = array(), $namespaceUri = null,
  90152. $multiline = false, $indent = '_auto', $linebreak = "\n",
  90153. $sortAttributes = true
  90154. ) {
  90155. // if no attributes hav been set, use empty attributes
  90156. if (!isset($attributes) || !is_array($attributes)) {
  90157. $attributes = array();
  90158. }
  90159. if ($namespaceUri != null) {
  90160. $parts = XML_Util::splitQualifiedName($qname);
  90161. }
  90162. // check for multiline attributes
  90163. if ($multiline === true) {
  90164. if ($indent === '_auto') {
  90165. $indent = str_repeat(' ', (strlen($qname)+2));
  90166. }
  90167. }
  90168. if ($namespaceUri != null) {
  90169. // is a namespace given
  90170. if (isset($parts['namespace']) && !empty($parts['namespace'])) {
  90171. $attributes['xmlns:' . $parts['namespace']] = $namespaceUri;
  90172. } else {
  90173. // define this Uri as the default namespace
  90174. $attributes['xmlns'] = $namespaceUri;
  90175. }
  90176. }
  90177. // create attribute list
  90178. $attList = XML_Util::attributesToString(
  90179. $attributes, $sortAttributes,
  90180. $multiline, $indent, $linebreak
  90181. );
  90182. $element = sprintf('<%s%s>', $qname, $attList);
  90183. return $element;
  90184. }
  90185. /**
  90186. * Create an end element
  90187. *
  90188. * <code>
  90189. * require_once 'XML/Util.php';
  90190. *
  90191. * // create an XML start element:
  90192. * $tag = XML_Util::createEndElement('myNs:myTag');
  90193. * </code>
  90194. *
  90195. * @param string $qname qualified tagname (including namespace)
  90196. *
  90197. * @return string XML end element
  90198. * @see createStartElement(), createTag()
  90199. */
  90200. public static function createEndElement($qname)
  90201. {
  90202. $element = sprintf('</%s>', $qname);
  90203. return $element;
  90204. }
  90205. /**
  90206. * Create an XML comment
  90207. *
  90208. * <code>
  90209. * require_once 'XML/Util.php';
  90210. *
  90211. * // create an XML start element:
  90212. * $tag = XML_Util::createComment('I am a comment');
  90213. * </code>
  90214. *
  90215. * @param string $content content of the comment
  90216. *
  90217. * @return string XML comment
  90218. */
  90219. public static function createComment($content)
  90220. {
  90221. $comment = sprintf('<!-- %s -->', $content);
  90222. return $comment;
  90223. }
  90224. /**
  90225. * Create a CData section
  90226. *
  90227. * <code>
  90228. * require_once 'XML/Util.php';
  90229. *
  90230. * // create a CData section
  90231. * $tag = XML_Util::createCDataSection('I am content.');
  90232. * </code>
  90233. *
  90234. * @param string $data data of the CData section
  90235. *
  90236. * @return string CData section with content
  90237. */
  90238. public static function createCDataSection($data)
  90239. {
  90240. return sprintf(
  90241. '<![CDATA[%s]]>',
  90242. preg_replace('/\]\]>/', ']]]]><![CDATA[>', strval($data))
  90243. );
  90244. }
  90245. /**
  90246. * Split qualified name and return namespace and local part
  90247. *
  90248. * <code>
  90249. * require_once 'XML/Util.php';
  90250. *
  90251. * // split qualified tag
  90252. * $parts = XML_Util::splitQualifiedName('xslt:stylesheet');
  90253. * </code>
  90254. * the returned array will contain two elements:
  90255. * <pre>
  90256. * array(
  90257. * 'namespace' => 'xslt',
  90258. * 'localPart' => 'stylesheet'
  90259. * );
  90260. * </pre>
  90261. *
  90262. * @param string $qname qualified tag name
  90263. * @param string $defaultNs default namespace (optional)
  90264. *
  90265. * @return array array containing namespace and local part
  90266. */
  90267. public static function splitQualifiedName($qname, $defaultNs = null)
  90268. {
  90269. if (strstr($qname, ':')) {
  90270. $tmp = explode(':', $qname);
  90271. return array(
  90272. 'namespace' => $tmp[0],
  90273. 'localPart' => $tmp[1]
  90274. );
  90275. }
  90276. return array(
  90277. 'namespace' => $defaultNs,
  90278. 'localPart' => $qname
  90279. );
  90280. }
  90281. /**
  90282. * Check, whether string is valid XML name
  90283. *
  90284. * <p>XML names are used for tagname, attribute names and various
  90285. * other, lesser known entities.</p>
  90286. * <p>An XML name may only consist of alphanumeric characters,
  90287. * dashes, undescores and periods, and has to start with a letter
  90288. * or an underscore.</p>
  90289. *
  90290. * <code>
  90291. * require_once 'XML/Util.php';
  90292. *
  90293. * // verify tag name
  90294. * $result = XML_Util::isValidName('invalidTag?');
  90295. * if (is_a($result, 'PEAR_Error')) {
  90296. * print 'Invalid XML name: ' . $result->getMessage();
  90297. * }
  90298. * </code>
  90299. *
  90300. * @param string $string string that should be checked
  90301. *
  90302. * @return mixed true, if string is a valid XML name, PEAR error otherwise
  90303. *
  90304. * @todo support for other charsets
  90305. * @todo PEAR CS - unable to avoid 85-char limit on second preg_match
  90306. */
  90307. public static function isValidName($string)
  90308. {
  90309. // check for invalid chars
  90310. if (!preg_match('/^[[:alpha:]_]\\z/', $string{0})) {
  90311. return XML_Util::raiseError(
  90312. 'XML names may only start with letter or underscore',
  90313. XML_UTIL_ERROR_INVALID_START
  90314. );
  90315. }
  90316. // check for invalid chars
  90317. $match = preg_match(
  90318. '/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?'
  90319. . '[[:alpha:]_]([[:alnum:]\_\-\.]+)?\\z/',
  90320. $string
  90321. );
  90322. if (!$match) {
  90323. return XML_Util::raiseError(
  90324. 'XML names may only contain alphanumeric '
  90325. . 'chars, period, hyphen, colon and underscores',
  90326. XML_UTIL_ERROR_INVALID_CHARS
  90327. );
  90328. }
  90329. // XML name is valid
  90330. return true;
  90331. }
  90332. /**
  90333. * Replacement for XML_Util::raiseError
  90334. *
  90335. * Avoids the necessity to always require
  90336. * PEAR.php
  90337. *
  90338. * @param string $msg error message
  90339. * @param int $code error code
  90340. *
  90341. * @return PEAR_Error
  90342. * @todo PEAR CS - should this use include_once instead?
  90343. */
  90344. public static function raiseError($msg, $code)
  90345. {
  90346. include_once 'phar://go-pear.phar/' . 'PEAR.php';
  90347. return PEAR::raiseError($msg, $code);
  90348. }
  90349. }
  90350. ?>
  90351. o§óñ)ηÞ4‰GF©Tñç���GBMB