iCalcreator.class.php 282 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473
  1. <?php
  2. /*********************************************************************************/
  3. /**
  4. * iCalcreator class v2.6
  5. * copyright (c) 2007-2008 Kjell-Inge Gustafsson kigkonsult
  6. * www.kigkonsult.se/iCalcreator/index.php
  7. * ical@kigkonsult.se
  8. *
  9. * Description:
  10. * This file is a PHP implementation of RFC 2445.
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. */
  26. /*********************************************************************************/
  27. /*********************************************************************************/
  28. /* A little setup */
  29. /*********************************************************************************/
  30. /* your local language code */
  31. // define( 'ICAL_LANG', 'sv' );
  32. // alt. autosetting
  33. /*
  34. $langstr = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
  35. $pos = strpos( $langstr, ';' );
  36. if ($pos !== false) {
  37. $langstr = substr( $langstr, 0, $pos );
  38. $pos = strpos( $langstr, ',' );
  39. if ($pos !== false) {
  40. $pos = strpos( $langstr, ',' );
  41. $langstr = substr( $langstr, 0, $pos );
  42. }
  43. define( 'ICAL_LANG', $langstr );
  44. }
  45. */
  46. /* only for phpversion 5.x, date management, default timezone setting */
  47. if( substr( phpversion(), 0, 1) >= '5' ) // && ( 'UTC' == date_default_timezone_get() )) {
  48. date_default_timezone_set( 'Europe/Stockholm' );
  49. /* version string, do NOT remove!! */
  50. define( 'ICALCREATOR_VERSION', 'iCalcreator 2.6' );
  51. /*********************************************************************************/
  52. /*********************************************************************************/
  53. /**
  54. * vcalendar class
  55. *
  56. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  57. * @since 2.2.13 - 2007-12-30
  58. */
  59. class vcalendar {
  60. // calendar property variables
  61. var $calscale;
  62. var $method;
  63. var $prodid;
  64. var $version;
  65. var $xprop;
  66. // container for calendar components
  67. var $components;
  68. // component config variables
  69. var $allowEmpty;
  70. var $unique_id;
  71. var $language;
  72. var $directory;
  73. var $filename;
  74. var $url;
  75. var $delimiter;
  76. var $nl;
  77. var $format;
  78. // component internal variables
  79. var $attributeDelimiter;
  80. var $valueInit;
  81. // component xCal declaration container
  82. var $xcaldecl;
  83. /*
  84. * constructor for calendar object
  85. *
  86. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  87. * @since 2.2.13 - 2007-12-30
  88. * @return void
  89. */
  90. function vcalendar () {
  91. $this->_makeVersion();
  92. $this->calscale = null;
  93. $this->method = null;
  94. $this->_makeUnique_id();
  95. $this->prodid = null;
  96. $this->xprop = array();
  97. /**
  98. * language = <Text identifying a language, as defined in [RFC 1766]>
  99. */
  100. if( defined( 'ICAL_LANG' ))
  101. $this->setConfig( 'language', ICAL_LANG );
  102. $this->setConfig( 'allowEmpty', TRUE );
  103. $this->setConfig( 'nl', "\n" );
  104. $this->setConfig( 'format', 'iCal');
  105. $this->directory = null;
  106. $this->filename = null;
  107. $this->url = null;
  108. $this->setConfig( 'delimiter', DIRECTORY_SEPARATOR );
  109. $this->xcaldecl = array();
  110. $this->components = array();
  111. }
  112. /*********************************************************************************/
  113. /**
  114. * Property Name: CALSCALE
  115. */
  116. /**
  117. * creates formatted output for calendar property calscale
  118. *
  119. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  120. * @since 2.4.8 - 2008-10-21
  121. * @return string
  122. */
  123. function createCalscale() {
  124. if( empty( $this->calscale )) return FALSE;
  125. switch( $this->format ) {
  126. case 'xcal':
  127. return ' calscale="'.$this->calscale.'"'.$this->nl;
  128. break;
  129. default:
  130. return 'CALSCALE:'.$this->calscale.$this->nl;
  131. break;
  132. }
  133. }
  134. /**
  135. * set calendar property calscale
  136. *
  137. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  138. * @since 2.4.8 - 2008-10-21
  139. * @param string $value
  140. * @return void
  141. */
  142. function setCalscale( $value ) {
  143. if( empty( $value )) return FALSE;
  144. $this->calscale = $value;
  145. }
  146. /*********************************************************************************/
  147. /**
  148. * Property Name: METHOD
  149. */
  150. /**
  151. * creates formatted output for calendar property method
  152. *
  153. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  154. * @since 0.9.7 - 2006-11-20
  155. * @return string
  156. */
  157. function createMethod() {
  158. if( empty( $this->method )) return FALSE;
  159. switch( $this->format ) {
  160. case 'xcal':
  161. return ' method="'.$this->method.'"'.$this->nl;
  162. break;
  163. default:
  164. return 'METHOD:'.$this->method.$this->nl;
  165. break;
  166. }
  167. }
  168. /**
  169. * set calendar property method
  170. *
  171. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  172. * @since 2.4.8 - 2008-20-23
  173. * @param string $value
  174. * @return bool
  175. */
  176. function setMethod( $value ) {
  177. if( empty( $value )) return FALSE;
  178. $this->method = $value;
  179. return TRUE;
  180. }
  181. /*********************************************************************************/
  182. /**
  183. * Property Name: PRODID
  184. *
  185. * The identifier is RECOMMENDED to be the identical syntax to the
  186. * [RFC 822] addr-spec. A good method to assure uniqueness is to put the
  187. * domain name or a domain literal IP address of the host on which.. .
  188. */
  189. /**
  190. * creates formatted output for calendar property prodid
  191. *
  192. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  193. * @since 0.9.7 - 2006-11-20
  194. * @return string
  195. */
  196. function createProdid() {
  197. if( !isset( $this->prodid ))
  198. $this->_makeProdid();
  199. switch( $this->format ) {
  200. case 'xcal':
  201. return ' prodid="'.$this->prodid.'"'.$this->nl;
  202. break;
  203. default:
  204. return 'PRODID:'.$this->prodid.$this->nl;
  205. break;
  206. }
  207. }
  208. /**
  209. * make default value for calendar prodid
  210. *
  211. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  212. * @since 0.3.0 - 2006-08-10
  213. * @return void
  214. */
  215. function _makeProdid() {
  216. $this->prodid = '-//'.$this->unique_id.'//NONSGML '.ICALCREATOR_VERSION.'//'.strtoupper( $this->language );
  217. }
  218. /**
  219. * Conformance: The property MUST be specified once in an iCalendar object.
  220. * Description: The vendor of the implementation SHOULD assure that this
  221. * is a globally unique identifier; using some technique such as an FPI
  222. * value, as defined in [ISO 9070].
  223. */
  224. /**
  225. * make default unique_id for calendar prodid
  226. *
  227. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  228. * @since 0.3.0 - 2006-08-10
  229. * @return void
  230. */
  231. function _makeUnique_id() {
  232. $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
  233. }
  234. /*********************************************************************************/
  235. /**
  236. * Property Name: VERSION
  237. *
  238. * Description: A value of "2.0" corresponds to this memo.
  239. */
  240. /**
  241. * creates formatted output for calendar property version
  242. *
  243. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  244. * @since 0.9.7 - 2006-11-20
  245. * @return string
  246. */
  247. function createVersion() {
  248. if( empty( $this->version ))
  249. $this->_makeVersion();
  250. switch( $this->format ) {
  251. case 'xcal':
  252. return ' version="'.$this->version.'"'.$this->nl;
  253. break;
  254. default:
  255. return 'VERSION:'.$this->version.$this->nl;
  256. break;
  257. }
  258. }
  259. /**
  260. * set default calendar version
  261. *
  262. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  263. * @since 0.3.0 - 2006-08-10
  264. * @return void
  265. */
  266. function _makeVersion() {
  267. $this->version = '2.0';
  268. }
  269. /**
  270. * set calendar version
  271. *
  272. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  273. * @since 2.4.8 - 2008-10-23
  274. * @param string $value
  275. * @return void
  276. */
  277. function setVersion( $value ) {
  278. if( empty( $value )) return FALSE;
  279. $this->version = $value;
  280. return TRUE;
  281. }
  282. /*********************************************************************************/
  283. /**
  284. * Property Name: x-prop
  285. */
  286. /**
  287. * creates formatted output for calendar property x-prop, iCal format only
  288. *
  289. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  290. * @since 2.4.11 - 2008-11-03
  291. * @return string
  292. */
  293. function createXprop() {
  294. if( 'xcal' == $this->format )
  295. return false;
  296. if( 0 >= count( $this->xprop ))
  297. return;
  298. $output = null;
  299. $toolbox = new calendarComponent();
  300. $toolbox->setConfig( 'language', $this->getConfig( 'language' ));
  301. $toolbox->setConfig( 'nl', $this->getConfig( 'nl' ));
  302. $toolbox->_createFormat( $this->getConfig( 'format' ));
  303. foreach( $this->xprop as $label => $xpropPart ) {
  304. if( empty( $xpropPart['value'] )) {
  305. $output .= $toolbox->_createElement( $label );
  306. continue;
  307. }
  308. $attributes = $toolbox->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
  309. if( is_array( $xpropPart['value'] )) {
  310. foreach( $xpropPart['value'] as $pix => $theXpart )
  311. $xpropPart['value'][$pix] = $toolbox->_strrep( $theXpart );
  312. $xpropPart['value'] = implode( ',', $xpropPart['value'] );
  313. }
  314. else
  315. $xpropPart['value'] = $toolbox->_strrep( $xpropPart['value'] );
  316. $output .= $toolbox->_createElement( $label, $attributes, $xpropPart['value'] );
  317. }
  318. return $output;
  319. }
  320. /**
  321. * set calendar property x-prop
  322. *
  323. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  324. * @since 2.4.11 - 2008-11-04
  325. * @param string $label
  326. * @param string $value
  327. * @param array $params optional
  328. * @return bool
  329. */
  330. function setXprop( $label, $value, $params=FALSE ) {
  331. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  332. if( empty( $label )) return FALSE;
  333. $xprop = array( 'value' => $value );
  334. $toolbox = new calendarComponent();
  335. $xprop['params'] = $toolbox->_setParams( $params );
  336. if( !is_array( $this->xprop )) $this->xprop = array();
  337. $this->xprop[strtoupper( $label )] = $xprop;
  338. return TRUE;
  339. }
  340. /*********************************************************************************/
  341. /**
  342. * delete calendar property value
  343. *
  344. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  345. * @since 2.4.5 - 2008-11-14
  346. * @param mixed $propName, bool FALSE => X-property
  347. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  348. * @return bool, if successfull delete
  349. */
  350. function deleteProperty( $propName, $propix=FALSE ) {
  351. $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
  352. if( !$propix )
  353. $propix = ( isset( $this->propdelix[$propName] )) ? $this->propdelix[$propName] + 2 : 1;
  354. $this->propdelix[$propName] = --$propix;
  355. $return = FALSE;
  356. switch( $propName ) {
  357. case 'CALSCALE':
  358. if( isset( $this->calscale )) {
  359. $this->calscale = null;
  360. $return = TRUE;
  361. }
  362. break;
  363. case 'METHOD':
  364. if( isset( $this->method )) {
  365. $this->method = null;
  366. $return = TRUE;
  367. }
  368. break;
  369. default:
  370. $reduced = array();
  371. if( $propName != 'X-PROP' ) {
  372. if( !isset( $this->xprop[$propName] )) return FALSE;
  373. foreach( $this->xprop as $k => $a ) {
  374. if(( $k != $propName ) && !empty( $a ))
  375. $reduced[$k] = $a;
  376. }
  377. }
  378. else {
  379. if( count( $this->xprop ) <= $propix ) return FALSE;
  380. $xpropno = 0;
  381. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  382. if( $propix != $xpropno )
  383. $reduced[$xpropkey] = $xpropvalue;
  384. $xpropno++;
  385. }
  386. }
  387. $this->xprop = $reduced;
  388. return TRUE;
  389. }
  390. return $return;
  391. }
  392. /**
  393. * get calendar property value/params
  394. *
  395. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  396. * @since 2.5.1 - 2008-11-02
  397. * @param string $propName, optional
  398. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  399. * @param bool $inclParam=FALSE
  400. * @return mixed
  401. */
  402. function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) {
  403. $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
  404. if( 'X-PROP' == $propName ) {
  405. if( !$propix )
  406. $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
  407. $this->propix[$propName] = --$propix;
  408. }
  409. switch( $propName ) {
  410. case 'CALSCALE':
  411. return ( !empty( $this->calscale )) ? $this->calscale : null;
  412. break;
  413. case 'METHOD':
  414. return ( !empty( $this->method )) ? $this->method : null;
  415. break;
  416. case 'PRODID':
  417. if( empty( $this->prodid ))
  418. $this->_makeProdid();
  419. return $this->prodid;
  420. break;
  421. case 'VERSION':
  422. return ( !empty( $this->version )) ? $this->version : null;
  423. break;
  424. default:
  425. if( $propName != 'X-PROP' ) {
  426. if( !isset( $this->xprop[$propName] )) return FALSE;
  427. return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
  428. : array( $propName, $this->xprop[$propName]['value'] );
  429. }
  430. else {
  431. if( empty( $this->xprop )) return FALSE;
  432. $xpropno = 0;
  433. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  434. if( $propix == $xpropno )
  435. return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
  436. : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
  437. else
  438. $xpropno++;
  439. }
  440. return FALSE; // not found ??
  441. }
  442. }
  443. return FALSE;
  444. }
  445. /**
  446. * general vcalendar property setting
  447. *
  448. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  449. * @since 2.2.13 - 2007-11-04
  450. * @param mixed $args variable number of function arguments,
  451. * first argument is ALWAYS component name,
  452. * second ALWAYS component value!
  453. * @return bool
  454. */
  455. function setProperty () {
  456. $numargs = func_num_args();
  457. if( 1 > $numargs )
  458. return FALSE;
  459. $arglist = func_get_args();
  460. $arglist[0] = strtoupper( $arglist[0] );
  461. switch( $arglist[0] ) {
  462. case 'CALSCALE':
  463. return $this->setCalscale( $arglist[1] );
  464. case 'METHOD':
  465. return $this->setMethod( $arglist[1] );
  466. case 'VERSION':
  467. return $this->setVersion( $arglist[1] );
  468. default:
  469. if( !isset( $arglist[1] )) $arglist[1] = null;
  470. if( !isset( $arglist[2] )) $arglist[2] = null;
  471. return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
  472. }
  473. return FALSE;
  474. }
  475. /*********************************************************************************/
  476. /**
  477. * get vcalendar config values or * calendar components
  478. *
  479. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  480. * @since 2.4.10 - 2008-10-23
  481. * @param string $config
  482. * @return value
  483. */
  484. function getConfig( $config ) {
  485. switch( strtoupper( $config )) {
  486. case 'ALLOWEMPTY':
  487. return $this->allowEmpty;
  488. break;
  489. case 'COMPSINFO':
  490. unset( $this->compix );
  491. $info = array();
  492. foreach( $this->components as $cix => $component ) {
  493. if( empty( $component )) continue;
  494. unset( $component->propix );
  495. $info[$cix]['ordno'] = $cix + 1;
  496. $info[$cix]['type'] = $component->objName;
  497. $info[$cix]['uid'] = $component->getProperty( 'uid' );
  498. $info[$cix]['props'] = $component->getConfig( 'propinfo' );
  499. $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
  500. unset( $component->propix );
  501. }
  502. return $info;
  503. break;
  504. case 'DELIMITER':
  505. return $this->delimiter;
  506. break;
  507. case 'DIRECTORY':
  508. if( empty( $this->directory ))
  509. $this->directory = '.';
  510. return $this->directory;
  511. break;
  512. case 'DIRFILE':
  513. return $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$this->getConfig( 'filename' );
  514. break;
  515. case 'FILEINFO':
  516. return array( $this->getConfig( 'directory' )
  517. , $this->getConfig( 'filename' )
  518. , $this->getConfig( 'filesize' ));
  519. break;
  520. case 'FILENAME':
  521. if( empty( $this->filename )) {
  522. if( 'xcal' == $this->format )
  523. $this->filename = date( 'YmdHis' ).'.xml'; // recommended xcs.. .
  524. else
  525. $this->filename = date( 'YmdHis' ).'.ics';
  526. }
  527. return $this->filename;
  528. break;
  529. case 'FILESIZE':
  530. $size = 0;
  531. if( empty( $this->url )) {
  532. $dirfile = $this->getConfig( 'dirfile' );
  533. if( FALSE === ( $size = filesize( $dirfile )))
  534. $size = 0;
  535. clearstatcache();
  536. }
  537. return $size;
  538. break;
  539. case 'FORMAT':
  540. return $this->format;
  541. break;
  542. case 'LANGUAGE':
  543. /* get language for calendar component as defined in [RFC 1766] */
  544. return $this->language;
  545. break;
  546. case 'NL':
  547. case 'NEWLINECHAR':
  548. return $this->nl;
  549. break;
  550. case 'UNIQUE_ID':
  551. return $this->unique_id;
  552. break;
  553. case 'URL':
  554. if( !empty( $this->url ))
  555. return $this->url;
  556. else
  557. return FALSE;
  558. break;
  559. }
  560. }
  561. /**
  562. * general vcalendar config setting
  563. *
  564. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  565. * @since 2.4.8 - 2008-10-24
  566. * @param string $config
  567. * @param string $value
  568. * @return void
  569. */
  570. function setConfig( $config, $value ) {
  571. $res = FALSE;
  572. switch( strtoupper( $config )) {
  573. case 'ALLOWEMPTY':
  574. $this->allowEmpty = $value;
  575. $subcfg = array( 'ALLOWEMPTY' => $value );
  576. $res = TRUE;
  577. break;
  578. case 'DELIMITER':
  579. $this->delimiter = $value;
  580. return TRUE;
  581. break;
  582. case 'DIRECTORY':
  583. $value = trim( $value );
  584. $nl = $this->getConfig('delimiter');
  585. if( $nl == substr( $value, ( 0 - strlen( $nl ))))
  586. $value = substr( $value, 0, ( strlen( $value ) - strlen( $nl )));
  587. if( is_dir( $value )) {
  588. /* local directory */
  589. clearstatcache();
  590. $this->directory = $value;
  591. $this->url = null;
  592. return TRUE;
  593. }
  594. else
  595. return FALSE;
  596. break;
  597. case 'FILENAME':
  598. $value = trim( $value );
  599. if( !empty( $this->url )) {
  600. /* remote directory+file - URL */
  601. $this->filename = $value;
  602. return TRUE;
  603. }
  604. $dirfile = $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$value;
  605. if( file_exists( $dirfile )) {
  606. /* local existing file */
  607. if( is_readable( $dirfile ) || is_writable( $dirfile )) {
  608. clearstatcache();
  609. $this->filename = $value;
  610. return TRUE;
  611. }
  612. else
  613. return FALSE;
  614. }
  615. elseif( FALSE !== touch( $dirfile )) {
  616. /* new local file created */
  617. $this->filename = $value;
  618. return TRUE;
  619. }
  620. else
  621. return FALSE;
  622. break;
  623. case 'FORMAT':
  624. $value = trim( $value );
  625. if( 'xcal' == strtolower( $value )) {
  626. $this->format = 'xcal';
  627. $this->attributeDelimiter = $this->nl;
  628. $this->valueInit = null;
  629. }
  630. else {
  631. $this->format = null;
  632. $this->attributeDelimiter = ';';
  633. $this->valueInit = ':';
  634. }
  635. $subcfg = array( 'FORMAT' => $value );
  636. $res = TRUE;
  637. break;
  638. case 'LANGUAGE':
  639. // set language for calendar component as defined in [RFC 1766]
  640. $value = trim( $value );
  641. $this->language = $value;
  642. $subcfg = array( 'LANGUAGE' => $value );
  643. $res = TRUE;
  644. break;
  645. case 'NL':
  646. case 'NEWLINECHAR':
  647. $this->nl = $value;
  648. $subcfg = array( 'NL' => $value );
  649. $res = TRUE;
  650. break;
  651. case 'UNIQUE_ID':
  652. $value = trim( $value );
  653. $this->unique_id = $value;
  654. $subcfg = array( 'UNIQUE_ID' => $value );
  655. $res = TRUE;
  656. break;
  657. case 'URL':
  658. /* remote file - URL */
  659. $value = trim( $value );
  660. $value = str_replace( 'HTTP://', 'http://', $value );
  661. $value = str_replace( 'WEBCAL://', 'http://', $value );
  662. $value = str_replace( 'webcal://', 'http://', $value );
  663. $this->url = $value;
  664. $this->directory = null;
  665. $parts = pathinfo( $value );
  666. return $this->setConfig( 'filename', $parts['basename'] );
  667. break;
  668. }
  669. if( !$res ) return FALSE;
  670. if( isset( $subcfg ) && !empty( $this->components )) {
  671. foreach( $subcfg as $cfgkey => $cfgvalue ) {
  672. foreach( $this->components as $cix => $component ) {
  673. $res = $component->setConfig( $cfgkey, $cfgvalue );
  674. if( !$res )
  675. break 2;
  676. $this->components[$cix] = $component->copy(); // PHP4 compliant
  677. }
  678. }
  679. }
  680. return $res;
  681. }
  682. /*********************************************************************************/
  683. /**
  684. * add calendar component to container
  685. *
  686. * alias to setComponent
  687. *
  688. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  689. * @since 1.x.x - 2007-04-24
  690. * @param object $component calendar component
  691. * @return void
  692. */
  693. function addComponent( $component ) {
  694. $this->setComponent( $component );
  695. }
  696. /**
  697. * delete calendar component from container
  698. *
  699. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  700. * @since 2.4.10 - 2008-08-05
  701. * @param mixed $arg1 ordno / component type / component uid
  702. * @param mixed $arg2 optional, ordno if arg1 = component type
  703. * @return void
  704. */
  705. function deleteComponent( $arg1, $arg2=FALSE ) {
  706. $argType = $index = null;
  707. if ( ctype_digit( (string) $arg1 )) {
  708. $argType = 'INDEX';
  709. $index = (int) $arg1 - 1;
  710. }
  711. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  712. $argType = strtolower( $arg1 );
  713. $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
  714. }
  715. $cix1dC = 0;
  716. foreach ( $this->components as $cix => $component) {
  717. if( empty( $component )) continue;
  718. unset( $component->propix );
  719. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  720. unset( $this->components[$cix] );
  721. return TRUE;
  722. }
  723. elseif( $argType == $component->objName ) {
  724. if( $index == $cix1dC ) {
  725. unset( $this->components[$cix] );
  726. return TRUE;
  727. }
  728. $cix1dC++;
  729. }
  730. elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
  731. unset( $this->components[$cix] );
  732. return TRUE;
  733. }
  734. }
  735. return FALSE;
  736. }
  737. /**
  738. * get calendar component from container
  739. *
  740. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  741. * @since 2.4.10 - 2008-08-06
  742. * @param mixed $arg1 optional, ordno/component type/ component uid
  743. * @param mixed $arg2 optional, ordno if arg1 = component type
  744. * @return object
  745. */
  746. function getComponent( $arg1=FALSE, $arg2=FALSE ) {
  747. $index = $argType = null;
  748. if ( !$arg1 ) {
  749. $argType = 'INDEX';
  750. $index = $this->compix['INDEX'] =
  751. ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
  752. }
  753. elseif ( ctype_digit( (string) $arg1 )) {
  754. $argType = 'INDEX';
  755. $index = (int) $arg1;
  756. unset( $this->compix );
  757. }
  758. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  759. unset( $this->compix['INDEX'] );
  760. $argType = strtolower( $arg1 );
  761. if( !$arg2 )
  762. $index = $this->compix[$argType] =
  763. ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
  764. else
  765. $index = (int) $arg2;
  766. }
  767. $index -= 1;
  768. $ckeys = array_keys( $this->components );
  769. if( !empty( $index) && ( $index > end( $ckeys )))
  770. return FALSE;
  771. $cix1gC = 0;
  772. foreach ( $this->components as $cix => $component) {
  773. if( empty( $component )) continue;
  774. unset( $component->propix );
  775. if(( 'INDEX' == $argType ) && ( $index == $cix ))
  776. return $component->copy();
  777. elseif( $argType == $component->objName ) {
  778. if( $index == $cix1gC )
  779. return $component->copy();
  780. $cix1gC++;
  781. }
  782. elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
  783. unset( $component->propix );
  784. return $component->copy();
  785. }
  786. }
  787. /* not found.. . */
  788. unset( $this->compix );
  789. return FALSE;
  790. }
  791. /**
  792. * select components from calendar on date basis
  793. *
  794. * Ensure DTSTART is set for every component.
  795. * No date controls occurs.
  796. *
  797. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  798. * @since 2.4.16 - 2008-10-18
  799. * @param int $startY optional, start Year, default current Year
  800. * @param int $startM optional, start Month, default current Month
  801. * @param int $startD optional, start Day, default current Day
  802. * @param int $endY optional, end Year, default $startY
  803. * @param int $endY optional, end Month, default $startM
  804. * @param int $endY optional, end Day, default $startD
  805. * @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s)
  806. * @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][]
  807. * TRUE => output : array[] (ignores split)
  808. * @param bool $any optional, TRUE (default) - select component that take place within period
  809. * FALSE - only components that starts within period
  810. * @param bool $split optional, TRUE (default) - one component copy every day it take place during the
  811. * period (implies flat=FALSE)
  812. * FALSE - one occurance of component only in output array</tr>
  813. * @return array or FALSE
  814. */
  815. function selectComponents( $startY=FALSE, $startM=FALSE, $startD=FALSE, $endY=FALSE, $endM=FALSE, $endD=FALSE, $cType=FALSE, $flat=FALSE, $any=TRUE, $split=TRUE ) {
  816. /* check if empty calendar */
  817. if( 0 >= count( $this->components )) return FALSE;
  818. /* check default dates */
  819. if( !$startY ) $startY = date( 'Y' );
  820. if( !$startM ) $startM = date( 'm' );
  821. if( !$startD ) $startD = date( 'd' );
  822. $startDate = mktime( 0, 0, 0, $startM, $startD, $startY );
  823. if( !$endY ) $endY = $startY;
  824. if( !$endM ) $endM = $startM;
  825. if( !$endD ) $endD = $startD;
  826. $endDate = mktime( 23, 59, 59, $endM, $endD, $endY );
  827. /* check component types */
  828. $validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' );
  829. if( is_array( $cType )) {
  830. foreach( $cType as $cix => $theType ) {
  831. $cType[$cix] = $theType = strtolower( $theType );
  832. if( !in_array( $theType, $validTypes ))
  833. $cType[$cix] = 'vevent';
  834. }
  835. $cType = array_unique( $cType );
  836. }
  837. elseif( !empty( $cType )) {
  838. $cType = strtolower( $cType );
  839. if( !in_array( $cType, $validTypes ))
  840. $cType = array( 'vevent' );
  841. else
  842. $cType = array( $cType );
  843. }
  844. else
  845. $cType = $validTypes;
  846. if( 0 >= count( $cType ))
  847. $cType = $validTypes;
  848. /* iterate components */
  849. $result = array();
  850. foreach ( $this->components as $cix => $component ) {
  851. if( empty( $component )) continue;
  852. unset( $component->propix, $start );
  853. /* deselect unvalid type components */
  854. if( !in_array( $component->objName, $cType )) continue;
  855. /* deselect components without dtstart set */
  856. if( FALSE === ( $start = $component->getProperty( 'dtstart' ))) continue;
  857. $dtendExist = $dueExist = $durationExist = $endAllDayEvent = FALSE;
  858. unset( $end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $workstart, $workend ); // clean up
  859. $startWdate = $component->_date2timestamp( $start );
  860. $startDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
  861. /* get end date from dtend/due/duration properties */
  862. $end = $component->getProperty( 'dtend' );
  863. if( !empty( $end )) {
  864. $dtendExist = TRUE;
  865. $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
  866. }
  867. // if( !empty($end)) echo 'selectComp 1 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  868. if( empty($end) && ( $component->objName == 'vtodo' )) {
  869. $end = $component->getProperty( 'due' );
  870. if( !empty( $end )) {
  871. $dueExist = TRUE;
  872. $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
  873. }
  874. // if( !empty($end)) echo 'selectComp 2 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  875. }
  876. if( !empty( $end ) && !isset( $end['hour'] )) {
  877. /* a DTEND without time part regards an event that ends the day before,
  878. for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */
  879. $endAllDayEvent = TRUE;
  880. $endWdate = mktime( 23, 59, 59, $end['month'], ($end['day'] - 1), $end['year'] );
  881. $end['year'] = date( 'Y', $endWdate );
  882. $end['month'] = date( 'm', $endWdate );
  883. $end['day'] = date( 'd', $endWdate );
  884. $end['hour'] = 23;
  885. $end['min'] = $end['sec'] = 59;
  886. // if( !empty($end)) echo 'selectComp 3 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  887. }
  888. if( empty( $end )) {
  889. $end = $component->getProperty( 'duration', FALSE, FALSE, TRUE );// in dtend (array) format
  890. if( !empty( $end ))
  891. $durationExist = TRUE;
  892. // if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  893. }
  894. if( empty( $end )) { // assume one day duration if missing end date
  895. $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
  896. // if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  897. }
  898. $endWdate = $component->_date2timestamp( $end );
  899. if( $endWdate < $startWdate ) { // MUST be after start date!!
  900. $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
  901. $endWdate = $component->_date2timestamp( $end );
  902. }
  903. $rdurWsecs = $endWdate - $startWdate; // compute component duration in seconds
  904. $rdur = $component->_date2duration( $start, $end ); // compute component duration, array
  905. /* make a list of optional exclude dates for component occurence from exrule and exdate */
  906. $exdatelist = array();
  907. $workstart = $component->_timestamp2date(( $startDate - $rdurWsecs ), 6);
  908. $workend = $component->_timestamp2date(( $endDate + $rdurWsecs ), 6);
  909. while( FALSE !== ( $exrule = $component->getProperty( 'exrule' ))) // check exrule
  910. $component->_recur2date( $exdatelist, $exrule, $start, $workstart, $workend );
  911. while( FALSE !== ( $exdate = $component->getProperty( 'exdate' ))) { // check exdate
  912. foreach( $exdate as $theExdate ) {
  913. $exWdate = $component->_date2timestamp( $theExdate );
  914. if((( $startDate - $rdurWsecs ) <= $exWdate ) && ( $endDate >= $exWdate ))
  915. $exdatelist[$exWdate] = TRUE;
  916. }
  917. }
  918. /* if 'any' components, check repeating components, removing all excluding dates */
  919. if( TRUE === $any ) {
  920. /* make a list of optional repeating dates for component occurence, rrule, rdate */
  921. $recurlist = array();
  922. while( FALSE !== ( $rrule = $component->getProperty( 'rrule' ))) // check rrule
  923. $component->_recur2date( $recurlist, $rrule, $start, $workstart, $workend );
  924. foreach( $recurlist as $recurkey => $recurvalue ) // key=match date as timestamp
  925. $recurlist[$recurkey] = $rdurWsecs; // add duration in seconds
  926. while( FALSE !== ( $rdate = $component->getProperty( 'rdate' ))) { // check rdate
  927. foreach( $rdate as $theRdate ) {
  928. if( is_array( $theRdate ) && ( 2 == count( $theRdate )) && // all days within PERIOD
  929. array_key_exists( '0', $theRdate ) && array_key_exists( '1', $theRdate )) {
  930. $rstart = $component->_date2timestamp( $theRdate[0] );
  931. if(( $rstart < ( $startDate - $rdurWsecs )) || ( $rstart > $endDate ))
  932. continue;
  933. if( isset( $theRdate[1]['year'] )) // date-date period
  934. $rend = $component->_date2timestamp( $theRdate[1] );
  935. else { // date-duration period
  936. $rend = $component->duration2date( $theRdate[0], $theRdate[1] );
  937. $rend = $component->_date2timestamp( $rend );
  938. }
  939. if((( $startDate - $rdurWsecs ) <= $rstart ) && ( $endDate >= $rstart ))
  940. $recurlist[$rstart] = ( $rstart - $rend ); // set start date + rdate duration in seconds
  941. } // PERIOD end
  942. else { // single date
  943. $theRdate = $component->_date2timestamp( $theRdate );
  944. if((( $startDate - $rdurWsecs ) <= $theRdate ) && ( $endDate >= $theRdate ))
  945. $recurlist[$theRdate] = $rdurWsecs; // set start date + event duration in seconds
  946. }
  947. }
  948. }
  949. if( 0 < count( $recurlist )) {
  950. ksort( $recurlist );
  951. foreach( $recurlist as $recurkey => $durvalue ) {
  952. if((( $startDate - $rdurWsecs ) > $recurkey ) || ( $endDate < $recurkey )) // not within period
  953. continue;
  954. if( isset( $exdatelist[$recurkey] )) // check excluded dates
  955. continue;
  956. if( $startWdate >= $recurkey ) // exclude component start date
  957. continue;
  958. $component2 = $component->copy();
  959. $rstart = $component2->_timestamp2date( $recurkey, 6);
  960. $datevalue = $rstart['month'].'/'.$rstart['day'].'/'.$rstart['year'];
  961. if( isset( $start['hour'] ) || isset( $start['min'] ) || isset( $start['sec'] )) {
  962. $datevalue .= ( isset( $rstart['hour'] )) ? ' '.$rstart['hour'] : ' 00';
  963. $datevalue .= ( isset( $rstart['min'] )) ? ':'.$rstart['min'] : ':00';
  964. $datevalue .= ( isset( $rstart['sec'] )) ? ':'.$rstart['sec'] : ':00';
  965. }
  966. $datestring = date( $startDateFormat, strtotime( $datevalue ));
  967. if( isset( $start['tz'] ))
  968. $datestring .= ' '.$start['tz'];
  969. $component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
  970. $rend = $component2->_timestamp2date(( $recurkey + $durvalue ), 6);
  971. if( $dtendExist || $dueExist ) {
  972. if( $endAllDayEvent ) {
  973. $rend2 = mktime( 0, 0, 0, $rend['month'], ($rend['day'] + 1), $rend['year'] );
  974. $datevalue = date( 'm', $rend2 ).'/'.date( 'd', $rend2 ).'/'.date( 'Y', $rend2 );
  975. }
  976. else {
  977. $datevalue = $rend['month'].'/'.$rend['day'].'/'.$rend['year'];
  978. if( isset( $end['hour'] ) || isset( $end['min'] ) || isset( $end['sec'] )) {
  979. $datevalue .= ( isset( $rend['hour'] )) ? ' '.$rend['hour'] : ' 00';
  980. $datevalue .= ( isset( $rend['min'] )) ? ':'.$rend['min'] : ':00';
  981. $datevalue .= ( isset( $rend['sec'] )) ? ':'.$rend['sec'] : ':00';
  982. }
  983. }
  984. $datestring = date( $endDateFormat, strtotime( $datevalue ));
  985. if( isset( $end['tz'] ))
  986. $datestring .= ' '.$end['tz'];
  987. if( $dtendExist )
  988. $component2->setProperty( 'X-CURRENT-DTEND', $datestring );
  989. elseif( $dueExist )
  990. $component2->setProperty( 'X-CURRENT-DUE', $datestring );
  991. }
  992. $rend = $component2->_date2timestamp( $rend );
  993. $rstart = $recurkey;
  994. /* add repeating components within valid dates to output array, only start date */
  995. if( $flat )
  996. $result[] = $component2->copy(); // copy to output
  997. elseif( $split ) {
  998. if( $rend > $endDate )
  999. $rend = $endDate;
  1000. while( $rstart <= $rend ) { // iterate
  1001. $wd = getdate( $rstart );
  1002. if(( $rstart > $startDate ) && // date after dtstart
  1003. !isset( $exdatelist[$rstart] )) // check exclude date
  1004. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component2->copy(); // copy to output
  1005. $rstart += ( 24*60*60 ); // step one day
  1006. }
  1007. }
  1008. elseif(( $rstart >= $startDate ) && // date within period
  1009. !isset( $exdatelist[$rstart] )) { // check exclude date
  1010. $wd = getdate( $rstart );
  1011. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component2->copy(); // copy to output
  1012. }
  1013. }
  1014. }
  1015. /* deselect components with startdate/enddate not within period */
  1016. if(( $endWdate < $startDate ) || ( $startWdate > $endDate )) continue;
  1017. }
  1018. /* deselect components with startdate not within period */
  1019. elseif(( $startWdate < $startDate ) || ( $startWdate > $endDate )) continue;
  1020. /* add selected components within valid dates to output array */
  1021. if( $flat )
  1022. $result[] = $component->copy(); // copy to output;
  1023. elseif( $split ) {
  1024. if( $endWdate > $endDate )
  1025. $endWdate = $endDate; // use period end date
  1026. if( !isset( $exdatelist[$startWdate] )) { // check excluded dates
  1027. if( $startWdate < $startDate )
  1028. $startWdate = $startDate; // use period start date
  1029. while( $startWdate <= $endWdate ) { // iterate
  1030. $wd = getdate( $startWdate );
  1031. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component->copy(); // copy to output
  1032. $startWdate += ( 24*60*60 ); // step one day
  1033. }
  1034. }
  1035. } // use component date
  1036. elseif( !isset( $exdatelist[$startWdate] ) && // check excluded dates
  1037. ( $startWdate >= $startDate )) { // within period
  1038. $wd = getdate( $startWdate );
  1039. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component->copy(); // copy to output
  1040. }
  1041. }
  1042. if( 0 >= count( $result )) return FALSE;
  1043. elseif( !$flat ) {
  1044. foreach( $result as $y => $yeararr ) {
  1045. foreach( $yeararr as $m => $montharr ) {
  1046. ksort( $result[$y][$m] );
  1047. }
  1048. ksort( $result[$y] );
  1049. }
  1050. ksort( $result );
  1051. }
  1052. return $result;
  1053. }
  1054. /**
  1055. * add calendar component to container
  1056. *
  1057. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1058. * @since 2.4.10 - 2008-08-06
  1059. * @param object $component calendar component
  1060. * @param mixed $arg1 optional, ordno/component type/ component uid
  1061. * @param mixed $arg2 optional, ordno if arg1 = component type
  1062. * @return void
  1063. */
  1064. function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
  1065. if( '' >= $component->getConfig( 'language'))
  1066. $component->setConfig( 'language', $this->getConfig( 'language' ));
  1067. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  1068. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  1069. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  1070. $component->setConfig( 'format', $this->getConfig( 'format' ));
  1071. if( !in_array( $component->objName, array( 'valarm', 'vtimezone' ))) {
  1072. unset( $component->propix );
  1073. /* make sure dtstamp and uid is set */
  1074. $dummy1 = $component->getProperty( 'dtstamp' );
  1075. $dummy2 = $component->getProperty( 'uid' );
  1076. }
  1077. if( !$arg1 ) {
  1078. $this->components[] = $component->copy();
  1079. return TRUE;
  1080. }
  1081. $argType = $index = null;
  1082. if ( ctype_digit( (string) $arg1 )) {
  1083. $argType = 'INDEX';
  1084. $index = (int) $arg1 - 1;
  1085. }
  1086. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  1087. $argType = strtolower( $arg1 );
  1088. $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
  1089. }
  1090. $cix1sC = 0;
  1091. foreach ( $this->components as $cix => $component2) {
  1092. if( empty( $component2 )) continue;
  1093. unset( $component2->propix );
  1094. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  1095. $this->components[$cix] = $component->copy();
  1096. return TRUE;
  1097. }
  1098. elseif( $argType == $component2->objName ) {
  1099. if( $index == $cix1sC ) {
  1100. $this->components[$cix] = $component->copy();
  1101. return TRUE;
  1102. }
  1103. $cix1sC++;
  1104. }
  1105. elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) {
  1106. $this->components[$cix] = $component->copy();
  1107. return TRUE;
  1108. }
  1109. }
  1110. /* not found.. . insert last in chain anyway .. .*/
  1111. $this->components[] = $component->copy();
  1112. return TRUE;
  1113. }
  1114. /**
  1115. * sort iCal compoments, only local date sort
  1116. *
  1117. * ascending sort on properties (if exist) x-current-dtstart, dtstart,
  1118. * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid
  1119. *
  1120. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1121. * @since 2.4.10 - 2008-09-24
  1122. * @return sort param
  1123. *
  1124. */
  1125. function sort() {
  1126. if( is_array( $this->components )) {
  1127. $this->_sortkeys = array( 'year', 'month', 'day', 'hour', 'min', 'sec' );
  1128. usort( $this->components, array( $this, '_cmpfcn' ));
  1129. }
  1130. }
  1131. function _cmpfcn( $a, $b ) {
  1132. if( empty( $a )) return -1;
  1133. if( empty( $b )) return 1;
  1134. if( 'vtimezone' == $a->objName) return -1;
  1135. if( 'vtimezone' == $b->objName) return 1;
  1136. $astart = ( isset( $a->xprop['X-CURRENT-DTSTART']['value'] )) ? $a->_date_time_string( $a->xprop['X-CURRENT-DTSTART']['value'] ) : null;
  1137. if( empty( $astart ) && isset( $a->dtstart['value'] ))
  1138. $astart = & $a->dtstart['value'];
  1139. $bstart = ( isset( $b->xprop['X-CURRENT-DTSTART']['value'] )) ? $b->_date_time_string( $b->xprop['X-CURRENT-DTSTART']['value'] ) : null;
  1140. if( empty( $bstart ) && isset( $b->dtstart['value'] ))
  1141. $bstart = & $b->dtstart['value'];
  1142. if( empty( $astart )) return -1;
  1143. elseif( empty( $bstart )) return 1;
  1144. foreach( $this->_sortkeys as $key ) {
  1145. if ( empty( $astart[$key] )) return -1;
  1146. elseif( empty( $bstart[$key] )) return 1;
  1147. if ( $astart[$key] == $bstart[$key]) continue;
  1148. if (( (int) $astart[$key] ) < ((int) $bstart[$key] ))
  1149. return -1;
  1150. elseif(( (int) $astart[$key] ) > ((int) $bstart[$key] ))
  1151. return 1;
  1152. }
  1153. $c = ( isset( $a->xprop['X-CURRENT-DTEND']['value'] )) ? $a->_date_time_string( $a->xprop['X-CURRENT-DTEND']['value'] ) : null;
  1154. if( empty( $c ) && !empty( $a->dtend['value'] ))
  1155. $c = & $a->dtend['value'];
  1156. if( empty( $c ) && isset( $a->xprop['X-CURRENT-DUE']['value'] ))
  1157. $c = $a->_date_time_string( $a->xprop['X-CURRENT-DUE']['value'] );
  1158. if( empty( $c ) && !empty( $a->due['value'] ))
  1159. $c = & $a->due['value'];
  1160. if( empty( $c ) && !empty( $a->duration['value'] ))
  1161. $c = $a->duration2date();
  1162. $d = ( isset( $b->xprop['X-CURRENT-DTEND']['value'] )) ? $b->_date_time_string( $b->xprop['X-CURRENT-DTEND']['value'] ) : null;
  1163. if( empty( $d ) && !empty( $b->dtend['value'] ))
  1164. $d = & $b->dtend['value'];
  1165. if( empty( $d ) && isset( $b->xprop['X-CURRENT-DUE']['value'] ))
  1166. $d = $b->_date_time_string( $b->xprop['X-CURRENT-DUE']['value'] );
  1167. if( empty( $d ) && !empty( $b->due['value'] ))
  1168. $d = & $b->due['value'];
  1169. if( empty( $d ) && !empty( $b->duration['value'] ))
  1170. $d = $b->duration2date();
  1171. if( empty( $c )) return -1;
  1172. elseif( empty( $d )) return 1;
  1173. foreach( $this->_sortkeys as $key ) {
  1174. if ( !isset( $c[$key] )) return -1;
  1175. elseif( !isset( $d[$key] )) return 1;
  1176. if ( $c[$key] == $d[$key] ) continue;
  1177. if (( (int) $c[$key] ) < ((int) $d[$key])) return -1;
  1178. elseif(( (int) $c[$key] ) > ((int) $d[$key])) return 1;
  1179. }
  1180. if( isset( $a->created['value'] ))
  1181. $e = & $a->created['value'];
  1182. else
  1183. $e = & $a->dtstamp['value'];
  1184. if( isset( $b->created['value'] ))
  1185. $f = & $b->created['value'];
  1186. else
  1187. $f = & $b->dtstamp['value'];
  1188. foreach( $this->_sortkeys as $key ) {
  1189. if( !isset( $e[$key] )) return -1;
  1190. elseif( !isset( $f[$key] )) return 1;
  1191. if ( $e[$key] == $f[$key] ) continue;
  1192. if (( (int) $e[$key] ) < ((int) $f[$key])) return -1;
  1193. elseif(( (int) $e[$key] ) > ((int) $f[$key])) return 1;
  1194. }
  1195. if (( $a->uid['value'] ) <
  1196. ( $b->uid['value'] )) return -1;
  1197. elseif(( $a->uid['value'] ) >
  1198. ( $b->uid['value'] )) return 1;
  1199. return 0;
  1200. }
  1201. /**
  1202. * parse iCal file into vcalendar, components, properties and parameters
  1203. *
  1204. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1205. * @since 2.4.10 - 2008-08-06
  1206. * @param string $filename optional filname (incl. opt. directory/path) or URL
  1207. * @return bool FALSE if error occurs during parsing
  1208. *
  1209. */
  1210. function parse( $filename=FALSE ) {
  1211. if( !$filename ) {
  1212. /* directory/filename previous set via setConfig directory+filename / url */
  1213. if( FALSE === ( $filename = $this->getConfig( 'url' )))
  1214. $filename = $this->getConfig( 'dirfile' );
  1215. }
  1216. elseif(( 'http://' == strtolower( substr( $filename, 0, 7 ))) ||
  1217. ( 'webcal://' == strtolower( substr( $filename, 0, 9 )))) {
  1218. /* remote file - URL */
  1219. $this->setConfig( 'URL', $filename );
  1220. if( !$filename = $this->getConfig( 'url' ))
  1221. return FALSE; /* err 2 */
  1222. }
  1223. else {
  1224. /* local directory/filename */
  1225. $parts = pathinfo( $filename );
  1226. if( !empty( $parts['dirname'] ) && ( '.' != $parts['dirname'] )) {
  1227. if( !$this->setConfig( 'directory', $parts['dirname'] ))
  1228. return FALSE; /* err 3 */
  1229. }
  1230. if( !$this->setConfig( 'filename', $parts['basename'] ))
  1231. return FALSE; /* err 4 */
  1232. }
  1233. if( 'http://' != substr( $filename, 0, 7 )) {
  1234. /* local file error tests */
  1235. if( !is_file( $filename )) /* err 5 */
  1236. return FALSE;
  1237. if( !is_readable( $filename ))
  1238. return FALSE; /* err 6 */
  1239. if( !filesize( $filename ))
  1240. return FALSE; /* err 7 */
  1241. clearstatcache();
  1242. }
  1243. /* READ FILE */
  1244. if( FALSE === ( $rows = file( $filename )))
  1245. return FALSE; /* err 1 */
  1246. /* identify BEGIN:VCALENDAR, MUST be first row */
  1247. if( 'BEGIN:VCALENDAR' != strtoupper( trim( $rows[0] )))
  1248. return FALSE; /* err 8 */
  1249. /* remove empty trailing lines */
  1250. while( '' == trim( $rows[count( $rows ) - 1] )) {
  1251. unset( $rows[count( $rows ) - 1] );
  1252. $rows = array_values( $rows );
  1253. }
  1254. /* identify ending END:VCALENDAR row */
  1255. if( 'END:VCALENDAR' != strtoupper( trim( $rows[count( $rows ) - 1] ))) {
  1256. return FALSE; /* err 9 */
  1257. }
  1258. if( 3 > count( $rows ))
  1259. return FALSE; /* err 10 */
  1260. $comp = $subcomp = null;
  1261. $actcomp = & $this;
  1262. $nl = $this->getConfig( 'nl' );
  1263. $calsync = 0;
  1264. /* identify components and update unparsed data within component */
  1265. foreach( $rows as $line ) {
  1266. if( '' == trim( $line ))
  1267. continue;
  1268. if( $nl == substr( $line, 0 - strlen( $nl )))
  1269. $line = substr( $line, 0, ( strlen( $line ) - strlen( $nl ))).'\n';
  1270. if( 'BEGIN:VCALENDAR' == strtoupper( substr( $line, 0, 15 ))) {
  1271. $calsync++;
  1272. continue;
  1273. }
  1274. elseif( 'END:VCALENDAR' == strtoupper( substr( $line, 0, 13 ))) {
  1275. $calsync--;
  1276. continue;
  1277. }
  1278. elseif( 1 != $calsync )
  1279. return FALSE; /* err 20 */
  1280. if( 'END:' == strtoupper( substr( $line, 0, 4 ))) {
  1281. if( null != $subcomp ) {
  1282. $comp->setComponent( $subcomp );
  1283. $subcomp = null;
  1284. }
  1285. else {
  1286. $this->setComponent( $comp );
  1287. $comp = null;
  1288. }
  1289. $actcomp = null;
  1290. continue;
  1291. } // end - if ( 'END:' ==.. .
  1292. elseif( 'BEGIN:' == strtoupper( substr( $line, 0, 6 ))) {
  1293. $line = str_replace( '\n', '', $line );
  1294. $compname = trim (strtoupper( substr( $line, 6 )));
  1295. if( null != $comp ) {
  1296. if( 'VALARM' == $compname )
  1297. $subcomp = new valarm();
  1298. elseif( 'STANDARD' == $compname )
  1299. $subcomp = new vtimezone( 'STANDARD' );
  1300. elseif( 'DAYLIGHT' == $compname )
  1301. $subcomp = new vtimezone( 'DAYLIGHT' );
  1302. else
  1303. return FALSE; /* err 6 */
  1304. $actcomp = & $subcomp;
  1305. }
  1306. else {
  1307. switch( $compname ) {
  1308. case 'VALARM':
  1309. $comp = new valarm();
  1310. break;
  1311. case 'VEVENT':
  1312. $comp = new vevent();
  1313. break;
  1314. case 'VFREEBUSY';
  1315. $comp = new vfreebusy();
  1316. break;
  1317. case 'VJOURNAL':
  1318. $comp = new vjournal();
  1319. break;
  1320. case 'VTODO':
  1321. $comp = new vtodo();
  1322. break;
  1323. case 'VTIMEZONE':
  1324. $comp = new vtimezone();
  1325. break;
  1326. default:
  1327. return FALSE; // err 7
  1328. break;
  1329. } // end - switch
  1330. $actcomp = & $comp;
  1331. }
  1332. continue;
  1333. } // end - elsif ( 'BEGIN:'.. .
  1334. /* update selected component with unparsed data */
  1335. $actcomp->unparsed[] = $line;
  1336. } // end - foreach( rows.. .
  1337. /* parse data for calendar (this) object */
  1338. if( is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) {
  1339. /* concatenate property values spread over several lines */
  1340. $lastix = -1;
  1341. $propnames = array( 'calscale','method','prodid','version','x-' );
  1342. $proprows = array();
  1343. foreach( $this->unparsed as $line ) {
  1344. $newProp = FALSE;
  1345. foreach ( $propnames as $propname ) {
  1346. if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
  1347. $newProp = TRUE;
  1348. break;
  1349. }
  1350. }
  1351. if( $newProp ) {
  1352. $newProp = FALSE;
  1353. $lastix++;
  1354. $proprows[$lastix] = $line;
  1355. }
  1356. else {
  1357. /* remove line breaks */
  1358. if(( '\n' == substr( $proprows[$lastix], -2 )) &&
  1359. ( ' ' == substr( $line, 0, 1 ))) {
  1360. $proprows[$lastix] = substr( $proprows[$lastix], 0, strlen( $proprows[$lastix] ) - 2 );
  1361. $line = substr( $line, 1 );
  1362. }
  1363. $proprows[$lastix] .= $line;
  1364. }
  1365. }
  1366. $toolbox = new calendarComponent();
  1367. foreach( $proprows as $line ) {
  1368. if( '\n' == substr( $line, -2 ))
  1369. $line = substr( $line, 0, strlen( $line ) - 2 );
  1370. /* get propname */
  1371. $cix = $propname = null;
  1372. for( $cix=0; $cix < strlen( $line ); $cix++ ) {
  1373. if( in_array( $line{$cix}, array( ':', ';' )))
  1374. break;
  1375. else
  1376. $propname .= $line{$cix};
  1377. }
  1378. /* ignore version/prodid properties */
  1379. if( in_array( strtoupper( $propname ), array( 'VERSION', 'PRODID' )))
  1380. continue;
  1381. $line = substr( $line, $cix);
  1382. /* separate attributes from value */
  1383. $attr = array();
  1384. $attrix = -1;
  1385. $strlen = strlen( $line );
  1386. for( $cix=0; $cix < $strlen; $cix++ ) {
  1387. if(( ':' == $line{$cix} ) &&
  1388. ( '://' != substr( $line, $cix, 3 )) &&
  1389. ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
  1390. $attrEnd = TRUE;
  1391. if(( $cix < ( $strlen - 4 )) &&
  1392. ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
  1393. for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
  1394. if( '://' == substr( $line, $c2ix - 2, 3 )) {
  1395. $attrEnd = FALSE;
  1396. break; // an URI with a portnr!!
  1397. }
  1398. }
  1399. }
  1400. if( $attrEnd) {
  1401. $line = substr( $line, $cix + 1 );
  1402. break;
  1403. }
  1404. }
  1405. if( ';' == $line{$cix} )
  1406. $attr[++$attrix] = null;
  1407. else
  1408. $attr[$attrix] .= $line{$cix};
  1409. }
  1410. /* make attributes in array format */
  1411. $propattr = array();
  1412. foreach( $attr as $attribute ) {
  1413. $attrsplit = explode( '=', $attribute, 2 );
  1414. if( 1 < count( $attrsplit ))
  1415. $propattr[$attrsplit[0]] = $attrsplit[1];
  1416. else
  1417. $propattr[] = $attribute;
  1418. }
  1419. /* update Property */
  1420. if( FALSE !== strpos( $line, ',' )) {
  1421. $content = explode( ',', $line );
  1422. $clen = count( $content );
  1423. for( $cix = 0; $cix < $clen; $cix++ ) {
  1424. if( "\\" == substr( $content[$cix], -1 )) {
  1425. $content[$cix] .= ','.$content[$cix + 1];
  1426. unset( $content[$cix + 1] );
  1427. $cix++;
  1428. }
  1429. }
  1430. if( 1 < count( $content )) {
  1431. foreach( $content as $cix => $contentPart )
  1432. $content[$cix] = $toolbox->_strunrep( $contentPart );
  1433. $this->setProperty( $propname, $content, $propattr );
  1434. continue;
  1435. }
  1436. else
  1437. $line = reset( $content );
  1438. $line = $toolbox->_strunrep( $line );
  1439. }
  1440. $this->setProperty( $propname, trim( $line ), $propattr );
  1441. } // end - foreach( $this->unparsed.. .
  1442. } // end - if( is_array( $this->unparsed.. .
  1443. /* parse Components */
  1444. if( is_array( $this->components ) && ( 0 < count( $this->components ))) {
  1445. for( $six = 0; $six < count( $this->components ); $six++ ) {
  1446. if( !empty( $this->components[$six] ))
  1447. $this->components[$six]->parse();
  1448. }
  1449. }
  1450. else
  1451. return FALSE; /* err 91 or something.. . */
  1452. return TRUE;
  1453. }
  1454. /*********************************************************************************/
  1455. /**
  1456. * creates formatted output for calendar object instance
  1457. *
  1458. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1459. * @since 2.4.10 - 2008-08-06
  1460. * @return string
  1461. */
  1462. function createCalendar() {
  1463. $calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null;
  1464. switch( $this->format ) {
  1465. case 'xcal':
  1466. $calendarInit1 = '<?xml version="1.0" encoding="UTF-8"?>'.$this->nl.
  1467. '<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"'.$this->nl.
  1468. '"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"';
  1469. $calendarInit2 = '>'.$this->nl;
  1470. $calendarStart = '<vcalendar';
  1471. break;
  1472. default:
  1473. $calendarStart = 'BEGIN:VCALENDAR'.$this->nl;
  1474. break;
  1475. }
  1476. $calendarStart .= $this->createCalscale();
  1477. $calendarStart .= $this->createMethod();
  1478. $calendarStart .= $this->createProdid();
  1479. $calendarStart .= $this->createVersion();
  1480. switch( $this->format ) {
  1481. case 'xcal':
  1482. $nlstrlen = strlen( $this->nl );
  1483. if( $this->nl == substr( $calendarStart, ( 0 - $nlstrlen )))
  1484. $calendarStart = substr( $calendarStart, 0, ( strlen( $calendarStart ) - $nlstrlen ));
  1485. $calendarStart .= '>'.$this->nl;
  1486. break;
  1487. default:
  1488. break;
  1489. }
  1490. $calendar .= $this->createXprop();
  1491. foreach( $this->components as $component ) {
  1492. if( empty( $component )) continue;
  1493. if( '' >= $component->getConfig( 'language'))
  1494. $component->setConfig( 'language', $this->getConfig( 'language' ));
  1495. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  1496. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  1497. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  1498. $component->setConfig( 'format', $this->getConfig( 'format' ));
  1499. $calendar .= $component->createComponent( $this->xcaldecl );
  1500. }
  1501. if(( 0 < count( $this->xcaldecl )) && ( 'xcal' == $this->format )) { // xCal only
  1502. $calendarInit1 .= $this->nl.'['.$this->nl;
  1503. $old_xcaldecl = array();
  1504. foreach( $this->xcaldecl as $declix => $declPart ) {
  1505. if(( 0 < count( $old_xcaldecl)) &&
  1506. ( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) &&
  1507. ( in_array( $declPart['external'], $old_xcaldecl['external'] )))
  1508. continue; // no duplicate uri and ext. references
  1509. $calendarxCaldecl .= '<!';
  1510. foreach( $declPart as $declKey => $declValue ) {
  1511. switch( $declKey ) { // index
  1512. case 'xmldecl': // no 1
  1513. $calendarxCaldecl .= $declValue.' ';
  1514. break;
  1515. case 'uri': // no 2
  1516. $calendarxCaldecl .= $declValue.' ';
  1517. $old_xcaldecl['uri'][] = $declValue;
  1518. break;
  1519. case 'ref': // no 3
  1520. $calendarxCaldecl .= $declValue.' ';
  1521. break;
  1522. case 'external': // no 4
  1523. $calendarxCaldecl .= '"'.$declValue.'" ';
  1524. $old_xcaldecl['external'][] = $declValue;
  1525. break;
  1526. case 'type': // no 5
  1527. $calendarxCaldecl .= $declValue.' ';
  1528. break;
  1529. case 'type2': // no 6
  1530. $calendarxCaldecl .= $declValue;
  1531. break;
  1532. }
  1533. }
  1534. $calendarxCaldecl .= '>'.$this->nl;
  1535. }
  1536. $calendarInit2 = ']'.$calendarInit2;
  1537. }
  1538. switch( $this->format ) {
  1539. case 'xcal':
  1540. $calendar .= '</vcalendar>'.$this->nl;
  1541. break;
  1542. default:
  1543. $calendar .= 'END:VCALENDAR'.$this->nl;
  1544. break;
  1545. }
  1546. return $calendarInit1.$calendarxCaldecl.$calendarInit2.$calendarStart.$calendar;
  1547. }
  1548. /**
  1549. * a HTTP redirect header is sent with created, updated and/or parsed calendar
  1550. *
  1551. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1552. * @since 2.2.12 - 2007-10-23
  1553. * @return redirect
  1554. */
  1555. function returnCalendar() {
  1556. $filename = $this->getConfig( 'filename' );
  1557. $output = $this->createCalendar();
  1558. $filesize = strlen( $output );
  1559. // if( headers_sent( $filename, $linenum ))
  1560. // die( "Headers already sent in $filename on line $linenum\n" );
  1561. if( 'xcal' == $this->format )
  1562. header( 'Content-Type: application/calendar+xml; charset=utf-8' );
  1563. else
  1564. header( 'Content-Type: text/calendar; charset=utf-8' );
  1565. header( 'Content-Length: '.$filesize );
  1566. header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
  1567. header( 'Cache-Control: max-age=10' );
  1568. echo $output;
  1569. die();
  1570. }
  1571. /**
  1572. * save content in a file
  1573. *
  1574. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1575. * @since 2.2.12 - 2007-12-30
  1576. * @param string $directory optional
  1577. * @param string $filename optional
  1578. * @param string $delimiter optional
  1579. * @return bool
  1580. */
  1581. function saveCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE ) {
  1582. if( $directory )
  1583. $this->setConfig( 'directory', $directory );
  1584. if( $filename )
  1585. $this->setConfig( 'filename', $filename );
  1586. if( $delimiter && ($delimiter != DIRECTORY_SEPARATOR ))
  1587. $this->setConfig( 'delimiter', $delimiter );
  1588. if( FALSE === ( $dirfile = $this->getConfig( 'url' )))
  1589. $dirfile = $this->getConfig( 'dirfile' );
  1590. $iCalFile = @fopen( $dirfile, 'w' );
  1591. if( $iCalFile ) {
  1592. if( FALSE === fwrite( $iCalFile, $this->createCalendar() ))
  1593. return FALSE;
  1594. fclose( $iCalFile );
  1595. return TRUE;
  1596. }
  1597. else
  1598. return FALSE;
  1599. }
  1600. /**
  1601. * if recent version of calendar file exists (default one hour), an HTTP redirect header is sent
  1602. * else FALSE is returned
  1603. *
  1604. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1605. * @since 2.2.12 - 2007-10-28
  1606. * @param string $directory optional alt. int timeout
  1607. * @param string $filename optional
  1608. * @param string $delimiter optional
  1609. * @param int timeout optional, default 3600 sec
  1610. * @return redirect/FALSE
  1611. */
  1612. function useCachedCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE, $timeout=3600) {
  1613. if ( $directory && ctype_digit( (string) $directory ) && !$filename ) {
  1614. $timeout = (int) $directory;
  1615. $directory = FALSE;
  1616. }
  1617. if( $directory )
  1618. $this->setConfig( 'directory', $directory );
  1619. if( $filename )
  1620. $this->setConfig( 'filename', $filename );
  1621. if( $delimiter && ( $delimiter != DIRECTORY_SEPARATOR ))
  1622. $this->setConfig( 'delimiter', $delimiter );
  1623. $filesize = $this->getConfig( 'filesize' );
  1624. if( 0 >= $filesize )
  1625. return FALSE;
  1626. $dirfile = $this->getConfig( 'dirfile' );
  1627. if( time() - filemtime( $dirfile ) < $timeout) {
  1628. clearstatcache();
  1629. $dirfile = $this->getConfig( 'dirfile' );
  1630. $filename = $this->getConfig( 'filename' );
  1631. // if( headers_sent( $filename, $linenum ))
  1632. // die( "Headers already sent in $filename on line $linenum\n" );
  1633. if( 'xcal' == $this->format )
  1634. header( 'Content-Type: application/calendar+xml; charset=utf-8' );
  1635. else
  1636. header( 'Content-Type: text/calendar; charset=utf-8' );
  1637. header( 'Content-Length: '.$filesize );
  1638. header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
  1639. header( 'Cache-Control: max-age=10' );
  1640. $fp = @$fopen( $dirfile, 'r' );
  1641. if( $fp ) {
  1642. fpassthru( $fp );
  1643. fclose( $fp );
  1644. }
  1645. die();
  1646. }
  1647. else
  1648. return FALSE;
  1649. }
  1650. }
  1651. /*********************************************************************************/
  1652. /*********************************************************************************/
  1653. /**
  1654. * abstract class for calendar components
  1655. *
  1656. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1657. * @since 2.4.19 - 2008-10-12
  1658. */
  1659. class calendarComponent {
  1660. // component property variables
  1661. var $uid;
  1662. var $dtstamp;
  1663. // component config variables
  1664. var $allowEmpty;
  1665. var $language;
  1666. var $nl;
  1667. var $unique_id;
  1668. var $format;
  1669. var $objName; // created automatically at instance creation
  1670. // component internal variables
  1671. var $componentStart1;
  1672. var $componentStart2;
  1673. var $componentEnd1;
  1674. var $componentEnd2;
  1675. var $elementStart1;
  1676. var $elementStart2;
  1677. var $elementEnd1;
  1678. var $elementEnd2;
  1679. var $intAttrDelimiter;
  1680. var $attributeDelimiter;
  1681. var $valueInit;
  1682. // component xCal declaration container
  1683. var $xcaldecl;
  1684. /**
  1685. * constructor for calendar component object
  1686. *
  1687. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1688. * @since 2.4.19 - 2008-10-23
  1689. */
  1690. function calendarComponent() {
  1691. $this->objName = ( isset( $this->timezonetype )) ?
  1692. strtolower( $this->timezonetype ) : get_class ( $this );
  1693. $this->uid = array();
  1694. $this->dtstamp = array();
  1695. $this->language = null;
  1696. $this->nl = null;
  1697. $this->unique_id = null;
  1698. $this->format = null;
  1699. $this->allowEmpty = TRUE;
  1700. $this->xcaldecl = array();
  1701. $this->_createFormat();
  1702. $this->_makeDtstamp();
  1703. }
  1704. /*********************************************************************************/
  1705. /**
  1706. * Property Name: ACTION
  1707. */
  1708. /**
  1709. * creates formatted output for calendar component property action
  1710. *
  1711. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1712. * @since 2.4.8 - 2008-10-22
  1713. * @return string
  1714. */
  1715. function createAction() {
  1716. if( empty( $this->action )) return FALSE;
  1717. if( empty( $this->action['value'] ))
  1718. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE;
  1719. $attributes = $this->_createParams( $this->action['params'] );
  1720. return $this->_createElement( 'ACTION', $attributes, $this->action['value'] );
  1721. }
  1722. /**
  1723. * set calendar component property action
  1724. *
  1725. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1726. * @since 2.4.8 - 2008-11-04
  1727. * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
  1728. * @param mixed $params
  1729. * @return bool
  1730. */
  1731. function setAction( $value, $params=FALSE ) {
  1732. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1733. $this->action = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  1734. return TRUE;
  1735. }
  1736. /*********************************************************************************/
  1737. /**
  1738. * Property Name: ATTACH
  1739. */
  1740. /**
  1741. * creates formatted output for calendar component property attach
  1742. *
  1743. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1744. * @since 0.9.7 - 2006-11-23
  1745. * @return string
  1746. */
  1747. function createAttach() {
  1748. if( empty( $this->attach )) return FALSE;
  1749. $output = null;
  1750. foreach( $this->attach as $attachPart ) {
  1751. if(! empty( $attachPart['value'] )) {
  1752. $attributes = $this->_createParams( $attachPart['params'] );
  1753. $output .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] );
  1754. }
  1755. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' );
  1756. }
  1757. return $output;
  1758. }
  1759. /**
  1760. * set calendar component property attach
  1761. *
  1762. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1763. * @since 2.5.1 - 2008-11-06
  1764. * @param string $value
  1765. * @param array $params, optional
  1766. * @param integer $index, optional
  1767. * @return bool
  1768. */
  1769. function setAttach( $value, $params=FALSE, $index=FALSE ) {
  1770. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1771. $this->_setMval( $this->attach, $value, $params, FALSE, $index );
  1772. return TRUE;
  1773. }
  1774. /*********************************************************************************/
  1775. /**
  1776. * Property Name: ATTENDEE
  1777. */
  1778. /**
  1779. * creates formatted output for calendar component property attendee
  1780. *
  1781. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1782. * @since 2.4.8 - 2008-09-23
  1783. * @return string
  1784. */
  1785. function createAttendee() {
  1786. if( empty( $this->attendee )) return FALSE;
  1787. $output = null;
  1788. foreach( $this->attendee as $attendeePart ) { // start foreach 1
  1789. if( empty( $attendeePart['value'] )) {
  1790. if( $this->getConfig( 'allowEmpty' ))
  1791. $output .= $this->_createElement( 'ATTENDEE' );
  1792. continue;
  1793. }
  1794. $attendee1 = $attendee2 = $attendeeLANG = $attendeeCN = null;
  1795. foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2
  1796. if( 'value' == $paramlabel )
  1797. $attendee2 .= 'MAILTO:'.$paramvalue;
  1798. elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
  1799. foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
  1800. $attendee11 = $attendee12 = null;
  1801. if( is_int( $optparamlabel )) {
  1802. $attendee1 .= $this->intAttrDelimiter.$optparamvalue;
  1803. continue;
  1804. }
  1805. switch( $optparamlabel ) { // start switch
  1806. case 'CUTYPE':
  1807. case 'PARTSTAT':
  1808. case 'ROLE':
  1809. case 'RSVP':
  1810. $attendee1 .= $this->intAttrDelimiter.$optparamlabel.'="'.$optparamvalue.'"';
  1811. break;
  1812. case 'SENT-BY':
  1813. $attendee1 .= $this->intAttrDelimiter.'SENT-BY="MAILTO:'.$optparamvalue.'"';
  1814. break;
  1815. case 'MEMBER':
  1816. $attendee11 = $this->intAttrDelimiter.'MEMBER=';
  1817. case 'DELEGATED-TO':
  1818. $attendee11 = ( !$attendee11 ) ? $this->intAttrDelimiter.'DELEGATED-TO=' : $attendee11;
  1819. case 'DELEGATED-FROM':
  1820. $attendee11 = ( !$attendee11 ) ? $this->intAttrDelimiter.'DELEGATED-FROM=' : $attendee11;
  1821. foreach( $optparamvalue as $cix => $calUserAddress ) {
  1822. $attendee12 .= ( $cix ) ? ',' : null;
  1823. $attendee12 .= '"MAILTO:'.$calUserAddress.'"';
  1824. }
  1825. $attendee1 .= $attendee11.$attendee12;
  1826. break;
  1827. case 'CN':
  1828. $attendeeCN .= $this->intAttrDelimiter.'CN="'.$optparamvalue.'"';
  1829. break;
  1830. case 'DIR':
  1831. $attendee1 .= $this->intAttrDelimiter.'DIR="'.$optparamvalue.'"';
  1832. break;
  1833. case 'LANGUAGE':
  1834. $attendeeLANG .= $this->intAttrDelimiter.'LANGUAGE='.$optparamvalue;
  1835. break;
  1836. default:
  1837. $attendee1 .= $this->intAttrDelimiter."$optparamlabel=$optparamvalue";
  1838. break;
  1839. } // end switch
  1840. } // end foreach 3
  1841. } // end elseif
  1842. } // end foreach 2
  1843. $output .= $this->_createElement( 'ATTENDEE', $attendee1.$attendeeLANG.$attendeeCN, $attendee2 );
  1844. } // end foreach 1
  1845. return $output;
  1846. }
  1847. /**
  1848. * set calendar component property attach
  1849. *
  1850. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1851. * @since 2.5.1 - 2008-11-05
  1852. * @param string $value
  1853. * @param array $params, optional
  1854. * @param integer $index, optional
  1855. * @return bool
  1856. */
  1857. function setAttendee( $value, $params=FALSE, $index=FALSE ) {
  1858. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1859. $value = str_replace ( 'MAILTO:', '', $value );
  1860. $value = str_replace ( 'mailto:', '', $value );
  1861. $params2 = array();
  1862. if( is_array($params )) {
  1863. $optarrays = array();
  1864. foreach( $params as $optparamlabel => $optparamvalue ) {
  1865. $optparamlabel = strtoupper( $optparamlabel );
  1866. switch( $optparamlabel ) {
  1867. case 'MEMBER':
  1868. case 'DELEGATED-TO':
  1869. case 'DELEGATED-FROM':
  1870. if( is_array( $optparamvalue )) {
  1871. foreach( $optparamvalue as $part ) {
  1872. $part = str_replace( 'MAILTO:', '', $part );
  1873. $part = str_replace( 'mailto:', '', $part );
  1874. if(( '"' == $part{0} ) && ( '"' == $part{strlen($part)-1} ))
  1875. $part = substr( $part, 1, ( strlen($part)-2 ));
  1876. $optarrays[$optparamlabel][] = $part;
  1877. }
  1878. }
  1879. else {
  1880. $part = str_replace( 'MAILTO:', '', $optparamvalue );
  1881. $part = str_replace( 'mailto:', '', $part );
  1882. if(( '"' == $part{0} ) && ( '"' == $part{strlen($part)-1} ))
  1883. $part = substr( $part, 1, ( strlen($part)-2 ));
  1884. $optarrays[$optparamlabel][] = $part;
  1885. }
  1886. break;
  1887. default:
  1888. if( 'SENT-BY' == $optparamlabel ) {
  1889. $optparamvalue = str_replace( 'MAILTO:', '', $optparamvalue );
  1890. $optparamvalue = str_replace( 'mailto:', '', $optparamvalue );
  1891. }
  1892. if(( '"' == substr( $optparamvalue, 0, 1 )) &&
  1893. ( '"' == substr( $optparamvalue, -1 )))
  1894. $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
  1895. $params2[$optparamlabel] = $optparamvalue;
  1896. break;
  1897. } // end switch( $optparamlabel.. .
  1898. } // end foreach( $optparam.. .
  1899. foreach( $optarrays as $optparamlabel => $optparams )
  1900. $params2[$optparamlabel] = $optparams;
  1901. }
  1902. // remove defaults
  1903. $this->_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' );
  1904. $this->_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
  1905. $this->_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' );
  1906. $this->_existRem( $params2, 'RSVP', 'FALSE' );
  1907. // check language setting
  1908. if( isset( $params2['CN' ] )) {
  1909. $lang = $this->getConfig( 'language' );
  1910. if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
  1911. $params2['LANGUAGE' ] = $lang;
  1912. }
  1913. $this->_setMval( $this->attendee, $value, $params2, FALSE, $index );
  1914. return TRUE;
  1915. }
  1916. /*********************************************************************************/
  1917. /**
  1918. * Property Name: CATEGORIES
  1919. */
  1920. /**
  1921. * creates formatted output for calendar component property categories
  1922. *
  1923. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1924. * @since 2.4.8 - 2008-10-22
  1925. * @return string
  1926. */
  1927. function createCategories() {
  1928. if( empty( $this->categories )) return FALSE;
  1929. $output = null;
  1930. foreach( $this->categories as $category ) {
  1931. if( empty( $category['value'] )) {
  1932. if ( $this->getConfig( 'allowEmpty' ))
  1933. $output .= $this->_createElement( 'CATEGORIES' );
  1934. continue;
  1935. }
  1936. $attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' ));
  1937. if( is_array( $category['value'] )) {
  1938. foreach( $category['value'] as $cix => $categoryPart )
  1939. $category['value'][$cix] = $this->_strrep( $categoryPart );
  1940. $content = implode( ',', $category['value'] );
  1941. }
  1942. else
  1943. $content = $this->_strrep( $category['value'] );
  1944. $output .= $this->_createElement( 'CATEGORIES', $attributes, $content );
  1945. }
  1946. return $output;
  1947. }
  1948. /**
  1949. * set calendar component property categories
  1950. *
  1951. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1952. * @since 2.5.1 - 2008-11-06
  1953. * @param mixed $value
  1954. * @param array $params, optional
  1955. * @param integer $index, optional
  1956. * @return bool
  1957. */
  1958. function setCategories( $value, $params=FALSE, $index=FALSE ) {
  1959. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1960. $this->_setMval( $this->categories, $value, $params, FALSE, $index );
  1961. return TRUE;
  1962. }
  1963. /*********************************************************************************/
  1964. /**
  1965. * Property Name: CLASS
  1966. */
  1967. /**
  1968. * creates formatted output for calendar component property class
  1969. *
  1970. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1971. * @since 0.9.7 - 2006-11-20
  1972. * @return string
  1973. */
  1974. function createClass() {
  1975. if( empty( $this->class )) return FALSE;
  1976. if( empty( $this->class['value'] ))
  1977. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE;
  1978. $attributes = $this->_createParams( $this->class['params'] );
  1979. return $this->_createElement( 'CLASS', $attributes, $this->class['value'] );
  1980. }
  1981. /**
  1982. * set calendar component property class
  1983. *
  1984. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1985. * @since 2.4.8 - 2008-11-04
  1986. * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
  1987. * @param array $params optional
  1988. * @return bool
  1989. */
  1990. function setClass( $value, $params=FALSE ) {
  1991. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1992. $this->class = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  1993. return TRUE;
  1994. }
  1995. /*********************************************************************************/
  1996. /**
  1997. * Property Name: COMMENT
  1998. */
  1999. /**
  2000. * creates formatted output for calendar component property comment
  2001. *
  2002. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2003. * @since 2.4.8 - 2008-10-22
  2004. * @return string
  2005. */
  2006. function createComment() {
  2007. if( empty( $this->comment )) return FALSE;
  2008. $output = null;
  2009. foreach( $this->comment as $commentPart ) {
  2010. if( empty( $commentPart['value'] )) {
  2011. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
  2012. continue;
  2013. }
  2014. $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
  2015. $content = $this->_strrep( $commentPart['value'] );
  2016. $output .= $this->_createElement( 'COMMENT', $attributes, $content );
  2017. }
  2018. return $output;
  2019. }
  2020. /**
  2021. * set calendar component property comment
  2022. *
  2023. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2024. * @since 2.5.1 - 2008-11-06
  2025. * @param string $value
  2026. * @param array $params, optional
  2027. * @param integer $index, optional
  2028. * @return bool
  2029. */
  2030. function setComment( $value, $params=FALSE, $index=FALSE ) {
  2031. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2032. $this->_setMval( $this->comment, $value, $params, FALSE, $index );
  2033. return TRUE;
  2034. }
  2035. /*********************************************************************************/
  2036. /**
  2037. * Property Name: COMPLETED
  2038. */
  2039. /**
  2040. * creates formatted output for calendar component property completed
  2041. *
  2042. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2043. * @since 2.4.8 - 2008-10-22
  2044. * @return string
  2045. */
  2046. function createCompleted( ) {
  2047. if( empty( $this->completed )) return FALSE;
  2048. if( !isset( $this->completed['value']['year'] ) &&
  2049. !isset( $this->completed['value']['month'] ) &&
  2050. !isset( $this->completed['value']['day'] ) &&
  2051. !isset( $this->completed['value']['hour'] ) &&
  2052. !isset( $this->completed['value']['min'] ) &&
  2053. !isset( $this->completed['value']['sec'] ))
  2054. if( $this->getConfig( 'allowEmpty' ))
  2055. return $this->_createElement( 'COMPLETED' );
  2056. else return FALSE;
  2057. $formatted = $this->_format_date_time( $this->completed['value'], 7 );
  2058. $attributes = $this->_createParams( $this->completed['params'] );
  2059. return $this->_createElement( 'COMPLETED', $attributes, $formatted );
  2060. }
  2061. /**
  2062. * set calendar component property completed
  2063. *
  2064. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2065. * @since 2.4.8 - 2008-10-23
  2066. * @param mixed $year
  2067. * @param mixed $month optional
  2068. * @param int $day optional
  2069. * @param int $hour optional
  2070. * @param int $min optional
  2071. * @param int $sec optional
  2072. * @param array $params optional
  2073. * @return bool
  2074. */
  2075. function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2076. if( empty( $year )) {
  2077. if( $this->getConfig( 'allowEmpty' )) {
  2078. $this->completed = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2079. return TRUE;
  2080. }
  2081. else
  2082. return FALSE;
  2083. }
  2084. $this->completed = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2085. return TRUE;
  2086. }
  2087. /*********************************************************************************/
  2088. /**
  2089. * Property Name: CONTACT
  2090. */
  2091. /**
  2092. * creates formatted output for calendar component property contact
  2093. *
  2094. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2095. * @since 2.4.8 - 2008-10-23
  2096. * @return string
  2097. */
  2098. function createContact() {
  2099. if( empty( $this->contact )) return FALSE;
  2100. $output = null;
  2101. foreach( $this->contact as $contact ) {
  2102. if( !empty( $contact['value'] )) {
  2103. $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
  2104. $content = $this->_strrep( $contact['value'] );
  2105. $output .= $this->_createElement( 'CONTACT', $attributes, $content );
  2106. }
  2107. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
  2108. }
  2109. return $output;
  2110. }
  2111. /**
  2112. * set calendar component property contact
  2113. *
  2114. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2115. * @since 2.5.1 - 2008-11-05
  2116. * @param string $value
  2117. * @param array $params, optional
  2118. * @param integer $index, optional
  2119. * @return bool
  2120. */
  2121. function setContact( $value, $params=FALSE, $index=FALSE ) {
  2122. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2123. $this->_setMval( $this->contact, $value, $params, FALSE, $index );
  2124. return TRUE;
  2125. }
  2126. /*********************************************************************************/
  2127. /**
  2128. * Property Name: CREATED
  2129. */
  2130. /**
  2131. * creates formatted output for calendar component property created
  2132. *
  2133. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2134. * @since 2.4.8 - 2008-10-21
  2135. * @return string
  2136. */
  2137. function createCreated() {
  2138. if( empty( $this->created )) return FALSE;
  2139. $formatted = $this->_format_date_time( $this->created['value'], 7 );
  2140. $attributes = $this->_createParams( $this->created['params'] );
  2141. return $this->_createElement( 'CREATED', $attributes, $formatted );
  2142. }
  2143. /**
  2144. * set calendar component property created
  2145. *
  2146. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2147. * @since 2.4.8 - 2008-10-23
  2148. * @param mixed $year optional
  2149. * @param mixed $month optional
  2150. * @param int $day optional
  2151. * @param int $hour optional
  2152. * @param int $min optional
  2153. * @param int $sec optional
  2154. * @param mixed $params optional
  2155. * @return bool
  2156. */
  2157. function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2158. if( !isset( $year )) {
  2159. $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
  2160. }
  2161. $this->created = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2162. return TRUE;
  2163. }
  2164. /*********************************************************************************/
  2165. /**
  2166. * Property Name: DESCRIPTION
  2167. */
  2168. /**
  2169. * creates formatted output for calendar component property description
  2170. *
  2171. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2172. * @since 2.4.8 - 2008-10-22
  2173. * @return string
  2174. */
  2175. function createDescription() {
  2176. if( empty( $this->description )) return FALSE;
  2177. $output = null;
  2178. foreach( $this->description as $description ) {
  2179. if( !empty( $description['value'] )) {
  2180. $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
  2181. $content = $this->_strrep( $description['value'] );
  2182. $output .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
  2183. }
  2184. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
  2185. }
  2186. return $output;
  2187. }
  2188. /**
  2189. * set calendar component property description
  2190. *
  2191. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2192. * @since 2.5.1 - 2008-11-05
  2193. * @param string $value
  2194. * @param array $params, optional
  2195. * @param integer $index, optional
  2196. * @return bool
  2197. */
  2198. function setDescription( $value, $params=FALSE, $index=FALSE ) {
  2199. if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; }
  2200. $this->_setMval( $this->description, $value, $params, FALSE, $index );
  2201. return TRUE;
  2202. }
  2203. /*********************************************************************************/
  2204. /**
  2205. * Property Name: DTEND
  2206. */
  2207. /**
  2208. * creates formatted output for calendar component property dtend
  2209. *
  2210. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2211. * @since 2.4.8 - 2008-10-21
  2212. * @return string
  2213. */
  2214. function createDtend() {
  2215. if( empty( $this->dtend )) return FALSE;
  2216. if( !isset( $this->dtend['value']['year'] ) &&
  2217. !isset( $this->dtend['value']['month'] ) &&
  2218. !isset( $this->dtend['value']['day'] ) &&
  2219. !isset( $this->dtend['value']['hour'] ) &&
  2220. !isset( $this->dtend['value']['min'] ) &&
  2221. !isset( $this->dtend['value']['sec'] ))
  2222. if( $this->getConfig( 'allowEmpty' ))
  2223. return $this->_createElement( 'DTEND' );
  2224. else return FALSE;
  2225. $formatted = $this->_format_date_time( $this->dtend['value'] );
  2226. $attributes = $this->_createParams( $this->dtend['params'] );
  2227. return $this->_createElement( 'DTEND', $attributes, $formatted );
  2228. }
  2229. /**
  2230. * set calendar component property dtend
  2231. *
  2232. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2233. * @since 2.4.8 - 2008-10-23
  2234. * @param mixed $year
  2235. * @param mixed $month optional
  2236. * @param int $day optional
  2237. * @param int $hour optional
  2238. * @param int $min optional
  2239. * @param int $sec optional
  2240. * @param string $tz optional
  2241. * @param array params optional
  2242. * @return bool
  2243. */
  2244. function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  2245. if( empty( $year )) {
  2246. if( $this->getConfig( 'allowEmpty' )) {
  2247. $this->dtend = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2248. return TRUE;
  2249. }
  2250. else
  2251. return FALSE;
  2252. }
  2253. $this->dtend = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
  2254. return TRUE;
  2255. }
  2256. /*********************************************************************************/
  2257. /**
  2258. * Property Name: DTSTAMP
  2259. */
  2260. /**
  2261. * creates formatted output for calendar component property dtstamp
  2262. *
  2263. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2264. * @since 2.4.4 - 2008-03-07
  2265. * @return string
  2266. */
  2267. function createDtstamp() {
  2268. if( !isset( $this->dtstamp['value']['year'] ) &&
  2269. !isset( $this->dtstamp['value']['month'] ) &&
  2270. !isset( $this->dtstamp['value']['day'] ) &&
  2271. !isset( $this->dtstamp['value']['hour'] ) &&
  2272. !isset( $this->dtstamp['value']['min'] ) &&
  2273. !isset( $this->dtstamp['value']['sec'] ))
  2274. $this->_makeDtstamp();
  2275. $formatted = $this->_format_date_time( $this->dtstamp['value'], 7 );
  2276. $attributes = $this->_createParams( $this->dtstamp['params'] );
  2277. return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
  2278. }
  2279. /**
  2280. * computes datestamp for calendar component object instance dtstamp
  2281. *
  2282. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2283. * @since 1.x.x - 2007-05-13
  2284. * @return void
  2285. */
  2286. function _makeDtstamp() {
  2287. $this->dtstamp['value'] = array( 'year' => date( 'Y' )
  2288. , 'month' => date( 'm' )
  2289. , 'day' => date( 'd' )
  2290. , 'hour' => date( 'H' )
  2291. , 'min' => date( 'i' )
  2292. , 'sec' => date( 's' ) - date( 'Z' ));
  2293. $this->dtstamp['params'] = null;
  2294. }
  2295. /**
  2296. * set calendar component property dtstamp
  2297. *
  2298. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2299. * @since 2.4.8 - 2008-10-23
  2300. * @param mixed $year
  2301. * @param mixed $month optional
  2302. * @param int $day optional
  2303. * @param int $hour optional
  2304. * @param int $min optional
  2305. * @param int $sec optional
  2306. * @param array $params optional
  2307. * @return TRUE
  2308. */
  2309. function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2310. if( empty( $year ))
  2311. $this->_makeDtstamp();
  2312. else
  2313. $this->dtstamp = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2314. return TRUE;
  2315. }
  2316. /*********************************************************************************/
  2317. /**
  2318. * Property Name: DTSTART
  2319. */
  2320. /**
  2321. * creates formatted output for calendar component property dtstart
  2322. *
  2323. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2324. * @since 2.4.16 - 2008-10-26
  2325. * @return string
  2326. */
  2327. function createDtstart() {
  2328. if( empty( $this->dtstart )) return FALSE;
  2329. if( !isset( $this->dtstart['value']['year'] ) &&
  2330. !isset( $this->dtstart['value']['month'] ) &&
  2331. !isset( $this->dtstart['value']['day'] ) &&
  2332. !isset( $this->dtstart['value']['hour'] ) &&
  2333. !isset( $this->dtstart['value']['min'] ) &&
  2334. !isset( $this->dtstart['value']['sec'] ))
  2335. if( $this->getConfig( 'allowEmpty' ))
  2336. return $this->_createElement( 'DTSTART' );
  2337. else return FALSE;
  2338. if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
  2339. unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
  2340. $formatted = $this->_format_date_time( $this->dtstart['value'] );
  2341. $attributes = $this->_createParams( $this->dtstart['params'] );
  2342. return $this->_createElement( 'DTSTART', $attributes, $formatted );
  2343. }
  2344. /**
  2345. * set calendar component property dtstart
  2346. *
  2347. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2348. * @since 2.4.16 - 2008-11-04
  2349. * @param mixed $year
  2350. * @param mixed $month optional
  2351. * @param int $day optional
  2352. * @param int $hour optional
  2353. * @param int $min optional
  2354. * @param int $sec optional
  2355. * @param string $tz optional
  2356. * @param array $params optional
  2357. * @return bool
  2358. */
  2359. function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  2360. if( empty( $year )) {
  2361. if( $this->getConfig( 'allowEmpty' )) {
  2362. $this->dtstart = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2363. return TRUE;
  2364. }
  2365. else
  2366. return FALSE;
  2367. }
  2368. $this->dtstart = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart' );
  2369. return TRUE;
  2370. }
  2371. /*********************************************************************************/
  2372. /**
  2373. * Property Name: DUE
  2374. */
  2375. /**
  2376. * creates formatted output for calendar component property due
  2377. *
  2378. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2379. * @since 2.4.8 - 2008-10-22
  2380. * @return string
  2381. */
  2382. function createDue() {
  2383. if( empty( $this->due )) return FALSE;
  2384. if( !isset( $this->due['value']['year'] ) &&
  2385. !isset( $this->due['value']['month'] ) &&
  2386. !isset( $this->due['value']['day'] ) &&
  2387. !isset( $this->due['value']['hour'] ) &&
  2388. !isset( $this->due['value']['min'] ) &&
  2389. !isset( $this->due['value']['sec'] ))
  2390. if( $this->getConfig( 'allowEmpty' ))
  2391. return $this->_createElement( 'DUE' );
  2392. else return FALSE;
  2393. $formatted = $this->_format_date_time( $this->due['value'] );
  2394. $attributes = $this->_createParams( $this->due['params'] );
  2395. return $this->_createElement( 'DUE', $attributes, $formatted );
  2396. }
  2397. /**
  2398. * set calendar component property due
  2399. *
  2400. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2401. * @since 2.4.8 - 2008-11-04
  2402. * @param mixed $year
  2403. * @param mixed $month optional
  2404. * @param int $day optional
  2405. * @param int $hour optional
  2406. * @param int $min optional
  2407. * @param int $sec optional
  2408. * @param array $params optional
  2409. * @return bool
  2410. */
  2411. function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  2412. if( empty( $year )) {
  2413. if( $this->getConfig( 'allowEmpty' )) {
  2414. $this->due = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2415. return TRUE;
  2416. }
  2417. else
  2418. return FALSE;
  2419. }
  2420. $this->due = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
  2421. return TRUE;
  2422. }
  2423. /*********************************************************************************/
  2424. /**
  2425. * Property Name: DURATION
  2426. */
  2427. /**
  2428. * creates formatted output for calendar component property duration
  2429. *
  2430. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2431. * @since 2.4.8 - 2008-10-21
  2432. * @return string
  2433. */
  2434. function createDuration() {
  2435. if( empty( $this->duration )) return FALSE;
  2436. if( !isset( $this->duration['value']['week'] ) &&
  2437. !isset( $this->duration['value']['day'] ) &&
  2438. !isset( $this->duration['value']['hour'] ) &&
  2439. !isset( $this->duration['value']['min'] ) &&
  2440. !isset( $this->duration['value']['sec'] ))
  2441. if( $this->getConfig( 'allowEmpty' ))
  2442. return $this->_createElement( 'DURATION', array(), null );
  2443. else return FALSE;
  2444. $attributes = $this->_createParams( $this->duration['params'] );
  2445. return $this->_createElement( 'DURATION', $attributes, $this->_format_duration( $this->duration['value'] ));
  2446. }
  2447. /**
  2448. * set calendar component property duration
  2449. *
  2450. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2451. * @since 2.4.8 - 2008-11-04
  2452. * @param mixed $week
  2453. * @param mixed $day optional
  2454. * @param int $hour optional
  2455. * @param int $min optional
  2456. * @param int $sec optional
  2457. * @param array $params optional
  2458. * @return bool
  2459. */
  2460. function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2461. if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
  2462. if( is_array( $week ) && ( 1 <= count( $week )))
  2463. $this->duration = array( 'value' => $this->_duration_array( $week ), 'params' => $this->_setParams( $day ));
  2464. elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
  2465. $week = trim( $week );
  2466. if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
  2467. $week = substr( $week, 1 );
  2468. $this->duration = array( 'value' => $this->_duration_string( $week ), 'params' => $this->_setParams( $day ));
  2469. }
  2470. elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
  2471. return FALSE;
  2472. else
  2473. $this->duration = array( 'value' => $this->_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => $this->_setParams( $params ));
  2474. return TRUE;
  2475. }
  2476. /*********************************************************************************/
  2477. /**
  2478. * Property Name: EXDATE
  2479. */
  2480. /**
  2481. * creates formatted output for calendar component property exdate
  2482. *
  2483. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2484. * @since 2.4.8 - 2008-10-22
  2485. * @return string
  2486. */
  2487. function createExdate() {
  2488. if( empty( $this->exdate )) return FALSE;
  2489. $output = null;
  2490. foreach( $this->exdate as $ex => $theExdate ) {
  2491. if( empty( $theExdate['value'] )) {
  2492. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'EXDATE' );
  2493. continue;
  2494. }
  2495. $content = $attributes = null;
  2496. foreach( $theExdate['value'] as $eix => $exdatePart ) {
  2497. $parno = count( $exdatePart );
  2498. $formatted = $this->_format_date_time( $exdatePart, $parno );
  2499. if( isset( $theExdate['params']['TZID'] ))
  2500. $formatted = str_replace( 'Z', '', $formatted);
  2501. if( 0 < $eix ) {
  2502. if( isset( $theExdate['value'][0]['tz'] )) {
  2503. if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) ||
  2504. ( 'Z' == $theExdate['value'][0]['tz'] )) {
  2505. if( 'Z' != substr( $formatted, -1 ))
  2506. $formatted .= 'Z';
  2507. }
  2508. else
  2509. $formatted = str_replace( 'Z', '', $formatted );
  2510. }
  2511. else
  2512. $formatted = str_replace( 'Z', '', $formatted );
  2513. }
  2514. $content .= ( 0 < $eix ) ? ','.$formatted : $formatted;
  2515. }
  2516. $attributes .= $this->_createParams( $theExdate['params'] );
  2517. $output .= $this->_createElement( 'EXDATE', $attributes, $content );
  2518. }
  2519. return $output;
  2520. }
  2521. /**
  2522. * set calendar component property exdate
  2523. *
  2524. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2525. * @since 2.5.1 - 2008-11-05
  2526. * @param array exdates
  2527. * @param array $params, optional
  2528. * @param integer $index, optional
  2529. * @return bool
  2530. */
  2531. function setExdate( $exdates, $params=FALSE, $index=FALSE ) {
  2532. if( empty( $exdates )) {
  2533. if( $this->getConfig( 'allowEmpty' )) {
  2534. $this->_setMval( $this->exdate, null, $params, FALSE, $index );
  2535. return TRUE;
  2536. }
  2537. else
  2538. return FALSE;
  2539. }
  2540. $input = array( 'params' => $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
  2541. /* ev. check 1:st date and save ev. timezone **/
  2542. $this->_chkdatecfg( reset( $exdates ), $parno, $input['params'] );
  2543. $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
  2544. foreach( $exdates as $eix => $theExdate ) {
  2545. if( $this->_isArrayTimestampDate( $theExdate ))
  2546. $exdatea = $this->_timestamp2date( $theExdate, $parno );
  2547. elseif( is_array( $theExdate ))
  2548. $exdatea = $this->_date_time_array( $theExdate, $parno );
  2549. elseif( 8 <= strlen( trim( $theExdate ))) // ex. 2006-08-03 10:12:18
  2550. $exdatea = $this->_date_time_string( $theExdate, $parno );
  2551. if( 3 == $parno )
  2552. unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] );
  2553. elseif( isset( $exdatea['tz'] ))
  2554. $exdatea['tz'] = (string) $exdatea['tz'];
  2555. if( isset( $input['params']['TZID'] ) ||
  2556. ( isset( $exdatea['tz'] ) && !$this->_isOffset( $exdatea['tz'] )) ||
  2557. ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
  2558. ( isset( $input['value'][0]['tz'] ) && !$this->_isOffset( $input['value'][0]['tz'] )))
  2559. unset( $exdatea['tz'] );
  2560. $input['value'][] = $exdatea;
  2561. }
  2562. if( 0 >= count( $input['value'] ))
  2563. return FALSE;
  2564. if( 3 == $parno ) {
  2565. $input['params']['VALUE'] = 'DATE';
  2566. unset( $input['params']['TZID'] );
  2567. }
  2568. $this->_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index );
  2569. return TRUE;
  2570. }
  2571. /*********************************************************************************/
  2572. /**
  2573. * Property Name: EXRULE
  2574. */
  2575. /**
  2576. * creates formatted output for calendar component property exrule
  2577. *
  2578. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2579. * @since 2.4.8 - 2008-10-22
  2580. * @return string
  2581. */
  2582. function createExrule() {
  2583. if( empty( $this->exrule )) return FALSE;
  2584. return $this->_format_recur( 'EXRULE', $this->exrule );
  2585. }
  2586. /**
  2587. * set calendar component property exdate
  2588. *
  2589. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2590. * @since 2.5.1 - 2008-11-05
  2591. * @param array $exruleset
  2592. * @param array $params, optional
  2593. * @param integer $index, optional
  2594. * @return bool
  2595. */
  2596. function setExrule( $exruleset, $params=FALSE, $index=FALSE ) {
  2597. if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = null; else return FALSE;
  2598. $this->_setMval( $this->exrule, $this->_setRexrule( $exruleset ), $params, FALSE, $index );
  2599. return TRUE;
  2600. }
  2601. /*********************************************************************************/
  2602. /**
  2603. * Property Name: FREEBUSY
  2604. */
  2605. /**
  2606. * creates formatted output for calendar component property freebusy
  2607. *
  2608. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2609. * @since 2.4.8 - 2008-10-22
  2610. * @return string
  2611. */
  2612. function createFreebusy() {
  2613. if( empty( $this->freebusy )) return FALSE;
  2614. $output = null;
  2615. foreach( $this->freebusy as $freebusyPart ) {
  2616. if( empty( $freebusyPart['value'] )) {
  2617. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' );
  2618. continue;
  2619. }
  2620. $attributes = $content = null;
  2621. if( isset( $freebusyPart['value']['fbtype'] )) {
  2622. $attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype'];
  2623. unset( $freebusyPart['value']['fbtype'] );
  2624. $freebusyPart['value'] = array_values( $freebusyPart['value'] );
  2625. }
  2626. else
  2627. $attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY';
  2628. $attributes .= $this->_createParams( $freebusyPart['params'] );
  2629. $fno = 1;
  2630. $cnt = count( $freebusyPart['value']);
  2631. foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
  2632. $formatted = $this->_format_date_time( $freebusyPeriod[0] );
  2633. $content .= $formatted;
  2634. $content .= '/';
  2635. $cnt2 = count( $freebusyPeriod[1]);
  2636. if( array_key_exists( 'year', $freebusyPeriod[1] )) // date-time
  2637. $cnt2 = 7;
  2638. elseif( array_key_exists( 'week', $freebusyPeriod[1] )) // duration
  2639. $cnt2 = 5;
  2640. if(( 7 == $cnt2 ) && // period= -> date-time
  2641. isset( $freebusyPeriod[1]['year'] ) &&
  2642. isset( $freebusyPeriod[1]['month'] ) &&
  2643. isset( $freebusyPeriod[1]['day'] )) {
  2644. $content .= $this->_format_date_time( $freebusyPeriod[1] );
  2645. }
  2646. else { // period= -> dur-time
  2647. $content .= $this->_format_duration( $freebusyPeriod[1] );
  2648. }
  2649. if( $fno < $cnt )
  2650. $content .= ',';
  2651. $fno++;
  2652. }
  2653. $output .= $this->_createElement( 'FREEBUSY', $attributes, $content );
  2654. }
  2655. return $output;
  2656. }
  2657. /**
  2658. * set calendar component property freebusy
  2659. *
  2660. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2661. * @since 2.5.1 - 2008-11-05
  2662. * @param string $fbType
  2663. * @param array $fbValues
  2664. * @param array $params, optional
  2665. * @param integer $index, optional
  2666. * @return bool
  2667. */
  2668. function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) {
  2669. if( empty( $fbValues )) {
  2670. if( $this->getConfig( 'allowEmpty' )) {
  2671. $this->_setMval( $this->freebusy, null, $params, FALSE, $index );
  2672. return TRUE;
  2673. }
  2674. else
  2675. return FALSE;
  2676. }
  2677. $fbType = strtoupper( $fbType );
  2678. if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) &&
  2679. ( 'X-' != substr( $fbType, 0, 2 )))
  2680. $fbType = 'BUSY';
  2681. $input = array( 'fbtype' => $fbType );
  2682. foreach( $fbValues as $fbPeriod ) { // periods => period
  2683. $freebusyPeriod = array();
  2684. foreach( $fbPeriod as $fbMember ) { // pairs => singlepart
  2685. $freebusyPairMember = array();
  2686. if( is_array( $fbMember )) {
  2687. if( $this->_isArrayDate( $fbMember )) { // date-time value
  2688. $freebusyPairMember = $this->_date_time_array( $fbMember, 7 );
  2689. $freebusyPairMember['tz'] = 'Z';
  2690. }
  2691. elseif( $this->_isArrayTimestampDate( $fbMember )) { // timestamp value
  2692. $freebusyPairMember = $this->_timestamp2date( $fbMember['timestamp'], 7 );
  2693. $freebusyPairMember['tz'] = 'Z';
  2694. }
  2695. else { // array format duration
  2696. $freebusyPairMember = $this->_duration_array( $fbMember );
  2697. }
  2698. }
  2699. elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
  2700. ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
  2701. if( 'P' != $fbMember{0} )
  2702. $fbmember = substr( $fbMember, 1 );
  2703. $freebusyPairMember = $this->_duration_string( $fbMember );
  2704. }
  2705. elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
  2706. $freebusyPairMember = $this->_date_time_string( $fbMember, 7 );
  2707. $freebusyPairMember['tz'] = 'Z';
  2708. }
  2709. $freebusyPeriod[] = $freebusyPairMember;
  2710. }
  2711. $input[] = $freebusyPeriod;
  2712. }
  2713. $this->_setMval( $this->freebusy, $input, $params, FALSE, $index );
  2714. return TRUE;
  2715. }
  2716. /*********************************************************************************/
  2717. /**
  2718. * Property Name: GEO
  2719. */
  2720. /**
  2721. * creates formatted output for calendar component property geo
  2722. *
  2723. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2724. * @since 2.4.8 - 2008-10-21
  2725. * @return string
  2726. */
  2727. function createGeo() {
  2728. if( empty( $this->geo )) return FALSE;
  2729. if( empty( $this->geo['value'] ))
  2730. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE;
  2731. $attributes = $this->_createParams( $this->geo['params'] );
  2732. $content = null;
  2733. $content .= number_format( (float) $this->geo['value']['latitude'], 6, '.', '');
  2734. $content .= ';';
  2735. $content .= number_format( (float) $this->geo['value']['longitude'], 6, '.', '');
  2736. return $this->_createElement( 'GEO', $attributes, $content );
  2737. }
  2738. /**
  2739. * set calendar component property geo
  2740. *
  2741. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2742. * @since 2.4.8 - 2008-11-04
  2743. * @param float $latitude
  2744. * @param float $longitude
  2745. * @param array $params optional
  2746. * @return bool
  2747. */
  2748. function setGeo( $latitude, $longitude, $params=FALSE ) {
  2749. if( !empty( $latitude ) && !empty( $longitude )) {
  2750. if( !is_array( $this->geo )) $this->geo = array();
  2751. $this->geo['value']['latitude'] = $latitude;
  2752. $this->geo['value']['longitude'] = $longitude;
  2753. $this->geo['params'] = $this->_setParams( $params );
  2754. }
  2755. elseif( $this->getConfig( 'allowEmpty' ))
  2756. $this->geo = array( 'value' => null, 'params' => $this->_setParams( $params ) );
  2757. else
  2758. return FALSE;
  2759. return TRUE;
  2760. }
  2761. /*********************************************************************************/
  2762. /**
  2763. * Property Name: LAST-MODIFIED
  2764. */
  2765. /**
  2766. * creates formatted output for calendar component property last-modified
  2767. *
  2768. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2769. * @since 2.4.8 - 2008-10-21
  2770. * @return string
  2771. */
  2772. function createLastModified() {
  2773. if( empty( $this->lastmodified )) return FALSE;
  2774. $attributes = $this->_createParams( $this->lastmodified['params'] );
  2775. $formatted = $this->_format_date_time( $this->lastmodified['value'], 7 );
  2776. return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
  2777. }
  2778. /**
  2779. * set calendar component property completed
  2780. *
  2781. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2782. * @since 2.4.8 - 2008-10-23
  2783. * @param mixed $year optional
  2784. * @param mixed $month optional
  2785. * @param int $day optional
  2786. * @param int $hour optional
  2787. * @param int $min optional
  2788. * @param int $sec optional
  2789. * @param array $params optional
  2790. * @return boll
  2791. */
  2792. function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2793. if( empty( $year ))
  2794. $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
  2795. $this->lastmodified = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2796. return TRUE;
  2797. }
  2798. /*********************************************************************************/
  2799. /**
  2800. * Property Name: LOCATION
  2801. */
  2802. /**
  2803. * creates formatted output for calendar component property location
  2804. *
  2805. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2806. * @since 2.4.8 - 2008-10-22
  2807. * @return string
  2808. */
  2809. function createLocation() {
  2810. if( empty( $this->location )) return FALSE;
  2811. if( empty( $this->location['value'] ))
  2812. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
  2813. $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
  2814. $content = $this->_strrep( $this->location['value'] );
  2815. return $this->_createElement( 'LOCATION', $attributes, $content );
  2816. }
  2817. /**
  2818. * set calendar component property location
  2819. '
  2820. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2821. * @since 2.4.8 - 2008-11-04
  2822. * @param string $value
  2823. * @param array params optional
  2824. * @return bool
  2825. */
  2826. function setLocation( $value, $params=FALSE ) {
  2827. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2828. $this->location = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2829. return TRUE;
  2830. }
  2831. /*********************************************************************************/
  2832. /**
  2833. * Property Name: ORGANIZER
  2834. */
  2835. /**
  2836. * creates formatted output for calendar component property organizer
  2837. *
  2838. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2839. * @since 2.4.8 - 2008-10-21
  2840. * @return string
  2841. */
  2842. function createOrganizer() {
  2843. if( empty( $this->organizer )) return FALSE;
  2844. if( empty( $this->organizer['value'] ))
  2845. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
  2846. $attributes = $this->_createParams( $this->organizer['params']
  2847. , array( 'CN', 'DIR', 'LANGUAGE', 'SENT-BY' ));
  2848. $content = 'MAILTO:'.$this->organizer['value'];
  2849. return $this->_createElement( 'ORGANIZER', $attributes, $content );
  2850. }
  2851. /**
  2852. * set calendar component property organizer
  2853. *
  2854. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2855. * @since 2.4.8 - 2008-11-04
  2856. * @param string $value
  2857. * @param array params optional
  2858. * @return bool
  2859. */
  2860. function setOrganizer( $value, $params=FALSE ) {
  2861. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2862. $value = str_replace ( 'MAILTO:', '', $value );
  2863. $value = str_replace ( 'mailto:', '', $value );
  2864. $this->organizer = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2865. if( isset( $this->organizer['params']['SENT-BY'] )) {
  2866. if( 'MAILTO' == strtoupper( substr( $this->organizer['params']['SENT-BY'], 0, 6 )))
  2867. $this->organizer['params']['SENT-BY'] = substr( $this->organizer['params']['SENT-BY'], 7 );
  2868. }
  2869. return TRUE;
  2870. }
  2871. /*********************************************************************************/
  2872. /**
  2873. * Property Name: PERCENT-COMPLETE
  2874. */
  2875. /**
  2876. * creates formatted output for calendar component property percent-complete
  2877. *
  2878. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2879. * @since 2.4.8 - 2008-10-22
  2880. * @return string
  2881. */
  2882. function createPercentComplete() {
  2883. if( empty( $this->percentcomplete )) return FALSE;
  2884. if( empty( $this->percentcomplete['value'] ))
  2885. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE;
  2886. $attributes = $this->_createParams( $this->percentcomplete['params'] );
  2887. return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] );
  2888. }
  2889. /**
  2890. * set calendar component property percent-complete
  2891. *
  2892. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2893. * @since 2.4.8 - 2008-11-04
  2894. * @param int $value
  2895. * @param array $params optional
  2896. * @return bool
  2897. */
  2898. function setPercentComplete( $value, $params=FALSE ) {
  2899. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2900. $this->percentcomplete = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2901. return TRUE;
  2902. }
  2903. /*********************************************************************************/
  2904. /**
  2905. * Property Name: PRIORITY
  2906. */
  2907. /**
  2908. * creates formatted output for calendar component property priority
  2909. *
  2910. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2911. * @since 2.4.8 - 2008-10-21
  2912. * @return string
  2913. */
  2914. function createPriority() {
  2915. if( empty( $this->priority )) return FALSE;
  2916. if( empty( $this->priority['value'] ))
  2917. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
  2918. $attributes = $this->_createParams( $this->priority['params'] );
  2919. return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
  2920. }
  2921. /**
  2922. * set calendar component property priority
  2923. *
  2924. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2925. * @since 2.4.8 - 2008-11-04
  2926. * @param int $value
  2927. * @param array $params optional
  2928. * @return bool
  2929. */
  2930. function setPriority( $value, $params=FALSE ) {
  2931. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2932. $this->priority = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2933. return TRUE;
  2934. }
  2935. /*********************************************************************************/
  2936. /**
  2937. * Property Name: RDATE
  2938. */
  2939. /**
  2940. * creates formatted output for calendar component property rdate
  2941. *
  2942. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2943. * @since 2.4.16 - 2008-10-26
  2944. * @return string
  2945. */
  2946. function createRdate() {
  2947. if( empty( $this->rdate )) return FALSE;
  2948. $utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
  2949. $output = null;
  2950. if( $utctime )
  2951. unset( $this->rdate['params']['TZID'] );
  2952. foreach( $this->rdate as $theRdate ) {
  2953. if( empty( $theRdate['value'] )) {
  2954. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
  2955. continue;
  2956. }
  2957. if( $utctime )
  2958. unset( $theRdate['params']['TZID'] );
  2959. $attributes = $this->_createParams( $theRdate['params'] );
  2960. $cnt = count( $theRdate['value'] );
  2961. $content = null;
  2962. $rno = 1;
  2963. foreach( $theRdate['value'] as $rpix => $rdatePart ) {
  2964. $contentPart = null;
  2965. if( is_array( $rdatePart ) &&
  2966. isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
  2967. if( $utctime )
  2968. unset( $rdatePart[0]['tz'] );
  2969. $formatted = $this->_format_date_time( $rdatePart[0]); // PERIOD part 1
  2970. if( $utctime || !empty( $theRdate['params']['TZID'] ))
  2971. $formatted = str_replace( 'Z', '', $formatted);
  2972. if( 0 < $rpix ) {
  2973. if( !empty( $rdatePart[0]['tz'] ) && $this->_isOffset( $rdatePart[0]['tz'] )) {
  2974. if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
  2975. }
  2976. else
  2977. $formatted = str_replace( 'Z', '', $formatted );
  2978. }
  2979. $contentPart .= $formatted;
  2980. $contentPart .= '/';
  2981. $cnt2 = count( $rdatePart[1]);
  2982. if( array_key_exists( 'year', $rdatePart[1] )) {
  2983. if( array_key_exists( 'hour', $rdatePart[1] ))
  2984. $cnt2 = 7; // date-time
  2985. else
  2986. $cnt2 = 3; // date
  2987. }
  2988. elseif( array_key_exists( 'week', $rdatePart[1] )) // duration
  2989. $cnt2 = 5;
  2990. if(( 7 == $cnt2 ) && // period= -> date-time
  2991. isset( $rdatePart[1]['year'] ) &&
  2992. isset( $rdatePart[1]['month'] ) &&
  2993. isset( $rdatePart[1]['day'] )) {
  2994. if( $utctime )
  2995. unset( $rdatePart[1]['tz'] );
  2996. $formatted = $this->_format_date_time( $rdatePart[1] ); // PERIOD part 2
  2997. if( $utctime || !empty( $theRdate['params']['TZID'] ))
  2998. $formatted = str_replace( 'Z', '', $formatted);
  2999. if( !empty( $rdatePart[0]['tz'] ) && $this->_isOffset( $rdatePart[0]['tz'] )) {
  3000. if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
  3001. }
  3002. else
  3003. $formatted = str_replace( 'Z', '', $formatted );
  3004. $contentPart .= $formatted;
  3005. }
  3006. else { // period= -> dur-time
  3007. $contentPart .= $this->_format_duration( $rdatePart[1] );
  3008. }
  3009. } // PERIOD end
  3010. else { // SINGLE date start
  3011. if( $utctime )
  3012. unset( $rdatePart['tz'] );
  3013. $formatted = $this->_format_date_time( $rdatePart);
  3014. if( $utctime || !empty( $theRdate['params']['TZID'] ))
  3015. $formatted = str_replace( 'Z', '', $formatted);
  3016. if( !$utctime && ( 0 < $rpix )) {
  3017. if( !empty( $theRdate['value'][0]['tz'] ) && $this->_isOffset( $theRdate['value'][0]['tz'] )) {
  3018. if( 'Z' != substr( $formatted, -1 ))
  3019. $formatted .= 'Z';
  3020. }
  3021. else
  3022. $formatted = str_replace( 'Z', '', $formatted );
  3023. }
  3024. $contentPart .= $formatted;
  3025. }
  3026. $content .= $contentPart;
  3027. if( $rno < $cnt )
  3028. $content .= ',';
  3029. $rno++;
  3030. }
  3031. $output .= $this->_createElement( 'RDATE', $attributes, $content );
  3032. }
  3033. return $output;
  3034. }
  3035. /**
  3036. * set calendar component property rdate
  3037. *
  3038. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3039. * @since 2.5.1 - 2008-11-07
  3040. * @param array $rdates
  3041. * @param array $params, optional
  3042. * @param integer $index, optional
  3043. * @return bool
  3044. */
  3045. function setRdate( $rdates, $params=FALSE, $index=FALSE ) {
  3046. if( empty( $rdates )) {
  3047. if( $this->getConfig( 'allowEmpty' )) {
  3048. $this->_setMval( $this->rdate, null, $params, FALSE, $index );
  3049. return TRUE;
  3050. }
  3051. else
  3052. return FALSE;
  3053. }
  3054. $input = array( 'params' => $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
  3055. if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) {
  3056. unset( $input['params']['TZID'] );
  3057. $input['params']['VALUE'] = 'DATE-TIME';
  3058. }
  3059. /* check if PERIOD, if not set */
  3060. if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) &&
  3061. isset( $rdates[0] ) && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) &&
  3062. isset( $rdates[0][0] ) && isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) &&
  3063. (( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) ||
  3064. $this->_isArrayDate( $rdates[0][0] ))) ||
  3065. ( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] ))))) &&
  3066. ( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] ))))))
  3067. $input['params']['VALUE'] = 'PERIOD';
  3068. /* check 1:st date, upd. $parno (opt) and save ev. timezone **/
  3069. $date = reset( $rdates );
  3070. if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD
  3071. $date = reset( $date );
  3072. $this->_chkdatecfg( $date, $parno, $input['params'] );
  3073. if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
  3074. unset( $input['params']['TZID'] );
  3075. $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default
  3076. foreach( $rdates as $rpix => $theRdate ) {
  3077. $inputa = null;
  3078. if( is_array( $theRdate )) {
  3079. if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD
  3080. foreach( $theRdate as $rix => $rPeriod ) {
  3081. if( is_array( $rPeriod )) {
  3082. if( $this->_isArrayTimestampDate( $rPeriod )) // timestamp
  3083. $inputab = ( isset( $rPeriod['tz'] )) ? $this->_timestamp2date( $rPeriod, $parno ) : $this->_timestamp2date( $rPeriod, 6 );
  3084. elseif( $this->_isArrayDate( $rPeriod ))
  3085. $inputab = ( 3 < count ( $rPeriod )) ? $this->_date_time_array( $rPeriod, $parno ) : $this->_date_time_array( $rPeriod, 6 );
  3086. elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) // text-date
  3087. $inputab = $this->_date_time_string( reset( $rPeriod ), $parno );
  3088. else // array format duration
  3089. $inputab = $this->_duration_array( $rPeriod );
  3090. }
  3091. elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
  3092. ( in_array( $rPeriod{0}, array( 'P', '+', '-' )))) {
  3093. if( 'P' != $rPeriod{0} )
  3094. $rPeriod = substr( $rPeriod, 1 );
  3095. $inputab = $this->_duration_string( $rPeriod );
  3096. }
  3097. elseif( 8 <= strlen( trim( $rPeriod ))) // text date ex. 2006-08-03 10:12:18
  3098. $inputab = $this->_date_time_string( $rPeriod, $parno );
  3099. if( isset( $input['params']['TZID'] ) ||
  3100. ( isset( $inputab['tz'] ) && !$this->_isOffset( $inputab['tz'] )) ||
  3101. ( isset( $inputa[0] ) && ( !isset( $inputa[0]['tz'] ))) ||
  3102. ( isset( $inputa[0]['tz'] ) && !$this->_isOffset( $inputa[0]['tz'] )))
  3103. unset( $inputab['tz'] );
  3104. $inputa[] = $inputab;
  3105. }
  3106. } // PERIOD end
  3107. elseif ( $this->_isArrayTimestampDate( $theRdate )) // timestamp
  3108. $inputa = $this->_timestamp2date( $theRdate, $parno );
  3109. else // date[-time]
  3110. $inputa = $this->_date_time_array( $theRdate, $parno );
  3111. }
  3112. elseif( 8 <= strlen( trim( $theRdate ))) // text date ex. 2006-08-03 10:12:18
  3113. $inputa = $this->_date_time_string( $theRdate, $parno );
  3114. if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
  3115. if( 3 == $parno )
  3116. unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
  3117. elseif( isset( $inputa['tz'] ))
  3118. $inputa['tz'] = (string) $inputa['tz'];
  3119. if( isset( $input['params']['TZID'] ) ||
  3120. ( isset( $inputa['tz'] ) && !$this->_isOffset( $inputa['tz'] )) ||
  3121. ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
  3122. ( isset( $input['value'][0]['tz'] ) && !$this->_isOffset( $input['value'][0]['tz'] )))
  3123. unset( $inputa['tz'] );
  3124. }
  3125. $input['value'][] = $inputa;
  3126. }
  3127. if( 3 == $parno ) {
  3128. $input['params']['VALUE'] = 'DATE';
  3129. unset( $input['params']['TZID'] );
  3130. }
  3131. $this->_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index );
  3132. return TRUE;
  3133. }
  3134. /*********************************************************************************/
  3135. /**
  3136. * Property Name: RECURRENCE-ID
  3137. */
  3138. /**
  3139. * creates formatted output for calendar component property recurrence-id
  3140. *
  3141. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3142. * @since 2.4.8 - 2008-10-21
  3143. * @return string
  3144. */
  3145. function createRecurrenceid() {
  3146. if( empty( $this->recurrenceid )) return FALSE;
  3147. if( empty( $this->recurrenceid['value'] ))
  3148. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
  3149. $formatted = $this->_format_date_time( $this->recurrenceid['value'] );
  3150. $attributes = $this->_createParams( $this->recurrenceid['params'] );
  3151. return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
  3152. }
  3153. /**
  3154. * set calendar component property recurrence-id
  3155. *
  3156. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3157. * @since 2.4.8 - 2008-10-23
  3158. * @param mixed $year
  3159. * @param mixed $month optional
  3160. * @param int $day optional
  3161. * @param int $hour optional
  3162. * @param int $min optional
  3163. * @param int $sec optional
  3164. * @param array $params optional
  3165. * @return bool
  3166. */
  3167. function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  3168. if( empty( $year )) {
  3169. if( $this->getConfig( 'allowEmpty' )) {
  3170. $this->recurrenceid = array( 'value' => null, 'params' => null );
  3171. return TRUE;
  3172. }
  3173. else
  3174. return FALSE;
  3175. }
  3176. $this->recurrenceid = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
  3177. return TRUE;
  3178. }
  3179. /*********************************************************************************/
  3180. /**
  3181. * Property Name: RELATED-TO
  3182. */
  3183. /**
  3184. * creates formatted output for calendar component property related-to
  3185. *
  3186. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3187. * @since 2.4.8 - 2008-10-23
  3188. * @return string
  3189. */
  3190. function createRelatedTo() {
  3191. if( empty( $this->relatedto )) return FALSE;
  3192. $output = null;
  3193. foreach( $this->relatedto as $relation ) {
  3194. if( empty( $relation['value'] )) {
  3195. if( $this->getConfig( 'allowEmpty' )) $output.= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ));
  3196. continue;
  3197. }
  3198. $attributes = $this->_createParams( $relation['params'] );
  3199. $content = ( 'xcal' != $this->format ) ? '<' : '';
  3200. $content .= $this->_strrep( $relation['value'] );
  3201. $content .= ( 'xcal' != $this->format ) ? '>' : '';
  3202. $output .= $this->_createElement( 'RELATED-TO', $attributes, $content );
  3203. }
  3204. return $output;
  3205. }
  3206. /**
  3207. * set calendar component property related-to
  3208. *
  3209. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3210. * @since 2.5.1 - 2008-11-07
  3211. * @param float $relid
  3212. * @param array $params, optional
  3213. * @param index $index, optional
  3214. * @return bool
  3215. */
  3216. function setRelatedTo( $value, $params=FALSE, $index=FALSE ) {
  3217. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3218. if(( '<' == substr( $value, 0, 1 )) && ( '>' == substr( $value, -1 )))
  3219. $value = substr( $value, 1, ( strlen( $value ) - 2 ));
  3220. $this->_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default
  3221. $this->_setMval( $this->relatedto, $value, $params, FALSE, $index );
  3222. return TRUE;
  3223. }
  3224. /*********************************************************************************/
  3225. /**
  3226. * Property Name: REPEAT
  3227. */
  3228. /**
  3229. * creates formatted output for calendar component property repeat
  3230. *
  3231. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3232. * @since 2.4.8 - 2008-10-21
  3233. * @return string
  3234. */
  3235. function createRepeat() {
  3236. if( empty( $this->repeat )) return FALSE;
  3237. if( empty( $this->repeat['value'] ))
  3238. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE;
  3239. $attributes = $this->_createParams( $this->repeat['params'] );
  3240. return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] );
  3241. }
  3242. /**
  3243. * set calendar component property transp
  3244. *
  3245. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3246. * @since 2.4.8 - 2008-11-04
  3247. * @param string $value
  3248. * @param array $params optional
  3249. * @return void
  3250. */
  3251. function setRepeat( $value, $params=FALSE ) {
  3252. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3253. $this->repeat = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3254. return TRUE;
  3255. }
  3256. /*********************************************************************************/
  3257. /**
  3258. * Property Name: REQUEST-STATUS
  3259. */
  3260. /**
  3261. * creates formatted output for calendar component property request-status
  3262. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3263. * @since 2.4.8 - 2008-10-23
  3264. * @return string
  3265. */
  3266. function createRequestStatus() {
  3267. if( empty( $this->requeststatus )) return FALSE;
  3268. $output = null;
  3269. foreach( $this->requeststatus as $rstat ) {
  3270. if( empty( $rstat['value']['statcode'] )) {
  3271. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' );
  3272. continue;
  3273. }
  3274. $attributes = $this->_createParams( $rstat['params'], array( 'LANGUAGE' ));
  3275. $content = number_format( (float) $rstat['value']['statcode'], 2, '.', '');
  3276. $content .= ';'.$this->_strrep( $rstat['value']['text'] );
  3277. if( isset( $rstat['value']['extdata'] ))
  3278. $content .= ';'.$this->_strrep( $rstat['value']['extdata'] );
  3279. $output .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content );
  3280. }
  3281. return $output;
  3282. }
  3283. /**
  3284. * set calendar component property request-status
  3285. *
  3286. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3287. * @since 2.5.1 - 2008-11-05
  3288. * @param float $statcode
  3289. * @param string $text
  3290. * @param string $extdata, optional
  3291. * @param array $params, optional
  3292. * @param integer $index, optional
  3293. * @return bool
  3294. */
  3295. function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) {
  3296. if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = null; else return FALSE;
  3297. $input = array( 'statcode' => $statcode, 'text' => $text );
  3298. if( $extdata )
  3299. $input['extdata'] = $extdata;
  3300. $this->_setMval( $this->requeststatus, $input, $params, FALSE, $index );
  3301. return TRUE;
  3302. }
  3303. /*********************************************************************************/
  3304. /**
  3305. * Property Name: RESOURCES
  3306. */
  3307. /**
  3308. * creates formatted output for calendar component property resources
  3309. *
  3310. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3311. * @since 2.4.8 - 2008-10-23
  3312. * @return string
  3313. */
  3314. function createResources() {
  3315. if( empty( $this->resources )) return FALSE;
  3316. $output = null;
  3317. foreach( $this->resources as $resource ) {
  3318. if( empty( $resource['value'] )) {
  3319. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
  3320. continue;
  3321. }
  3322. $attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
  3323. if( is_array( $resource['value'] )) {
  3324. foreach( $resource['value'] as $rix => $resourcePart )
  3325. $resource['value'][$rix] = $this->_strrep( $resourcePart );
  3326. $content = implode( ',', $resource['value'] );
  3327. }
  3328. else
  3329. $content = $this->_strrep( $resource['value'] );
  3330. $output .= $this->_createElement( 'RESOURCES', $attributes, $content );
  3331. }
  3332. return $output;
  3333. }
  3334. /**
  3335. * set calendar component property recources
  3336. *
  3337. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3338. * @since 2.5.1 - 2008-11-05
  3339. * @param mixed $value
  3340. * @param array $params, optional
  3341. * @param integer $index, optional
  3342. * @return bool
  3343. */
  3344. function setResources( $value, $params=FALSE, $index=FALSE ) {
  3345. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3346. $this->_setMval( $this->resources, $value, $params, FALSE, $index );
  3347. return TRUE;
  3348. }
  3349. /*********************************************************************************/
  3350. /**
  3351. * Property Name: RRULE
  3352. */
  3353. /**
  3354. * creates formatted output for calendar component property rrule
  3355. *
  3356. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3357. * @since 2.4.8 - 2008-10-21
  3358. * @return string
  3359. */
  3360. function createRrule() {
  3361. if( empty( $this->rrule )) return FALSE;
  3362. return $this->_format_recur( 'RRULE', $this->rrule );
  3363. }
  3364. /**
  3365. * set calendar component property rrule
  3366. *
  3367. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3368. * @since 2.5.1 - 2008-11-05
  3369. * @param array $rruleset
  3370. * @param array $params, optional
  3371. * @param integer $index, optional
  3372. * @return void
  3373. */
  3374. function setRrule( $rruleset, $params=FALSE, $index=FALSE ) {
  3375. if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = null; else return FALSE;
  3376. $this->_setMval( $this->rrule, $this->_setRexrule( $rruleset ), $params, FALSE, $index );
  3377. return TRUE;
  3378. }
  3379. /*********************************************************************************/
  3380. /**
  3381. * Property Name: SEQUENCE
  3382. */
  3383. /**
  3384. * creates formatted output for calendar component property sequence
  3385. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3386. * @since 0.9.7 - 2006-11-20
  3387. * @return string
  3388. */
  3389. function createSequence() {
  3390. if( empty( $this->sequence )) return FALSE;
  3391. if( empty( $this->sequence['value'] ))
  3392. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
  3393. $attributes = $this->_createParams( $this->sequence['params'] );
  3394. return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
  3395. }
  3396. /**
  3397. * set calendar component property sequence
  3398. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3399. * @since 2.4.8 - 2008-11-04
  3400. * @param int $value optional
  3401. * @param array $params optional
  3402. * @return bool
  3403. */
  3404. function setSequence( $value=FALSE, $params=FALSE ) {
  3405. if( empty( $value ))
  3406. $value = ( isset( $this->sequence['value'] ) && ( 0 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : 1;
  3407. $this->sequence = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3408. return TRUE;
  3409. }
  3410. /*********************************************************************************/
  3411. /**
  3412. * Property Name: STATUS
  3413. */
  3414. /**
  3415. * creates formatted output for calendar component property status
  3416. *
  3417. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3418. * @since 2.4.8 - 2008-10-21
  3419. * @return string
  3420. */
  3421. function createStatus() {
  3422. if( empty( $this->status )) return FALSE;
  3423. if( empty( $this->status['value'] ))
  3424. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
  3425. $attributes = $this->_createParams( $this->status['params'] );
  3426. return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
  3427. }
  3428. /**
  3429. * set calendar component property status
  3430. *
  3431. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3432. * @since 2.4.8 - 2008-11-04
  3433. * @param string $value
  3434. * @param array $params optional
  3435. * @return bool
  3436. */
  3437. function setStatus( $value, $params=FALSE ) {
  3438. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3439. $this->status = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3440. return TRUE;
  3441. }
  3442. /*********************************************************************************/
  3443. /**
  3444. * Property Name: SUMMARY
  3445. */
  3446. /**
  3447. * creates formatted output for calendar component property summary
  3448. *
  3449. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3450. * @since 2.4.8 - 2008-10-21
  3451. * @return string
  3452. */
  3453. function createSummary() {
  3454. if( empty( $this->summary )) return FALSE;
  3455. if( empty( $this->summary['value'] ))
  3456. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
  3457. $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
  3458. $content = $this->_strrep( $this->summary['value'] );
  3459. return $this->_createElement( 'SUMMARY', $attributes, $content );
  3460. }
  3461. /**
  3462. * set calendar component property summary
  3463. *
  3464. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3465. * @since 2.4.8 - 2008-11-04
  3466. * @param string $value
  3467. * @param string $params optional
  3468. * @return bool
  3469. */
  3470. function setSummary( $value, $params=FALSE ) {
  3471. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3472. $this->summary = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3473. return TRUE;
  3474. }
  3475. /*********************************************************************************/
  3476. /**
  3477. * Property Name: TRANSP
  3478. */
  3479. /**
  3480. * creates formatted output for calendar component property transp
  3481. *
  3482. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3483. * @since 2.4.8 - 2008-10-21
  3484. * @return string
  3485. */
  3486. function createTransp() {
  3487. if( empty( $this->transp )) return FALSE;
  3488. if( empty( $this->transp['value'] ))
  3489. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE;
  3490. $attributes = $this->_createParams( $this->transp['params'] );
  3491. return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] );
  3492. }
  3493. /**
  3494. * set calendar component property transp
  3495. *
  3496. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3497. * @since 2.4.8 - 2008-11-04
  3498. * @param string $value
  3499. * @param string $params optional
  3500. * @return bool
  3501. */
  3502. function setTransp( $value, $params=FALSE ) {
  3503. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3504. $this->transp = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3505. return TRUE;
  3506. }
  3507. /*********************************************************************************/
  3508. /**
  3509. * Property Name: TRIGGER
  3510. */
  3511. /**
  3512. * creates formatted output for calendar component property trigger
  3513. *
  3514. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3515. * @since 2.4.16 - 2008-10-21
  3516. * @return string
  3517. */
  3518. function createTrigger() {
  3519. if( empty( $this->trigger )) return FALSE;
  3520. if( empty( $this->trigger['value'] ))
  3521. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE;
  3522. $content = $attributes = null;
  3523. if( isset( $this->trigger['value']['year'] ) &&
  3524. isset( $this->trigger['value']['month'] ) &&
  3525. isset( $this->trigger['value']['day'] ))
  3526. $content .= $this->_format_date_time( $this->trigger['value'] );
  3527. else {
  3528. if( TRUE !== $this->trigger['value']['relatedStart'] )
  3529. $attributes .= $this->intAttrDelimiter.'RELATED=END';
  3530. if( $this->trigger['value']['before'] )
  3531. $content .= '-';
  3532. $content .= $this->_format_duration( $this->trigger['value'] );
  3533. }
  3534. $attributes .= $this->_createParams( $this->trigger['params'] );
  3535. return $this->_createElement( 'TRIGGER', $attributes, $content );
  3536. }
  3537. /**
  3538. * set calendar component property trigger
  3539. *
  3540. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3541. * @since 2.4.16 - 2008-11-04
  3542. * @param mixed $year
  3543. * @param mixed $month optional
  3544. * @param int $day optional
  3545. * @param int $week optional
  3546. * @param int $hour optional
  3547. * @param int $min optional
  3548. * @param int $sec optional
  3549. * @param bool $relatedStart optional
  3550. * @param bool $before optional
  3551. * @param array $params optional
  3552. * @return bool
  3553. */
  3554. function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) {
  3555. if( empty( $year ) && empty( $month ) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec ))
  3556. if( $this->getConfig( 'allowEmpty' )) {
  3557. $this->trigger = array( 'value' => null, 'params' => $this->_setParams( $params ) );
  3558. return TRUE;
  3559. }
  3560. else
  3561. return FALSE;
  3562. if( $this->_isArrayTimestampDate( $year )) { // timestamp
  3563. $params = $this->_setParams( $month );
  3564. $date = $this->_timestamp2date( $year, 7 );
  3565. foreach( $date as $k => $v )
  3566. $$k = $v;
  3567. }
  3568. elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) {
  3569. $params = $this->_setParams( $month );
  3570. if(!(array_key_exists( 'year', $year ) && // exclude date-time
  3571. array_key_exists( 'month', $year ) &&
  3572. array_key_exists( 'day', $year ))) { // so this must be a duration
  3573. if( isset( $params['RELATED'] ) && ( 'END' == $params['RELATED'] ))
  3574. $relatedStart = FALSE;
  3575. else
  3576. $relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE;
  3577. $before = ( array_key_exists( 'before', $year ) && ( TRUE !== $year['before'] )) ? FALSE : TRUE;
  3578. }
  3579. $SSYY = ( array_key_exists( 'year', $year )) ? $year['year'] : null;
  3580. $month = ( array_key_exists( 'month', $year )) ? $year['month'] : null;
  3581. $day = ( array_key_exists( 'day', $year )) ? $year['day'] : null;
  3582. $week = ( array_key_exists( 'week', $year )) ? $year['week'] : null;
  3583. $hour = ( array_key_exists( 'hour', $year )) ? $year['hour'] : 0; //null;
  3584. $min = ( array_key_exists( 'min', $year )) ? $year['min'] : 0; //null;
  3585. $sec = ( array_key_exists( 'sec', $year )) ? $year['sec'] : 0; //null;
  3586. $year = $SSYY;
  3587. }
  3588. elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) { // duration or date in a string
  3589. $params = $this->_setParams( $month );
  3590. if( in_array( $year{0}, array( 'P', '+', '-' ))) { // duration
  3591. $relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == $params['RELATED'] )) ? FALSE : TRUE;
  3592. $before = ( '-' == $year{0} ) ? TRUE : FALSE;
  3593. if( 'P' != $year{0} )
  3594. $year = substr( $year, 1 );
  3595. $date = $this->_duration_string( $year);
  3596. }
  3597. else // date
  3598. $date = $this->_date_time_string( $year, 7 );
  3599. unset( $year, $month, $day );
  3600. foreach( $date as $k => $v )
  3601. $$k = $v;
  3602. }
  3603. else // single values in function input parameters
  3604. $params = $this->_setParams( $params );
  3605. if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date
  3606. $params['VALUE'] = 'DATE-TIME';
  3607. $hour = ( $hour ) ? $hour : 0;
  3608. $min = ( $min ) ? $min : 0;
  3609. $sec = ( $sec ) ? $sec : 0;
  3610. $this->trigger = array( 'params' => $params );
  3611. $this->trigger['value'] = array( 'year' => $year
  3612. , 'month' => $month
  3613. , 'day' => $day
  3614. , 'hour' => $hour
  3615. , 'min' => $min
  3616. , 'sec' => $sec
  3617. , 'tz' => 'Z' );
  3618. return TRUE;
  3619. }
  3620. elseif(( empty( $year ) && empty( $month )) && // duration
  3621. (!empty( $week ) || !empty( $day ) || !empty( $hour ) || !empty( $min ) || !empty( $sec ))) {
  3622. unset( $params['RELATED'] ); // set at output creation (END only)
  3623. unset( $params['VALUE'] ); // 'DURATION' default
  3624. $this->trigger = array( 'params' => $params );
  3625. $relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE;
  3626. $before = ( FALSE !== $before ) ? TRUE : FALSE;
  3627. $this->trigger['value'] = array( 'relatedStart' => $relatedStart
  3628. , 'before' => $before );
  3629. if( !empty( $week )) $this->trigger['value']['week'] = $week;
  3630. if( !empty( $day )) $this->trigger['value']['day'] = $day;
  3631. if( !empty( $hour )) $this->trigger['value']['hour'] = $hour;
  3632. if( !empty( $min )) $this->trigger['value']['min'] = $min;
  3633. if( !empty( $sec )) $this->trigger['value']['sec'] = $sec;
  3634. return TRUE;
  3635. }
  3636. return FALSE;
  3637. }
  3638. /*********************************************************************************/
  3639. /**
  3640. * Property Name: TZID
  3641. */
  3642. /**
  3643. * creates formatted output for calendar component property tzid
  3644. *
  3645. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3646. * @since 2.4.8 - 2008-10-21
  3647. * @return string
  3648. */
  3649. function createTzid() {
  3650. if( empty( $this->tzid )) return FALSE;
  3651. if( empty( $this->tzid['value'] ))
  3652. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
  3653. $attributes = $this->_createParams( $this->tzid['params'] );
  3654. return $this->_createElement( 'TZID', $attributes, $this->_strrep( $this->tzid['value'] ));
  3655. }
  3656. /**
  3657. * set calendar component property tzid
  3658. *
  3659. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3660. * @since 2.4.8 - 2008-11-04
  3661. * @param string $value
  3662. * @param array $params optional
  3663. * @return bool
  3664. */
  3665. function setTzid( $value, $params=FALSE ) {
  3666. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3667. $this->tzid = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3668. return TRUE;
  3669. }
  3670. /*********************************************************************************/
  3671. /**
  3672. * .. .
  3673. * Property Name: TZNAME
  3674. */
  3675. /**
  3676. * creates formatted output for calendar component property tzname
  3677. *
  3678. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3679. * @since 2.4.8 - 2008-10-21
  3680. * @return string
  3681. */
  3682. function createTzname() {
  3683. if( empty( $this->tzname )) return FALSE;
  3684. $output = null;
  3685. foreach( $this->tzname as $theName ) {
  3686. if( !empty( $theName['value'] )) {
  3687. $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
  3688. $output .= $this->_createElement( 'TZNAME', $attributes, $this->_strrep( $theName['value'] ));
  3689. }
  3690. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
  3691. }
  3692. return $output;
  3693. }
  3694. /**
  3695. * set calendar component property tzname
  3696. *
  3697. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3698. * @since 2.5.1 - 2008-11-05
  3699. * @param string $value
  3700. * @param string $params, optional
  3701. * @param integer $index, optional
  3702. * @return bool
  3703. */
  3704. function setTzname( $value, $params=FALSE, $index=FALSE ) {
  3705. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3706. $this->_setMval( $this->tzname, $value, $params, FALSE, $index );
  3707. return TRUE;
  3708. }
  3709. /*********************************************************************************/
  3710. /**
  3711. * Property Name: TZOFFSETFROM
  3712. */
  3713. /**
  3714. * creates formatted output for calendar component property tzoffsetfrom
  3715. *
  3716. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3717. * @since 2.4.8 - 2008-10-21
  3718. * @return string
  3719. */
  3720. function createTzoffsetfrom() {
  3721. if( empty( $this->tzoffsetfrom )) return FALSE;
  3722. if( empty( $this->tzoffsetfrom['value'] ))
  3723. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
  3724. $attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
  3725. return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
  3726. }
  3727. /**
  3728. * set calendar component property tzoffsetfrom
  3729. *
  3730. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3731. * @since 2.4.8 - 2008-11-04
  3732. * @param string $value
  3733. * @param string $params optional
  3734. * @return bool
  3735. */
  3736. function setTzoffsetfrom( $value, $params=FALSE ) {
  3737. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3738. $this->tzoffsetfrom = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3739. return TRUE;
  3740. }
  3741. /*********************************************************************************/
  3742. /**
  3743. * Property Name: TZOFFSETTO
  3744. */
  3745. /**
  3746. * creates formatted output for calendar component property tzoffsetto
  3747. *
  3748. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3749. * @since 2.4.8 - 2008-10-21
  3750. * @return string
  3751. */
  3752. function createTzoffsetto() {
  3753. if( empty( $this->tzoffsetto )) return FALSE;
  3754. if( empty( $this->tzoffsetto['value'] ))
  3755. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
  3756. $attributes = $this->_createParams( $this->tzoffsetto['params'] );
  3757. return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
  3758. }
  3759. /**
  3760. * set calendar component property tzoffsetto
  3761. *
  3762. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3763. * @since 2.4.8 - 2008-11-04
  3764. * @param string $value
  3765. * @param string $params optional
  3766. * @return bool
  3767. */
  3768. function setTzoffsetto( $value, $params=FALSE ) {
  3769. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3770. $this->tzoffsetto = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3771. return TRUE;
  3772. }
  3773. /*********************************************************************************/
  3774. /**
  3775. * Property Name: TZURL
  3776. */
  3777. /**
  3778. * creates formatted output for calendar component property tzurl
  3779. *
  3780. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3781. * @since 2.4.8 - 2008-10-21
  3782. * @return string
  3783. */
  3784. function createTzurl() {
  3785. if( empty( $this->tzurl )) return FALSE;
  3786. if( empty( $this->tzurl['value'] ))
  3787. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
  3788. $attributes = $this->_createParams( $this->tzurl['params'] );
  3789. return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
  3790. }
  3791. /**
  3792. * set calendar component property tzurl
  3793. *
  3794. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3795. * @since 2.4.8 - 2008-11-04
  3796. * @param string $value
  3797. * @param string $params optional
  3798. * @return boll
  3799. */
  3800. function setTzurl( $value, $params=FALSE ) {
  3801. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3802. $this->tzurl = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3803. return TRUE;
  3804. }
  3805. /*********************************************************************************/
  3806. /**
  3807. * Property Name: UID
  3808. */
  3809. /**
  3810. * creates formatted output for calendar component property uid
  3811. *
  3812. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3813. * @since 0.9.7 - 2006-11-20
  3814. * @return string
  3815. */
  3816. function createUid() {
  3817. if( 0 >= count( $this->uid ))
  3818. $this->_makeuid();
  3819. $attributes = $this->_createParams( $this->uid['params'] );
  3820. return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
  3821. }
  3822. /**
  3823. * create an unique id for this calendar component object instance
  3824. *
  3825. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3826. * @since 2.2.7 - 2007-09-04
  3827. * @return void
  3828. */
  3829. function _makeUid() {
  3830. $date = date('Ymd\THisT');
  3831. $unique = substr(microtime(), 2, 4);
  3832. $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
  3833. $start = 0;
  3834. $end = strlen( $base ) - 1;
  3835. $length = 6;
  3836. $str = null;
  3837. for( $p = 0; $p < $length; $p++ )
  3838. $unique .= $base{mt_rand( $start, $end )};
  3839. $this->uid = array( 'params' => null );
  3840. $this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
  3841. }
  3842. /**
  3843. * set calendar component property uid
  3844. *
  3845. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3846. * @since 2.4.8 - 2008-11-04
  3847. * @param string $value
  3848. * @param string $params optional
  3849. * @return bool
  3850. */
  3851. function setUid( $value, $params=FALSE ) {
  3852. if( empty( $value )) return FALSE; // no allowEmpty check here !!!!
  3853. $this->uid = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3854. return TRUE;
  3855. }
  3856. /*********************************************************************************/
  3857. /**
  3858. * Property Name: URL
  3859. */
  3860. /**
  3861. * creates formatted output for calendar component property url
  3862. *
  3863. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3864. * @since 2.4.8 - 2008-10-21
  3865. * @return string
  3866. */
  3867. function createUrl() {
  3868. if( empty( $this->url )) return FALSE;
  3869. if( empty( $this->url['value'] ))
  3870. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
  3871. $attributes = $this->_createParams( $this->url['params'] );
  3872. return $this->_createElement( 'URL', $attributes, $this->url['value'] );
  3873. }
  3874. /**
  3875. * set calendar component property url
  3876. *
  3877. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3878. * @since 2.4.8 - 2008-11-04
  3879. * @param string $value
  3880. * @param string $params optional
  3881. * @return bool
  3882. */
  3883. function setUrl( $value, $params=FALSE ) {
  3884. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3885. $this->url = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3886. return TRUE;
  3887. }
  3888. /*********************************************************************************/
  3889. /**
  3890. * Property Name: x-prop
  3891. */
  3892. /**
  3893. * creates formatted output for calendar component property x-prop
  3894. *
  3895. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3896. * @since 2.4.11 - 2008-10-22
  3897. * @return string
  3898. */
  3899. function createXprop() {
  3900. if( empty( $this->xprop )) return FALSE;
  3901. $output = null;
  3902. foreach( $this->xprop as $label => $xpropPart ) {
  3903. if( empty( $xpropPart['value'] )) {
  3904. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label );
  3905. continue;
  3906. }
  3907. $attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
  3908. if( is_array( $xpropPart['value'] )) {
  3909. foreach( $xpropPart['value'] as $pix => $theXpart )
  3910. $xpropPart['value'][$pix] = $this->_strrep( $theXpart );
  3911. $xpropPart['value'] = implode( ',', $xpropPart['value'] );
  3912. }
  3913. else
  3914. $xpropPart['value'] = $this->_strrep( $xpropPart['value'] );
  3915. $output .= $this->_createElement( $label, $attributes, $xpropPart['value'] );
  3916. }
  3917. return $output;
  3918. }
  3919. /**
  3920. * set calendar component property x-prop
  3921. *
  3922. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3923. * @since 2.4.11 - 2008-11-04
  3924. * @param string $label
  3925. * @param mixed $value
  3926. * @param array $params optional
  3927. * @return bool
  3928. */
  3929. function setXprop( $label, $value, $params=FALSE ) {
  3930. if( empty( $label )) return;
  3931. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3932. $xprop = array( 'value' => $value );
  3933. $toolbox = new calendarComponent();
  3934. $xprop['params'] = $toolbox->_setParams( $params );
  3935. if( !is_array( $this->xprop )) $this->xprop = array();
  3936. $this->xprop[strtoupper( $label )] = $xprop;
  3937. return TRUE;
  3938. }
  3939. /*********************************************************************************/
  3940. /*********************************************************************************/
  3941. /**
  3942. * create element format parts
  3943. *
  3944. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3945. * @since 2.0.6 - 2006-06-20
  3946. * @return string
  3947. */
  3948. function _createFormat() {
  3949. $objectname = null;
  3950. switch( $this->format ) {
  3951. case 'xcal':
  3952. $objectname = ( isset( $this->timezonetype )) ?
  3953. strtolower( $this->timezonetype ) : strtolower( $this->objName );
  3954. $this->componentStart1 = $this->elementStart1 = '<';
  3955. $this->componentStart2 = $this->elementStart2 = '>';
  3956. $this->componentEnd1 = $this->elementEnd1 = '</';
  3957. $this->componentEnd2 = $this->elementEnd2 = '>'.$this->nl;
  3958. $this->intAttrDelimiter = '<!-- -->';
  3959. $this->attributeDelimiter = $this->nl;
  3960. $this->valueInit = null;
  3961. break;
  3962. default:
  3963. $objectname = ( isset( $this->timezonetype )) ?
  3964. strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
  3965. $this->componentStart1 = 'BEGIN:';
  3966. $this->componentStart2 = null;
  3967. $this->componentEnd1 = 'END:';
  3968. $this->componentEnd2 = $this->nl;
  3969. $this->elementStart1 = null;
  3970. $this->elementStart2 = null;
  3971. $this->elementEnd1 = null;
  3972. $this->elementEnd2 = $this->nl;
  3973. $this->intAttrDelimiter = '<!-- -->';
  3974. $this->attributeDelimiter = ';';
  3975. $this->valueInit = ':';
  3976. break;
  3977. }
  3978. return $objectname;
  3979. }
  3980. /**
  3981. * creates formatted output for calendar component property
  3982. *
  3983. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3984. * @since 2.4.8 - 2008-10-23
  3985. * @param string $label property name
  3986. * @param string $attributes property attributes
  3987. * @param string $content property content (optional)
  3988. * @return string
  3989. */
  3990. function _createElement( $label, $attributes=null, $content=FALSE ) {
  3991. $label = $this->_formatPropertyName( $label );
  3992. $output = $this->elementStart1.$label;
  3993. $categoriesAttrLang = null;
  3994. $attachInlineBinary = FALSE;
  3995. $attachfmttype = null;
  3996. if( !empty( $attributes )) {
  3997. $attributes = trim( $attributes );
  3998. if ( 'xcal' == $this->format) {
  3999. $attributes2 = explode( $this->intAttrDelimiter, $attributes );
  4000. $attributes = null;
  4001. foreach( $attributes2 as $attribute ) {
  4002. $attrKVarr = explode( '=', $attribute );
  4003. if( empty( $attrKVarr[0] ))
  4004. continue;
  4005. if( !isset( $attrKVarr[1] )) {
  4006. $attrValue = $attrKVarr[0];
  4007. $attrKey = null;
  4008. }
  4009. elseif( 2 == count( $attrKVarr)) {
  4010. $attrKey = strtolower( $attrKVarr[0] );
  4011. $attrValue = $attrKVarr[1];
  4012. }
  4013. else {
  4014. $attrKey = strtolower( $attrKVarr[0] );
  4015. unset( $attrKVarr[0] );
  4016. $attrValue = implode( '=', $attrKVarr );
  4017. }
  4018. if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) {
  4019. $attachInlineBinary = TRUE;
  4020. if( 'fmttype' == $attrKey )
  4021. $attachfmttype = $attrKey.'='.$attrValue;
  4022. continue;
  4023. }
  4024. elseif(( 'categories' == $label ) && ( 'language' == $attrKey ))
  4025. $categoriesAttrLang = $attrKey.'='.$attrValue;
  4026. else {
  4027. $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
  4028. $attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null;
  4029. if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) {
  4030. $attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 ));
  4031. $attrValue = str_replace( '"', '', $attrValue );
  4032. }
  4033. $attributes .= '"'.htmlspecialchars( $attrValue ).'"';
  4034. }
  4035. }
  4036. }
  4037. else {
  4038. $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
  4039. }
  4040. }
  4041. if(((( 'attach' == $label ) && !$attachInlineBinary ) ||
  4042. ( in_array( $label, array( 'tzurl', 'url' )))) && ( 'xcal' == $this->format)) {
  4043. $pos = strrpos($content, "/");
  4044. $docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content;
  4045. $this->xcaldecl[] = array( 'xmldecl' => 'ENTITY'
  4046. , 'uri' => $docname
  4047. , 'ref' => 'SYSTEM'
  4048. , 'external' => $content
  4049. , 'type' => 'NDATA'
  4050. , 'type2' => 'BINERY' );
  4051. $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
  4052. $attributes .= 'uri="'.$docname.'"';
  4053. $content = null;
  4054. if( 'attach' == $label ) {
  4055. $attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes );
  4056. $content = $this->_createElement( 'extref', $attributes, null );
  4057. $attributes = null;
  4058. }
  4059. }
  4060. elseif(( 'attach' == $label ) && $attachInlineBinary && ( 'xcal' == $this->format)) {
  4061. $content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute
  4062. }
  4063. $output .= $attributes;
  4064. if( !$content ) {
  4065. switch( $this->format ) {
  4066. case 'xcal':
  4067. $output .= ' /';
  4068. $output .= $this->elementStart2;
  4069. return $output;
  4070. break;
  4071. default:
  4072. $output .= $this->elementStart2.$this->valueInit;
  4073. return $this->_size75( $output );
  4074. break;
  4075. }
  4076. }
  4077. $output .= $this->elementStart2;
  4078. $output .= $this->valueInit.$content;
  4079. switch( $this->format ) {
  4080. case 'xcal':
  4081. return $output.$this->elementEnd1.$label.$this->elementEnd2;
  4082. break;
  4083. default:
  4084. return $this->_size75( $output );
  4085. break;
  4086. }
  4087. }
  4088. /**
  4089. * creates formatted output for calendar component property parameters
  4090. *
  4091. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4092. * @since 0.9.22 - 2007-04-10
  4093. * @param array $params optional
  4094. * @param array $ctrKeys optional
  4095. * @return string
  4096. */
  4097. function _createParams( $params=array(), $ctrKeys=array() ) {
  4098. $attrLANG = $attr1 = $attr2 = null;
  4099. $CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ;
  4100. $LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ;
  4101. $CNattrExist = $LANGattrExist = FALSE;
  4102. if( is_array( $params )) {
  4103. foreach( $params as $paramKey => $paramValue ) {
  4104. if( is_int( $paramKey ))
  4105. $attr2 .= $this->intAttrDelimiter.$paramValue;
  4106. elseif(( 'LANGUAGE' == $paramKey ) && $LANGattrKey ) {
  4107. $attrLANG .= $this->intAttrDelimiter."LANGUAGE=$paramValue";
  4108. $LANGattrExist = TRUE;
  4109. }
  4110. elseif(( 'CN' == $paramKey ) && $CNattrKey ) {
  4111. $attr1 = $this->intAttrDelimiter.'CN="'.$paramValue.'"';
  4112. $CNattrExist = TRUE;
  4113. }
  4114. elseif(( 'ALTREP' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
  4115. $attr2 .= $this->intAttrDelimiter.'ALTREP="'.$paramValue.'"';
  4116. elseif(( 'DIR' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
  4117. $attr2 .= $this->intAttrDelimiter.'DIR="'.$paramValue.'"';
  4118. elseif(( 'SENT-BY' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
  4119. $attr2 .= $this->intAttrDelimiter.'SENT-BY="MAILTO:'.$paramValue.'"';
  4120. else
  4121. $attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue";
  4122. }
  4123. }
  4124. if( !$LANGattrExist ) {
  4125. $lang = $this->getConfig( 'language' );
  4126. if(( $CNattrExist || $LANGattrKey ) && $lang )
  4127. $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang;
  4128. }
  4129. return $attrLANG.$attr1.$attr2;
  4130. }
  4131. /**
  4132. * check a date(-time) for an opt. timezone and if it is a DATE-TIME or DATE
  4133. *
  4134. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4135. * @since 2.4.16 - 2008-10-25
  4136. * @param array $date, date to check
  4137. * @param int $parno, no of date parts (i.e. year, month.. .)
  4138. * @return array $params, property parameters
  4139. */
  4140. function _chkdatecfg( $theDate, & $parno, & $params ) {
  4141. if( isset( $params['TZID'] ))
  4142. $parno = 6;
  4143. elseif( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] ))
  4144. $parno = 3;
  4145. else {
  4146. if( isset( $params['VALUE'] ) && ( 'PERIOD' == $params['VALUE'] ))
  4147. $parno = 7;
  4148. if( is_array( $theDate )) {
  4149. if( isset( $theDate['timestamp'] ))
  4150. $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : null;
  4151. else
  4152. $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : ( 7 == count( $theDate )) ? end( $theDate ) : null;
  4153. if( !empty( $tzid )) {
  4154. $parno = 7;
  4155. if( !$this->_isOffset( $tzid ))
  4156. $params['TZID'] = $tzid; // save only timezone
  4157. }
  4158. elseif( !$parno && ( 3 == count( $theDate )) &&
  4159. ( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] )))
  4160. $parno = 3;
  4161. else
  4162. $parno = 6;
  4163. }
  4164. else { // string
  4165. $date = trim( $theDate );
  4166. if( 'Z' == substr( $date, -1 ))
  4167. $parno = 7; // UTC DATE-TIME
  4168. elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) &&
  4169. ( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' ))))
  4170. $parno = 3; // DATE
  4171. $date = $this->_date_time_string( $date, $parno );
  4172. if( !empty( $date['tz'] )) {
  4173. $parno = 7;
  4174. if( !$this->_isOffset( $date['tz'] ))
  4175. $params['TZID'] = $date['tz']; // save only timezone
  4176. }
  4177. elseif( empty( $parno ))
  4178. $parno = 6;
  4179. }
  4180. if( isset( $params['TZID'] ))
  4181. $parno = 6;
  4182. }
  4183. }
  4184. /**
  4185. * convert local startdate/enddate (Ymd[His]) to duration
  4186. *
  4187. * uses this component dates if missing input dates
  4188. *
  4189. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4190. * @since 2.2.11 - 2007-11-03
  4191. * @param array $startdate, optional
  4192. * @param array $duration, optional
  4193. * @return array duration
  4194. */
  4195. function _date2duration( $startdate=FALSE, $enddate=FALSE ) {
  4196. if( !$startdate || !$enddate ) {
  4197. if( FALSE === ( $startdate = $this->getProperty( 'dtstart' )))
  4198. return null;
  4199. if( FALSE === ( $enddate = $this->getProperty( 'dtend' ))) // vevent/vfreebusy
  4200. if( FALSE === ( $enddate = $this->getProperty( 'due' ))) // vtodo
  4201. return null;
  4202. }
  4203. if( !$startdate || !$enddate )
  4204. return null;
  4205. $startWdate = mktime( 0, 0, 0, $startdate['month'], $startdate['day'], $startdate['year'] );
  4206. $endWdate = mktime( 0, 0, 0, $enddate['month'], $enddate['day'], $enddate['year'] );
  4207. $wduration = $endWdate - $startWdate;
  4208. $dur = array();
  4209. $dur['week'] = (int) floor( $wduration / ( 7 * 24 * 60 * 60 ));
  4210. $wduration = $wduration % ( 7 * 24 * 60 * 60 );
  4211. $dur['day'] = (int) floor( $wduration / ( 24 * 60 * 60 ));
  4212. $wduration = $wduration % ( 24 * 60 * 60 );
  4213. $dur['hour'] = (int) floor( $wduration / ( 60 * 60 ));
  4214. $wduration = $wduration % ( 60 * 60 );
  4215. $dur['min'] = (int) floor( $wduration / ( 60 ));
  4216. $dur['sec'] = (int) $wduration % ( 60 );
  4217. return $dur;
  4218. }
  4219. /**
  4220. * convert date/datetime to timestamp
  4221. *
  4222. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4223. * @since 2.4.8 - 2008-10-30
  4224. * @param array $datetime datetime/(date)
  4225. * @param string $tz timezone
  4226. * @return timestamp
  4227. */
  4228. function _date2timestamp( $datetime, $tz=null ) {
  4229. $output = null;
  4230. if( !isset( $datetime['hour'] )) $datetime['hour'] = '0';
  4231. if( !isset( $datetime['min'] )) $datetime['min'] = '0';
  4232. if( !isset( $datetime['sec'] )) $datetime['sec'] = '0';
  4233. foreach( $datetime as $dkey => $dvalue ) {
  4234. if( 'tz' != $dkey )
  4235. $datetime[$dkey] = (integer) $dvalue;
  4236. }
  4237. if( $tz )
  4238. $datetime['tz'] = $tz;
  4239. $offset = ( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) ? $this->_tz2offset( $datetime['tz'] ) : 0;
  4240. $output = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year'] );
  4241. return $output;
  4242. }
  4243. /**
  4244. * ensures internal date-time/date format for input date-time/date in array format
  4245. *
  4246. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4247. * @since 0.3.0 - 2006-08-15
  4248. * @param array $datetime
  4249. * @param int $parno optional, default FALSE
  4250. * @return array
  4251. */
  4252. function _date_time_array( $datetime, $parno=FALSE ) {
  4253. $output = array();
  4254. foreach( $datetime as $dateKey => $datePart ) {
  4255. switch ( $dateKey ) {
  4256. case '0': case 'year': $output['year'] = $datePart; break;
  4257. case '1': case 'month': $output['month'] = $datePart; break;
  4258. case '2': case 'day': $output['day'] = $datePart; break;
  4259. }
  4260. if( 3 != $parno ) {
  4261. switch ( $dateKey ) {
  4262. case '0':
  4263. case '1':
  4264. case '2': break;
  4265. case '3': case 'hour': $output['hour'] = $datePart; break;
  4266. case '4': case 'min' : $output['min'] = $datePart; break;
  4267. case '5': case 'sec' : $output['sec'] = $datePart; break;
  4268. case '6': case 'tz' : $output['tz'] = $datePart; break;
  4269. }
  4270. }
  4271. }
  4272. if( 3 != $parno ) {
  4273. if( !isset( $output['hour'] ))
  4274. $output['hour'] = 0;
  4275. if( !isset( $output['min'] ))
  4276. $output['min'] = 0;
  4277. if( !isset( $output['sec'] ))
  4278. $output['sec'] = 0;
  4279. }
  4280. return $output;
  4281. }
  4282. /**
  4283. * ensures internal date-time/date format for input date-time/date in string fromat
  4284. *
  4285. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4286. * @since 2.2.10 - 2007-10-19
  4287. * @param array $datetime
  4288. * @param int $parno optional, default FALSE
  4289. * @return array
  4290. */
  4291. function _date_time_string( $datetime, $parno=FALSE ) {
  4292. $datetime = (string) trim( $datetime );
  4293. $tz = null;
  4294. $len = strlen( $datetime ) - 1;
  4295. if( 'Z' == substr( $datetime, -1 )) {
  4296. $tz = 'Z';
  4297. $datetime = trim( substr( $datetime, 0, $len ));
  4298. }
  4299. elseif( ( ctype_digit( substr( $datetime, -2, 2 ))) && // time or date
  4300. ( '-' == substr( $datetime, -3, 1 )) ||
  4301. ( ':' == substr( $datetime, -3, 1 )) ||
  4302. ( '.' == substr( $datetime, -3, 1 ))) {
  4303. $continue = TRUE;
  4304. }
  4305. elseif( ( ctype_digit( substr( $datetime, -4, 4 ))) && // 4 pos offset
  4306. ( ' +' == substr( $datetime, -6, 2 )) ||
  4307. ( ' -' == substr( $datetime, -6, 2 ))) {
  4308. $tz = substr( $datetime, -5, 5 );
  4309. $datetime = substr( $datetime, 0, ($len - 5));
  4310. }
  4311. elseif( ( ctype_digit( substr( $datetime, -6, 6 ))) && // 6 pos offset
  4312. ( ' +' == substr( $datetime, -8, 2 )) ||
  4313. ( ' -' == substr( $datetime, -8, 2 ))) {
  4314. $tz = substr( $datetime, -7, 7 );
  4315. $datetime = substr( $datetime, 0, ($len - 7));
  4316. }
  4317. elseif( ( 6 < $len ) && ( ctype_digit( substr( $datetime, -6, 6 )))) {
  4318. $continue = TRUE;
  4319. }
  4320. elseif( 'T' == substr( $datetime, -7, 1 )) {
  4321. $continue = TRUE;
  4322. }
  4323. else {
  4324. $cx = $tx = 0; // 19970415T133000 US-Eastern
  4325. for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
  4326. if(( ' ' == substr( $datetime, $cx, 1 )) || ctype_digit( substr( $datetime, $cx, 1 )))
  4327. break; // if exists, tz ends here.. . ?
  4328. elseif( ctype_alpha( substr( $datetime, $cx, 1 )) ||
  4329. ( in_array( substr( $datetime, $cx, 1 ), array( '-', '/' ))))
  4330. $tx--; // tz length counter
  4331. }
  4332. if( 0 > $tx ) {
  4333. $tz = substr( $datetime, $tx );
  4334. $datetime = trim( substr( $datetime, 0, $len + $tx + 1 ));
  4335. }
  4336. }
  4337. if( 0 < substr_count( $datetime, '-' )) {
  4338. $datetime = str_replace( '-', '/', $datetime );
  4339. }
  4340. elseif( ctype_digit( substr( $datetime, 0, 8 )) &&
  4341. ( 'T' == substr( $datetime, 8, 1 )) &&
  4342. ctype_digit( substr( $datetime, 9, 6 ))) {
  4343. $datetime = substr( $datetime, 4, 2 )
  4344. .'/'.substr( $datetime, 6, 2 )
  4345. .'/'.substr( $datetime, 0, 4 )
  4346. .' '.substr( $datetime, 9, 2 )
  4347. .':'.substr( $datetime, 11, 2 )
  4348. .':'.substr( $datetime, 13);
  4349. }
  4350. $datestring = date( 'Y-m-d H:i:s', strtotime( $datetime ));
  4351. $tz = trim( $tz );
  4352. $output = array();
  4353. $output['year'] = substr( $datestring, 0, 4 );
  4354. $output['month'] = substr( $datestring, 5, 2 );
  4355. $output['day'] = substr( $datestring, 8, 2 );
  4356. if(( 6 == $parno ) || ( 7 == $parno )) {
  4357. $output['hour'] = substr( $datestring, 11, 2 );
  4358. $output['min'] = substr( $datestring, 14, 2 );
  4359. $output['sec'] = substr( $datestring, 17, 2 );
  4360. if( !empty( $tz ))
  4361. $output['tz'] = $tz;
  4362. }
  4363. elseif( 3 != $parno ) {
  4364. if(( '00' < substr( $datestring, 11, 2 )) ||
  4365. ( '00' < substr( $datestring, 14, 2 )) ||
  4366. ( '00' < substr( $datestring, 17, 2 ))) {
  4367. $output['hour'] = substr( $datestring, 11, 2 );
  4368. $output['min'] = substr( $datestring, 14, 2 );
  4369. $output['sec'] = substr( $datestring, 17, 2 );
  4370. }
  4371. if( !empty( $tz ))
  4372. $output['tz'] = $tz;
  4373. }
  4374. return $output;
  4375. }
  4376. /**
  4377. * ensures internal duration format for input in array format
  4378. *
  4379. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4380. * @since 2.1.1 - 2007-06-24
  4381. * @param array $duration
  4382. * @return array
  4383. */
  4384. function _duration_array( $duration ) {
  4385. $output = array();
  4386. if( is_array( $duration ) &&
  4387. ( 1 == count( $duration )) &&
  4388. isset( $duration['sec'] ) &&
  4389. ( 60 < $duration['sec'] )) {
  4390. $durseconds = $duration['sec'];
  4391. $output['week'] = floor( $durseconds / ( 60 * 60 * 24 * 7 ));
  4392. $durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
  4393. $output['day'] = floor( $durseconds / ( 60 * 60 * 24 ));
  4394. $durseconds = $durseconds % ( 60 * 60 * 24 );
  4395. $output['hour'] = floor( $durseconds / ( 60 * 60 ));
  4396. $durseconds = $durseconds % ( 60 * 60 );
  4397. $output['min'] = floor( $durseconds / ( 60 ));
  4398. $output['sec'] = ( $durseconds % ( 60 ));
  4399. }
  4400. else {
  4401. foreach( $duration as $durKey => $durValue ) {
  4402. if( empty( $durValue )) continue;
  4403. switch ( $durKey ) {
  4404. case '0': case 'week': $output['week'] = $durValue; break;
  4405. case '1': case 'day': $output['day'] = $durValue; break;
  4406. case '2': case 'hour': $output['hour'] = $durValue; break;
  4407. case '3': case 'min': $output['min'] = $durValue; break;
  4408. case '4': case 'sec': $output['sec'] = $durValue; break;
  4409. }
  4410. }
  4411. }
  4412. if( isset( $output['week'] ) && ( 0 < $output['week'] )) {
  4413. unset( $output['day'], $output['hour'], $output['min'], $output['sec'] );
  4414. return $output;
  4415. }
  4416. unset( $output['week'] );
  4417. if( empty( $output['day'] ))
  4418. unset( $output['day'] );
  4419. if ( isset( $output['hour'] ) || isset( $output['min'] ) || isset( $output['sec'] )) {
  4420. if( !isset( $output['hour'] )) $output['hour'] = 0;
  4421. if( !isset( $output['min'] )) $output['min'] = 0;
  4422. if( !isset( $output['sec'] )) $output['sec'] = 0;
  4423. if(( 0 == $output['hour'] ) && ( 0 == $output['min'] ) && ( 0 == $output['sec'] ))
  4424. unset( $output['hour'], $output['min'], $output['sec'] );
  4425. }
  4426. return $output;
  4427. }
  4428. /**
  4429. * convert duration to date in array format based on input or dtstart value
  4430. *
  4431. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4432. * @since 2.4.8 - 2008-10-30
  4433. * @param array $startdate, optional
  4434. * @param array $duration, optional
  4435. * @return array, date format
  4436. */
  4437. function duration2date( $startdate=FALSE, $duration=FALSE ) {
  4438. if( $startdate && $duration ) {
  4439. $d1 = $startdate;
  4440. $dur = $duration;
  4441. }
  4442. elseif( isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) {
  4443. $d1 = $this->dtstart['value'];
  4444. $dur = $this->duration['value'];
  4445. }
  4446. else
  4447. return null;
  4448. $dateOnly = ( isset( $d1['hour'] ) || isset( $d1['min'] ) || isset( $d1['sec'] )) ? FALSE : TRUE;
  4449. $d1['hour'] = ( isset( $d1['hour'] )) ? $d1['hour'] : 0;
  4450. $d1['min'] = ( isset( $d1['min'] )) ? $d1['min'] : 0;
  4451. $d1['sec'] = ( isset( $d1['sec'] )) ? $d1['sec'] : 0;
  4452. $dtend = mktime( $d1['hour'], $d1['min'], $d1['sec'], $d1['month'], $d1['day'], $d1['year'] );
  4453. if( isset( $dur['week'] ))
  4454. $dtend += ( $dur['week'] * 7 * 24 * 60 * 60 );
  4455. if( isset( $dur['day'] ))
  4456. $dtend += ( $dur['day'] * 24 * 60 * 60 );
  4457. if( isset( $dur['hour'] ))
  4458. $dtend += ( $dur['hour'] * 60 *60 );
  4459. if( isset( $dur['min'] ))
  4460. $dtend += ( $dur['min'] * 60 );
  4461. if( isset( $dur['sec'] ))
  4462. $dtend += $dur['sec'];
  4463. $dtend2 = array();
  4464. $dtend2['year'] = date('Y', $dtend );
  4465. $dtend2['month'] = date('m', $dtend );
  4466. $dtend2['day'] = date('d', $dtend );
  4467. $dtend2['hour'] = date('H', $dtend );
  4468. $dtend2['min'] = date('i', $dtend );
  4469. $dtend2['sec'] = date('s', $dtend );
  4470. if( isset( $d1['tz'] ))
  4471. $dtend2['tz'] = $d1['tz'];
  4472. if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
  4473. unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
  4474. return $dtend2;
  4475. }
  4476. /**
  4477. * ensures internal duration format for input in string format
  4478. *
  4479. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4480. * @since 2.0.5 - 2007-03-14
  4481. * @param string $duration
  4482. * @return array
  4483. */
  4484. function _duration_string( $duration ) {
  4485. $duration = (string) trim( $duration );
  4486. while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
  4487. if( 0 < strlen( $duration ))
  4488. $duration = substr( $duration, 1 );
  4489. else
  4490. return false; // no leading P !?!?
  4491. }
  4492. $duration = substr( $duration, 1 ); // skip P
  4493. $duration = str_replace ( 't', 'T', $duration );
  4494. $duration = str_replace ( 'T', '', $duration );
  4495. $output = array();
  4496. $val = null;
  4497. for( $ix=0; $ix < strlen( $duration ); $ix++ ) {
  4498. switch( strtoupper( $duration{$ix} )) {
  4499. case 'W':
  4500. $output['week'] = $val;
  4501. $val = null;
  4502. break;
  4503. case 'D':
  4504. $output['day'] = $val;
  4505. $val = null;
  4506. break;
  4507. case 'H':
  4508. $output['hour'] = $val;
  4509. $val = null;
  4510. break;
  4511. case 'M':
  4512. $output['min'] = $val;
  4513. $val = null;
  4514. break;
  4515. case 'S':
  4516. $output['sec'] = $val;
  4517. $val = null;
  4518. break;
  4519. default:
  4520. if( !ctype_digit( $duration{$ix} ))
  4521. return false; // unknown duration controll character !?!?
  4522. else
  4523. $val .= $duration{$ix};
  4524. }
  4525. }
  4526. return $this->_duration_array( $output );
  4527. }
  4528. /**
  4529. * if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue
  4530. *
  4531. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4532. * @since 2.4.16 - 2008-11-08
  4533. * @param array $array
  4534. * @param string $expkey, expected key
  4535. * @param string $expval, expected value
  4536. * @param int $hitVal optional, return value if found
  4537. * @param int $elseVal optional, return value if not found
  4538. * @param int $preSet optional, return value if already preset
  4539. * @return int
  4540. */
  4541. function _existRem( &$array, $expkey, $expval=FALSE, $hitVal=null, $elseVal=null, $preSet=null ) {
  4542. if( $preSet )
  4543. return $preSet;
  4544. if( !is_array( $array ) || ( 0 == count( $array )))
  4545. return $elseVal;
  4546. foreach( $array as $key => $value ) {
  4547. if( strtoupper( $expkey ) == strtoupper( $key )) {
  4548. if( !$expval || ( strtoupper( $expval ) == strtoupper( $array[$key] ))) {
  4549. unset( $array[$key] );
  4550. return $hitVal;
  4551. }
  4552. }
  4553. }
  4554. return $elseVal;
  4555. }
  4556. /**
  4557. * creates formatted output for calendar component property data value type date/date-time
  4558. *
  4559. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4560. * @since 2.4.8 - 2008-10-30
  4561. * @param array $datetime
  4562. * @param int $parno, optional, default 6
  4563. * @return string
  4564. */
  4565. function _format_date_time( $datetime, $parno=6 ) {
  4566. if( !isset( $datetime['year'] ) &&
  4567. !isset( $datetime['month'] ) &&
  4568. !isset( $datetime['day'] ) &&
  4569. !isset( $datetime['hour'] ) &&
  4570. !isset( $datetime['min'] ) &&
  4571. !isset( $datetime['sec'] ))
  4572. return ;
  4573. $output = null;
  4574. // if( !isset( $datetime['day'] )) { $o=''; foreach($datetime as $k=>$v) {if(is_array($v)) $v=implode('-',$v);$o.=" $k=>$v";} echo " day SAKNAS : $o <br />\n"; }
  4575. foreach( $datetime as $dkey => $dvalue ) {
  4576. if( 'tz' != $dkey )
  4577. $datetime[$dkey] = (integer) $dvalue;
  4578. }
  4579. $output = date('Ymd', mktime( 0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year']));
  4580. if( isset( $datetime['hour'] ) ||
  4581. isset( $datetime['min'] ) ||
  4582. isset( $datetime['sec'] ) ||
  4583. isset( $datetime['tz'] )) {
  4584. if( isset( $datetime['tz'] ) &&
  4585. !isset( $datetime['hour'] ))
  4586. $datetime['hour'] = 0;
  4587. if( isset( $datetime['hour'] ) &&
  4588. !isset( $datetime['min'] ))
  4589. $datetime['min'] = 0;
  4590. if( isset( $datetime['hour'] ) &&
  4591. isset( $datetime['min'] ) &&
  4592. !isset( $datetime['sec'] ))
  4593. $datetime['sec'] = 0;
  4594. $date = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']);
  4595. $output .= date('\THis', $date );
  4596. if( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) {
  4597. $datetime['tz'] = trim( $datetime['tz'] );
  4598. if( 'Z' == $datetime['tz'] )
  4599. $output .= 'Z';
  4600. $offset = $this->_tz2offset( $datetime['tz'] );
  4601. if( 0 != $offset ) {
  4602. $date = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']);
  4603. $output = date( 'Ymd\THis\Z', $date );
  4604. }
  4605. }
  4606. elseif( 7 == $parno )
  4607. $output .= 'Z';
  4608. }
  4609. return $output;
  4610. }
  4611. /**
  4612. * creates formatted output for calendar component property data value type duration
  4613. *
  4614. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4615. * @since 2.4.16 - 2008-10-10
  4616. * @param array $duration ( week, day, hour, min, sec )
  4617. * @return string
  4618. */
  4619. function _format_duration( $duration ) {
  4620. if( !isset( $duration['week'] ) &&
  4621. !isset( $duration['day'] ) &&
  4622. !isset( $duration['hour'] ) &&
  4623. !isset( $duration['min'] ) &&
  4624. !isset( $duration['sec'] ))
  4625. return;
  4626. $output = 'P';
  4627. if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
  4628. $output .= $duration['week'].'W';
  4629. else {
  4630. if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
  4631. $output .= $duration['day'].'D';
  4632. if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
  4633. ( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
  4634. ( isset( $duration['sec']) && ( 0 < $duration['sec'] ))) {
  4635. $output .= 'T';
  4636. $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '0H';
  4637. $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '0M';
  4638. $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '0S';
  4639. }
  4640. }
  4641. return $output;
  4642. }
  4643. /**
  4644. * creates formatted output for calendar component property data value type recur
  4645. *
  4646. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4647. * @since 2.4.8 - 2008-10-22
  4648. * @param array $recurlabel
  4649. * @param array $recurdata
  4650. * @return string
  4651. */
  4652. function _format_recur( $recurlabel, $recurdata ) {
  4653. $output = null;
  4654. foreach( $recurdata as $therule ) {
  4655. if( empty( $therule['value'] )) {
  4656. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel );
  4657. continue;
  4658. }
  4659. $attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null;
  4660. $content1 = $content2 = null;
  4661. foreach( $therule['value'] as $rulelabel => $rulevalue ) {
  4662. switch( $rulelabel ) {
  4663. case 'FREQ': {
  4664. $content1 .= "FREQ=$rulevalue";
  4665. break;
  4666. }
  4667. case 'UNTIL': {
  4668. $content2 .= ";UNTIL=";
  4669. $content2 .= $this->_format_date_time( $rulevalue );
  4670. break;
  4671. }
  4672. case 'COUNT':
  4673. case 'INTERVAL':
  4674. case 'WKST': {
  4675. $content2 .= ";$rulelabel=$rulevalue";
  4676. break;
  4677. }
  4678. case 'BYSECOND':
  4679. case 'BYMINUTE':
  4680. case 'BYHOUR':
  4681. case 'BYMONTHDAY':
  4682. case 'BYYEARDAY':
  4683. case 'BYWEEKNO':
  4684. case 'BYMONTH':
  4685. case 'BYSETPOS': {
  4686. $content2 .= ";$rulelabel=";
  4687. if( is_array( $rulevalue )) {
  4688. foreach( $rulevalue as $vix => $valuePart ) {
  4689. $content2 .= ( $vix ) ? ',' : null;
  4690. $content2 .= $valuePart;
  4691. }
  4692. }
  4693. else
  4694. $content2 .= $rulevalue;
  4695. break;
  4696. }
  4697. case 'BYDAY': {
  4698. $content2 .= ";$rulelabel=";
  4699. $bydaycnt = 0;
  4700. foreach( $rulevalue as $vix => $valuePart ) {
  4701. $content21 = $content22 = null;
  4702. if( is_array( $valuePart )) {
  4703. $content2 .= ( $bydaycnt ) ? ',' : null;
  4704. foreach( $valuePart as $vix2 => $valuePart2 ) {
  4705. if( 'DAY' != strtoupper( $vix2 ))
  4706. $content21 .= $valuePart2;
  4707. else
  4708. $content22 .= $valuePart2;
  4709. }
  4710. $content2 .= $content21.$content22;
  4711. $bydaycnt++;
  4712. }
  4713. else {
  4714. $content2 .= ( $bydaycnt ) ? ',' : null;
  4715. if( 'DAY' != strtoupper( $vix ))
  4716. $content21 .= $valuePart;
  4717. else {
  4718. $content22 .= $valuePart;
  4719. $bydaycnt++;
  4720. }
  4721. $content2 .= $content21.$content22;
  4722. }
  4723. }
  4724. break;
  4725. }
  4726. default: {
  4727. $content2 .= ";$rulelabel=$rulevalue";
  4728. break;
  4729. }
  4730. }
  4731. }
  4732. $output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 );
  4733. }
  4734. return $output;
  4735. }
  4736. /**
  4737. * create property name case - lower/upper
  4738. *
  4739. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4740. * @since 0.9.7 - 2006-11-20
  4741. * @param string $propertyName
  4742. * @return string
  4743. */
  4744. function _formatPropertyName( $propertyName ) {
  4745. switch( $this->format ) {
  4746. case 'xcal':
  4747. return strtolower( $propertyName );
  4748. break;
  4749. default:
  4750. return strtoupper( $propertyName );
  4751. break;
  4752. }
  4753. }
  4754. /**
  4755. * checks if input array contains a date
  4756. *
  4757. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4758. * @since 2.4.16 - 2008-10-25
  4759. * @param array $input
  4760. * @return bool
  4761. */
  4762. function _isArrayDate( $input ) {
  4763. if( isset( $input['week'] ) || ( !in_array( count( $input ), array( 3, 6, 7 ))))
  4764. return FALSE;
  4765. if( 7 == count( $input ))
  4766. return TRUE;
  4767. if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
  4768. return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
  4769. if( isset( $input['day'] ) || isset( $input['hour'] ) || isset( $input['min'] ) || isset( $input['sec'] ))
  4770. return FALSE;
  4771. if( in_array( 0, $input ))
  4772. return FALSE;
  4773. if(( 1970 > $input[0] ) || ( 12 < $input[1] ) || ( 31 < $input[2] ))
  4774. return FALSE;
  4775. if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
  4776. checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
  4777. return TRUE;
  4778. $input = $this->_date_time_string( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
  4779. if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
  4780. return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
  4781. return FALSE;
  4782. }
  4783. /**
  4784. * checks if input array contains a timestamp date
  4785. *
  4786. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4787. * @since 2.4.16 - 2008-10-18
  4788. * @param array $input
  4789. * @return bool
  4790. */
  4791. function _isArrayTimestampDate( $input ) {
  4792. return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
  4793. }
  4794. /**
  4795. * controll if input string contains traling UTC offset
  4796. *
  4797. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4798. * @since 2.4.16 - 2008-10-19
  4799. * @param string $input
  4800. * @return bool
  4801. */
  4802. function _isOffset( $input ) {
  4803. $input = trim( (string) $input );
  4804. if( 'Z' == substr( $input, -1 ))
  4805. return TRUE;
  4806. elseif(( 5 <= strlen( $input )) &&
  4807. ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
  4808. ( '0000' < substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
  4809. return TRUE;
  4810. elseif(( 7 <= strlen( $input )) &&
  4811. ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
  4812. ( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
  4813. return TRUE;
  4814. return FALSE;
  4815. }
  4816. /**
  4817. * check if property not exists within component
  4818. *
  4819. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4820. * @since 2.5.1 - 2008-10-15
  4821. * @param string $propName
  4822. * @return bool
  4823. */
  4824. function _notExistProp( $propName ) {
  4825. if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
  4826. $propName = strtolower( $propName );
  4827. if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; }
  4828. elseif( 'percent-complete' == $propName ) { if( !isset( $this->percentcomplete )) return TRUE; }
  4829. elseif( 'recurrence-id' == $propName ) { if( !isset( $this->recurrenceid )) return TRUE; }
  4830. elseif( 'related-to' == $propName ) { if( !isset( $this->relatedto )) return TRUE; }
  4831. elseif( 'request-status' == $propName ) { if( !isset( $this->requeststatus )) return TRUE; }
  4832. elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE;
  4833. return FALSE;
  4834. }
  4835. /**
  4836. * remakes a recur pattern to an array of dates
  4837. *
  4838. * if missing, UNTIL is set 1 year from startdate (emergency break)
  4839. *
  4840. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4841. * @since 2.4.16 - 2008-10-18
  4842. * @param array $result, array to update, array([timestamp] => timestamp)
  4843. * @param array $recur, pattern for recurrency (only value part, params ignored)
  4844. * @param array $wdate, component start date
  4845. * @param array $startdate, start date
  4846. * @param array $enddate, optional
  4847. * @return array of recurrence (start-)dates as index
  4848. * @todo BYHOUR, BYMINUTE, BYSECOND, ev. BYSETPOS due to ambiguity, WEEKLY at year end/start
  4849. */
  4850. function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) {
  4851. foreach( $wdate as $k => $v ) if( ctype_digit( $v )) $wdate[$k] = (int) $v;
  4852. $wdatets = $this->_date2timestamp( $wdate );
  4853. $startdatets = $this->_date2timestamp( $startdate );
  4854. if( !$enddate ) {
  4855. $enddate = $startdate;
  4856. $enddate['year'] += 1;
  4857. // echo "recur __in_ ".implode('-',$startdate)." period start ".implode('-',$wdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test###
  4858. }
  4859. $endDatets = $this->_date2timestamp( $enddate ); // fix break
  4860. if( !isset( $recur['COUNT'] ) && !isset( $recur['UNTIL'] ))
  4861. $recur['UNTIL'] = $enddate; // create break
  4862. if( isset( $recur['UNTIL'] )) {
  4863. $tdatets = $this->_date2timestamp( $recur['UNTIL'] );
  4864. if( $endDatets > $tdatets ) {
  4865. $endDatets = $tdatets; // emergency break
  4866. $enddate = $this->_timestamp2date( $endDatets, 6 );
  4867. }
  4868. else
  4869. $recur['UNTIL'] = $this->_timestamp2date( $endDatets, 6 );
  4870. }
  4871. if( $wdatets > $endDatets ) {
  4872. //echo "recur out of date ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
  4873. return array(); // nothing to do.. .
  4874. }
  4875. if( !isset( $recur['FREQ'] )) // "MUST be specified.. ."
  4876. $recur['FREQ'] = 'DAILY'; // ??
  4877. $wkst = ( isset( $recur['WKST'] ) && ( 'SU' == $recur['WKST'] )) ? 24*60*60 : 0; // ??
  4878. if( !isset( $recur['INTERVAL'] ))
  4879. $recur['INTERVAL'] = 1;
  4880. $countcnt = ( !isset( $recur['BYSETPOS'] )) ? 1 : 0; // DTSTART counts as the first occurrence
  4881. /* find out how to step up dates and set index for interval count */
  4882. $step = array();
  4883. if( 'YEARLY' == $recur['FREQ'] )
  4884. $step['year'] = 1;
  4885. elseif( 'MONTHLY' == $recur['FREQ'] )
  4886. $step['month'] = 1;
  4887. elseif( 'WEEKLY' == $recur['FREQ'] )
  4888. $step['day'] = 7;
  4889. else
  4890. $step['day'] = 1;
  4891. if( isset( $step['year'] ) && isset( $recur['BYMONTH'] ))
  4892. $step = array( 'month' => 1 );
  4893. if( empty( $step ) && isset( $recur['BYWEEKNO'] )) // ??
  4894. $step = array( 'day' => 7 );
  4895. if( isset( $recur['BYYEARDAY'] ) || isset( $recur['BYMONTHDAY'] ) || isset( $recur['BYDAY'] ))
  4896. $step = array( 'day' => 1 );
  4897. $intervalarr = array();
  4898. if( 1 < $recur['INTERVAL'] ) {
  4899. $intervalix = $this->_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
  4900. $intervalarr = array( $intervalix => 0 );
  4901. }
  4902. if( isset( $recur['BYSETPOS'] )) { // save start date + weekno
  4903. $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array();
  4904. $bysetposWold = (int) date( 'W', ( $wdatets + $wkst ));
  4905. $bysetposYold = $wdate['year'];
  4906. $bysetposMold = $wdate['month'];
  4907. $bysetposDold = $wdate['day'];
  4908. if( is_array( $recur['BYSETPOS'] )) {
  4909. foreach( $recur['BYSETPOS'] as $bix => $bval )
  4910. $recur['BYSETPOS'][$bix] = (int) $bval;
  4911. }
  4912. else
  4913. $recur['BYSETPOS'] = array( (int) $recur['BYSETPOS'] );
  4914. $this->_stepdate( $enddate, $endDatets, $step); // make sure to count whole last period
  4915. }
  4916. $this->_stepdate( $wdate, $wdatets, $step);
  4917. $year_old = null;
  4918. $daynames = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' );
  4919. /* MAIN LOOP */
  4920. // echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test
  4921. while( TRUE ) {
  4922. if( isset( $endDatets ) && ( $wdatets > $endDatets ))
  4923. break;
  4924. if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
  4925. break;
  4926. if( $year_old != $wdate['year'] ) {
  4927. $year_old = $wdate['year'];
  4928. $daycnts = array();
  4929. $yeardays = $weekno = 0;
  4930. $yeardaycnt = array();
  4931. for( $m = 1; $m <= 12; $m++ ) { // count up and update up-counters
  4932. $daycnts[$m] = array();
  4933. $weekdaycnt = array();
  4934. foreach( $daynames as $dn )
  4935. $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
  4936. $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
  4937. for( $d = 1; $d <= $mcnt; $d++ ) {
  4938. $daycnts[$m][$d] = array();
  4939. if( isset( $recur['BYYEARDAY'] )) {
  4940. $yeardays++;
  4941. $daycnts[$m][$d]['yearcnt_up'] = $yeardays;
  4942. }
  4943. if( isset( $recur['BYDAY'] )) {
  4944. $day = date( 'w', mktime( 0, 0, 0, $m, $d, $wdate['year'] ));
  4945. $day = $daynames[$day];
  4946. $daycnts[$m][$d]['DAY'] = $day;
  4947. $weekdaycnt[$day]++;
  4948. $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day];
  4949. $yeardaycnt[$day]++;
  4950. $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day];
  4951. }
  4952. if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
  4953. $daycnts[$m][$d]['weekno_up'] =(int)date('W',mktime(0,0,$wkst,$m,$d,$wdate['year']));
  4954. }
  4955. }
  4956. $daycnt = 0;
  4957. $yeardaycnt = array();
  4958. if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) {
  4959. $weekno = null;
  4960. for( $d=31; $d > 25; $d-- ) { // get last weekno for year
  4961. if( !$weekno )
  4962. $weekno = $daycnts[12][$d]['weekno_up'];
  4963. elseif( $weekno < $daycnts[12][$d]['weekno_up'] ) {
  4964. $weekno = $daycnts[12][$d]['weekno_up'];
  4965. break;
  4966. }
  4967. }
  4968. }
  4969. for( $m = 12; $m > 0; $m-- ) { // count down and update down-counters
  4970. $weekdaycnt = array();
  4971. foreach( $daynames as $dn )
  4972. $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
  4973. $monthcnt = 0;
  4974. $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
  4975. for( $d = $mcnt; $d > 0; $d-- ) {
  4976. if( isset( $recur['BYYEARDAY'] )) {
  4977. $daycnt -= 1;
  4978. $daycnts[$m][$d]['yearcnt_down'] = $daycnt;
  4979. }
  4980. if( isset( $recur['BYMONTHDAY'] )) {
  4981. $monthcnt -= 1;
  4982. $daycnts[$m][$d]['monthcnt_down'] = $monthcnt;
  4983. }
  4984. if( isset( $recur['BYDAY'] )) {
  4985. $day = $daycnts[$m][$d]['DAY'];
  4986. $weekdaycnt[$day] -= 1;
  4987. $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day];
  4988. $yeardaycnt[$day] -= 1;
  4989. $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day];
  4990. }
  4991. if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
  4992. $daycnts[$m][$d]['weekno_down'] = ($daycnts[$m][$d]['weekno_up'] - $weekno - 1);
  4993. }
  4994. }
  4995. }
  4996. /* check interval */
  4997. if( 1 < $recur['INTERVAL'] ) {
  4998. /* create interval index */
  4999. $intervalix = $this->_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
  5000. /* check interval */
  5001. $currentKey = array_keys( $intervalarr );
  5002. $currentKey = end( $currentKey ); // get last index
  5003. if( $currentKey != $intervalix )
  5004. $intervalarr = array( $intervalix => ( $intervalarr[$currentKey] + 1 ));
  5005. if(( $recur['INTERVAL'] != $intervalarr[$intervalix] ) &&
  5006. ( 0 != $intervalarr[$intervalix] )) {
  5007. /* step up date */
  5008. //echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
  5009. $this->_stepdate( $wdate, $wdatets, $step);
  5010. continue;
  5011. }
  5012. else // continue within the selected interval
  5013. $intervalarr[$intervalix] = 0;
  5014. //echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
  5015. }
  5016. $updateOK = TRUE;
  5017. if( $updateOK && isset( $recur['BYMONTH'] ))
  5018. $updateOK = $this->_recurBYcntcheck( $recur['BYMONTH']
  5019. , $wdate['month']
  5020. ,($wdate['month'] - 13));
  5021. if( $updateOK && isset( $recur['BYWEEKNO'] ))
  5022. $updateOK = $this->_recurBYcntcheck( $recur['BYWEEKNO']
  5023. , $daycnts[$wdate['month']][$wdate['day']]['weekno_up']
  5024. , $daycnts[$wdate['month']][$wdate['day']]['weekno_down'] );
  5025. if( $updateOK && isset( $recur['BYYEARDAY'] ))
  5026. $updateOK = $this->_recurBYcntcheck( $recur['BYYEARDAY']
  5027. , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up']
  5028. , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down'] );
  5029. if( $updateOK && isset( $recur['BYMONTHDAY'] ))
  5030. $updateOK = $this->_recurBYcntcheck( $recur['BYMONTHDAY']
  5031. , $wdate['day']
  5032. , $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down'] );
  5033. //echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test###
  5034. if( $updateOK && isset( $recur['BYDAY'] )) {
  5035. $updateOK = FALSE;
  5036. $m = $wdate['month'];
  5037. $d = $wdate['day'];
  5038. if( isset( $recur['BYDAY']['DAY'] )) { // single day, opt with year/month day order no
  5039. $daynoexists = $daynosw = $daynamesw = FALSE;
  5040. if( $recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY'] )
  5041. $daynamesw = TRUE;
  5042. if( isset( $recur['BYDAY'][0] )) {
  5043. $daynoexists = TRUE;
  5044. if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) || isset( $recur['BYMONTH'] ))
  5045. $daynosw = $this->_recurBYcntcheck( $recur['BYDAY'][0]
  5046. , $daycnts[$m][$d]['monthdayno_up']
  5047. , $daycnts[$m][$d]['monthdayno_down'] );
  5048. elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
  5049. $daynosw = $this->_recurBYcntcheck( $recur['BYDAY'][0]
  5050. , $daycnts[$m][$d]['yeardayno_up']
  5051. , $daycnts[$m][$d]['yeardayno_down'] );
  5052. }
  5053. if(( $daynoexists && $daynosw && $daynamesw ) ||
  5054. ( !$daynoexists && !$daynosw && $daynamesw )) {
  5055. $updateOK = TRUE;
  5056. }
  5057. //echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
  5058. }
  5059. else {
  5060. foreach( $recur['BYDAY'] as $bydayvalue ) {
  5061. $daynoexists = $daynosw = $daynamesw = FALSE;
  5062. if( isset( $bydayvalue['DAY'] ) &&
  5063. ( $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY'] ))
  5064. $daynamesw = TRUE;
  5065. if( isset( $bydayvalue[0] )) {
  5066. $daynoexists = TRUE;
  5067. if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) ||
  5068. isset( $recur['BYMONTH'] ))
  5069. $daynosw = $this->_recurBYcntcheck( $bydayvalue['0']
  5070. , $daycnts[$m][$d]['monthdayno_up']
  5071. , $daycnts[$m][$d]['monthdayno_down'] );
  5072. elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
  5073. $daynosw = $this->_recurBYcntcheck( $bydayvalue['0']
  5074. , $daycnts[$m][$d]['yeardayno_up']
  5075. , $daycnts[$m][$d]['yeardayno_down'] );
  5076. }
  5077. //echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
  5078. if(( $daynoexists && $daynosw && $daynamesw ) ||
  5079. ( !$daynoexists && !$daynosw && $daynamesw )) {
  5080. $updateOK = TRUE;
  5081. break;
  5082. }
  5083. }
  5084. }
  5085. }
  5086. //echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ###
  5087. /* check BYSETPOS */
  5088. if( $updateOK ) {
  5089. if( isset( $recur['BYSETPOS'] ) &&
  5090. ( in_array( $recur['FREQ'], array( 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY' )))) {
  5091. if( isset( $recur['WEEKLY'] )) {
  5092. if( $bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] )
  5093. $bysetposw1[] = $wdatets;
  5094. else
  5095. $bysetposw2[] = $wdatets;
  5096. }
  5097. else {
  5098. if(( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
  5099. ( $bysetposYold == $wdate['year'] )) ||
  5100. ( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) &&
  5101. (( $bysetposYold == $wdate['year'] ) &&
  5102. ( $bysetposMold == $wdate['month'] ))) ||
  5103. ( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) &&
  5104. (( $bysetposYold == $wdate['year'] ) &&
  5105. ( $bysetposMold == $wdate['month']) &&
  5106. ( $bysetposDold == $wdate['sday'] ))))
  5107. $bysetposymd1[] = $wdatets;
  5108. else
  5109. $bysetposymd2[] = $wdatets;
  5110. }
  5111. }
  5112. else {
  5113. /* update result array if BYSETPOS is set */
  5114. $countcnt++;
  5115. if( $startdatets <= $wdatets ) { // only output within period
  5116. $result[$wdatets] = TRUE;
  5117. //echo "recur ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
  5118. }
  5119. //else echo "recur undate ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))." okdatstart ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$startdatets),6))."<br />\n";//test
  5120. $updateOK = FALSE;
  5121. }
  5122. }
  5123. /* step up date */
  5124. $this->_stepdate( $wdate, $wdatets, $step);
  5125. /* check if BYSETPOS is set for updating result array */
  5126. if( $updateOK && isset( $recur['BYSETPOS'] )) {
  5127. $bysetpos = FALSE;
  5128. if( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
  5129. ( $bysetposYold != $wdate['year'] )) {
  5130. $bysetpos = TRUE;
  5131. $bysetposYold = $wdate['year'];
  5132. }
  5133. elseif( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] &&
  5134. (( $bysetposYold != $wdate['year'] ) || ( $bysetposMold != $wdate['month'] )))) {
  5135. $bysetpos = TRUE;
  5136. $bysetposYold = $wdate['year'];
  5137. $bysetposMold = $wdate['month'];
  5138. }
  5139. elseif( isset( $recur['FREQ'] ) && ( 'WEEKLY' == $recur['FREQ'] )) {
  5140. $weekno = (int) date( 'W', mktime( 0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year']));
  5141. if( $bysetposWold != $weekno ) {
  5142. $bysetposWold = $weekno;
  5143. $bysetpos = TRUE;
  5144. }
  5145. }
  5146. elseif( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) &&
  5147. (( $bysetposYold != $wdate['year'] ) ||
  5148. ( $bysetposMold != $wdate['month'] ) ||
  5149. ( $bysetposDold != $wdate['sday'] ))) {
  5150. $bysetpos = TRUE;
  5151. $bysetposYold = $wdate['year'];
  5152. $bysetposMold = $wdate['month'];
  5153. $bysetposDold = $wdate['day'];
  5154. }
  5155. if( $bysetpos ) {
  5156. if( isset( $recur['BYWEEKNO'] )) {
  5157. $bysetposarr1 = & $bysetposw1;
  5158. $bysetposarr2 = & $bysetposw2;
  5159. }
  5160. else {
  5161. $bysetposarr1 = & $bysetposymd1;
  5162. $bysetposarr2 = & $bysetposymd2;
  5163. }
  5164. foreach( $recur['BYSETPOS'] as $ix ) {
  5165. if( 0 > $ix ) // both positive and negative BYSETPOS allowed
  5166. $ix = ( count( $bysetposarr1 ) + $ix + 1);
  5167. $ix--;
  5168. if( isset( $bysetposarr1[$ix] )) {
  5169. if( $startdatets <= $bysetposarr1[$ix] ) { // only output within period
  5170. $result[$bysetposarr1[$ix]] = TRUE;
  5171. //echo "recur ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$bysetposarr1[$ix]),6))."<br />\n";//test
  5172. }
  5173. $countcnt++;
  5174. }
  5175. if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
  5176. break;
  5177. }
  5178. $bysetposarr1 = $bysetposarr2;
  5179. $bysetposarr2 = array();
  5180. }
  5181. }
  5182. }
  5183. }
  5184. function _recurBYcntcheck( $BYvalue, $upValue, $downValue ) {
  5185. if( is_array( $BYvalue ) &&
  5186. ( in_array( $upValue, $BYvalue ) || in_array( $downValue, $BYvalue )))
  5187. return TRUE;
  5188. elseif(( $BYvalue == $upValue ) || ( $BYvalue == $downValue ))
  5189. return TRUE;
  5190. else
  5191. return FALSE;
  5192. }
  5193. function _recurIntervalIx( $freq, $date, $wkst ) {
  5194. /* create interval index */
  5195. switch( $freq ) {
  5196. case 'YEARLY':
  5197. $intervalix = $date['year'];
  5198. break;
  5199. case 'MONTHLY':
  5200. $intervalix = $date['year'].'-'.$date['month'];
  5201. break;
  5202. case 'WEEKLY':
  5203. $wdatets = $this->_date2timestamp( $date );
  5204. $intervalix = (int) date( 'W', ( $wdatets + $wkst ));
  5205. break;
  5206. case 'DAILY':
  5207. default:
  5208. $intervalix = $date['year'].'-'.$date['month'].'-'.$date['day'];
  5209. break;
  5210. }
  5211. return $intervalix;
  5212. }
  5213. /**
  5214. * convert input format for exrule and rrule to internal format
  5215. *
  5216. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5217. * @since 2.4.16 - 2008-10-19
  5218. * @param array $rexrule
  5219. * @return array
  5220. */
  5221. function _setRexrule( $rexrule ) {
  5222. $input = array();
  5223. if( empty( $rexrule ))
  5224. return $input;
  5225. foreach( $rexrule as $rexrulelabel => $rexrulevalue ) {
  5226. $rexrulelabel = strtoupper( $rexrulelabel );
  5227. if( 'UNTIL' != $rexrulelabel )
  5228. $input[$rexrulelabel] = $rexrulevalue;
  5229. else {
  5230. if( $this->_isArrayTimestampDate( $rexrulevalue )) // timestamp date
  5231. $input[$rexrulelabel] = $this->_timestamp2date( $rexrulevalue, 6 );
  5232. elseif( $this->_isArrayDate( $rexrulevalue )) // date-time
  5233. $input[$rexrulelabel] = $this->_date_time_array( $rexrulevalue, 6 );
  5234. elseif( 8 <= strlen( trim( $rexrulevalue ))) // ex. 2006-08-03 10:12:18
  5235. $input[$rexrulelabel] = $this->_date_time_string( $rexrulevalue );
  5236. if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] ))
  5237. $input[$rexrulelabel]['tz'] = 'Z';
  5238. }
  5239. }
  5240. return $input;
  5241. }
  5242. /**
  5243. * convert format for input date to internal date with parameters
  5244. *
  5245. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5246. * @since 2.4.17 - 2008-10-31
  5247. * @param mixed $year
  5248. * @param mixed $month optional
  5249. * @param int $day optional
  5250. * @param int $hour optional
  5251. * @param int $min optional
  5252. * @param int $sec optional
  5253. * @param array $params optional
  5254. * @param string $caller optional
  5255. * @return array
  5256. */
  5257. function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null ) {
  5258. $input = $parno = null;
  5259. $localtime = (( 'dtstart' == $caller ) && in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
  5260. if( $this->_isArrayDate( $year )) {
  5261. if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
  5262. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
  5263. if( isset( $input['params']['TZID'] )) {
  5264. $input['params']['VALUE'] = 'DATE-TIME';
  5265. unset( $year['tz'] );
  5266. }
  5267. $hitval = (( !empty( $year['tz'] ) || !empty( $year[6] ))) ? 7 : 6;
  5268. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
  5269. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $year ), $parno );
  5270. $input['value'] = $this->_date_time_array( $year, $parno );
  5271. }
  5272. elseif( $this->_isArrayTimestampDate( $year )) {
  5273. if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
  5274. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
  5275. if( isset( $input['params']['TZID'] )) {
  5276. $input['params']['VALUE'] = 'DATE-TIME';
  5277. unset( $year['tz'] );
  5278. }
  5279. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3 );
  5280. $hitval = ( isset( $year['tz'] )) ? 7 : 6;
  5281. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
  5282. $input['value'] = $this->_timestamp2date( $year, $parno );
  5283. }
  5284. elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
  5285. if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
  5286. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
  5287. if( isset( $input['params']['TZID'] )) {
  5288. $input['params']['VALUE'] = 'DATE-TIME';
  5289. $parno = 6;
  5290. }
  5291. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
  5292. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
  5293. $input['value'] = $this->_date_time_string( $year, $parno );
  5294. }
  5295. else {
  5296. if( is_array( $params )) {
  5297. if( $localtime ) unset ( $params['VALUE'], $params['TZID'] );
  5298. $input['params'] = $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
  5299. }
  5300. elseif( is_array( $tz )) {
  5301. $input['params'] = $this->_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
  5302. $tz = FALSE;
  5303. }
  5304. elseif( is_array( $hour )) {
  5305. $input['params'] = $this->_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
  5306. $hour = $min = $sec = $tz = FALSE;
  5307. }
  5308. if( isset( $input['params']['TZID'] )) {
  5309. $tz = null;
  5310. $input['params']['VALUE'] = 'DATE-TIME';
  5311. }
  5312. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3 );
  5313. $hitval = ( !empty( $tz )) ? 7 : 6;
  5314. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
  5315. $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
  5316. if( 3 != $parno ) {
  5317. $input['value']['hour'] = ( $hour ) ? $hour : '0';
  5318. $input['value']['min'] = ( $min ) ? $min : '0';
  5319. $input['value']['sec'] = ( $sec ) ? $sec : '0';
  5320. if( !empty( $tz ))
  5321. $input['value']['tz'] = $tz;
  5322. }
  5323. }
  5324. if( 3 == $parno ) {
  5325. $input['params']['VALUE'] = 'DATE';
  5326. unset( $input['value']['tz'] );
  5327. unset( $input['params']['TZID'] );
  5328. }
  5329. elseif( isset( $input['params']['TZID'] ))
  5330. unset( $input['value']['tz'] );
  5331. if( $localtime ) unset( $input['value']['tz'], $input['params']['TZID'] );
  5332. if( isset( $input['value']['tz'] ))
  5333. $input['value']['tz'] = (string) $input['value']['tz'];
  5334. if( !empty( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) &&
  5335. ( !$this->_isOffset( $input['value']['tz'] )))
  5336. $input['params']['TZID'] = $input['value']['tz'];
  5337. return $input;
  5338. }
  5339. /**
  5340. * convert format for input date (UTC) to internal date with parameters
  5341. *
  5342. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5343. * @since 2.4.17 - 2008-10-31
  5344. * @param mixed $year
  5345. * @param mixed $month optional
  5346. * @param int $day optional
  5347. * @param int $hour optional
  5348. * @param int $min optional
  5349. * @param int $sec optional
  5350. * @param array $params optional
  5351. * @return array
  5352. */
  5353. function _setDate2( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  5354. $input = null;
  5355. if( $this->_isArrayDate( $year )) {
  5356. $input['value'] = $this->_date_time_array( $year, 7 );
  5357. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
  5358. }
  5359. elseif( $this->_isArrayTimestampDate( $year )) {
  5360. $input['value'] = $this->_timestamp2date( $year, 7 );
  5361. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
  5362. }
  5363. elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
  5364. $input['value'] = $this->_date_time_string( $year, 7 );
  5365. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
  5366. }
  5367. else {
  5368. $input['value'] = array( 'year' => $year
  5369. , 'month' => $month
  5370. , 'day' => $day
  5371. , 'hour' => $hour
  5372. , 'min' => $min
  5373. , 'sec' => $sec );
  5374. $input['params'] = $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
  5375. }
  5376. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
  5377. if( !isset( $input['value']['hour'] ))
  5378. $input['value']['hour'] = 0;
  5379. if( !isset( $input['value']['min'] ))
  5380. $input['value']['min'] = 0;
  5381. if( !isset( $input['value']['sec'] ))
  5382. $input['value']['sec'] = 0;
  5383. if( !isset( $input['value']['tz'] ) || !$this->_isOffset( $input['value']['tz'] ))
  5384. $input['value']['tz'] = 'Z';
  5385. return $input;
  5386. }
  5387. /**
  5388. * check index and set (an indexed) content in multiple value array
  5389. *
  5390. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5391. * @since 2.5.1 - 2008-11-06
  5392. * @param array $valArr
  5393. * @param mixed $value
  5394. * @param array $params
  5395. * @param array $defaults
  5396. * @param int $index
  5397. * @return void
  5398. */
  5399. function _setMval( & $valArr, $value, $params=FALSE, $defaults=FALSE, $index=FALSE ) {
  5400. if( !is_array( $valArr )) $valArr = array();
  5401. if( $index )
  5402. $index = $index - 1;
  5403. elseif( 0 < count( $valArr )) {
  5404. $index = end( array_keys( $valArr ));
  5405. $index += 1;
  5406. }
  5407. else
  5408. $index = 0;
  5409. $valArr[$index] = array( 'value' => $value, 'params' => $this->_setParams( $params, $defaults ));
  5410. ksort( $valArr );
  5411. }
  5412. /**
  5413. * set input (formatted) parameters- component property attributes
  5414. *
  5415. * default parameters can be set, if missing
  5416. *
  5417. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5418. * @since 1.x.x - 2007-05-01
  5419. * @param array $params
  5420. * @param array $defaults
  5421. * @return array
  5422. */
  5423. function _setParams( $params, $defaults=FALSE ) {
  5424. if( !is_array( $params))
  5425. $params = array();
  5426. $input = array();
  5427. foreach( $params as $paramKey => $paramValue ) {
  5428. if( is_array( $paramValue )) {
  5429. foreach( $paramValue as $pkey => $pValue ) {
  5430. if(( '"' == substr( $pValue, 0, 1 )) && ( '"' == substr( $pValue, -1 )))
  5431. $paramValue[$pkey] = substr( $pValue, 1, ( strlen( $pValue ) - 2 ));
  5432. }
  5433. }
  5434. elseif(( '"' == substr( $paramValue, 0, 1 )) && ( '"' == substr( $paramValue, -1 )))
  5435. $paramValue = substr( $paramValue, 1, ( strlen( $paramValue ) - 2 ));
  5436. if( 'VALUE' == strtoupper( $paramKey ))
  5437. $input['VALUE'] = strtoupper( $paramValue );
  5438. else
  5439. $input[strtoupper( $paramKey )] = $paramValue;
  5440. }
  5441. if( is_array( $defaults )) {
  5442. foreach( $defaults as $paramKey => $paramValue ) {
  5443. if( !isset( $input[$paramKey] ))
  5444. $input[$paramKey] = $paramValue;
  5445. }
  5446. }
  5447. return (0 < count( $input )) ? $input : null;
  5448. }
  5449. /**
  5450. * step date, return updated date, array and timpstamp
  5451. *
  5452. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5453. * @since 2.4.16 - 2008-10-18
  5454. * @param array $date, date to step
  5455. * @param int $timestamp
  5456. * @param array $step, default array( 'day' => 1 )
  5457. * @return void
  5458. */
  5459. function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) {
  5460. foreach( $step as $stepix => $stepvalue )
  5461. $date[$stepix] += $stepvalue;
  5462. $timestamp = $this->_date2timestamp( $date );
  5463. $date = $this->_timestamp2date( $timestamp, 6 );
  5464. foreach( $date as $k => $v ) {
  5465. if( ctype_digit( $v ))
  5466. $date[$k] = (int) $v;
  5467. }
  5468. }
  5469. /**
  5470. * convert timestamp to date array
  5471. *
  5472. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5473. * @since 2.4.16 - 2008-11-01
  5474. * @param mixed $timestamp
  5475. * @param int $parno
  5476. * @return array
  5477. */
  5478. function _timestamp2date( $timestamp, $parno=6 ) {
  5479. if( is_array( $timestamp )) {
  5480. if(( 7 == $parno ) && !empty( $timestamp['tz'] ))
  5481. $tz = $timestamp['tz'];
  5482. $timestamp = $timestamp['timestamp'];
  5483. }
  5484. $output = array( 'year' => date( 'Y', $timestamp )
  5485. , 'month' => date( 'm', $timestamp )
  5486. , 'day' => date( 'd', $timestamp ));
  5487. if( 3 != $parno ) {
  5488. $output['hour'] = date( 'H', $timestamp );
  5489. $output['min'] = date( 'i', $timestamp );
  5490. $output['sec'] = date( 's', $timestamp );
  5491. if( isset( $tz ))
  5492. $output['tz'] = $tz;
  5493. }
  5494. return $output;
  5495. }
  5496. /**
  5497. * convert (numeric) local time offset to seconds correcting localtime to GMT
  5498. *
  5499. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5500. * @since 2.4.16 - 2008-10-19
  5501. * @param string $offset
  5502. * @return integer
  5503. */
  5504. function _tz2offset( $tz ) {
  5505. $tz = trim( (string) $tz );
  5506. $offset = 0;
  5507. if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
  5508. (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
  5509. (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
  5510. (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
  5511. return $offset;
  5512. $hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
  5513. $min2sec = (int) substr( $tz, 3, 2 ) * 60;
  5514. $sec = ( 7 == strlen( $tz )) ? (int) substr( $tz, -2 ) : '00';
  5515. $offset = $hours2sec + $min2sec + $sec;
  5516. $offset = ('-' == substr( $tz, 0, 1 )) ? $offset : -1 * $offset;
  5517. return $offset;
  5518. }
  5519. /*********************************************************************************/
  5520. /*********************************************************************************/
  5521. /**
  5522. * get general component config variables or info about subcomponents
  5523. *
  5524. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5525. * @since 2.5.1 - 2008-11-02
  5526. * @param string $config
  5527. * @return value
  5528. */
  5529. function getConfig( $config ) {
  5530. switch( strtoupper( $config )) {
  5531. case 'ALLOWEMPTY':
  5532. return $this->allowEmpty;
  5533. break;
  5534. case 'COMPSINFO':
  5535. unset( $this->compix );
  5536. $info = array();
  5537. if( isset( $this->components )) {
  5538. foreach( $this->components as $cix => $component ) {
  5539. if( empty( $component )) continue;
  5540. unset( $component->propix );
  5541. $info[$cix]['ordno'] = $cix + 1;
  5542. $info[$cix]['type'] = $component->objName;
  5543. $info[$cix]['uid'] = $component->getProperty( 'uid' );
  5544. $info[$cix]['props'] = $component->getConfig( 'propinfo' );
  5545. $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
  5546. unset( $component->propix );
  5547. }
  5548. }
  5549. return $info;
  5550. break;
  5551. case 'FORMAT':
  5552. return $this->format;
  5553. break;
  5554. case 'LANGUAGE':
  5555. // get language for calendar component as defined in [RFC 1766]
  5556. return $this->language;
  5557. break;
  5558. case 'NL':
  5559. case 'NEWLINECHAR':
  5560. return $this->nl;
  5561. break;
  5562. case 'PROPINFO':
  5563. $output = array();
  5564. if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
  5565. if( empty( $this->uid['value'] )) $this->_makeuid();
  5566. $output['UID'] = 1;
  5567. }
  5568. if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
  5569. if( !empty( $this->summary )) $output['SUMMARY'] = 1;
  5570. if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
  5571. if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
  5572. if( !empty( $this->dtend )) $output['DTEND'] = 1;
  5573. if( !empty( $this->due )) $output['DUE'] = 1;
  5574. if( !empty( $this->duration )) $output['DURATION'] = 1;
  5575. if( !empty( $this->rrule )) $output['RRULE'] = count( $this->rrule );
  5576. if( !empty( $this->rdate )) $output['RDATE'] = count( $this->rdate );
  5577. if( !empty( $this->exdate )) $output['EXDATE'] = count( $this->exdate );
  5578. if( !empty( $this->exrule )) $output['EXRULE'] = count( $this->exrule );
  5579. if( !empty( $this->action )) $output['ACTION'] = 1;
  5580. if( !empty( $this->attach )) $output['ATTACH'] = count( $this->attach );
  5581. if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee );
  5582. if( !empty( $this->categories )) $output['CATEGORIES'] = count( $this->categories );
  5583. if( !empty( $this->class )) $output['CLASS'] = 1;
  5584. if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment );
  5585. if( !empty( $this->completed )) $output['COMPLETED'] = 1;
  5586. if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact );
  5587. if( !empty( $this->created )) $output['CREATED'] = 1;
  5588. if( !empty( $this->freebusy )) $output['FREEBUSY'] = count( $this->freebusy );
  5589. if( !empty( $this->geo )) $output['GEO'] = 1;
  5590. if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1;
  5591. if( !empty( $this->location )) $output['LOCATION'] = 1;
  5592. if( !empty( $this->organizer )) $output['ORGANIZER'] = 1;
  5593. if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1;
  5594. if( !empty( $this->priority )) $output['PRIORITY'] = 1;
  5595. if( !empty( $this->recurrenceid )) $output['RECURRENCE-ID'] = 1;
  5596. if( !empty( $this->relatedto )) $output['RELATED-TO'] = count( $this->relatedto );
  5597. if( !empty( $this->repeat )) $output['REPEAT'] = 1;
  5598. if( !empty( $this->requeststatus )) $output['REQUEST-STATUS'] = count( $this->requeststatus );
  5599. if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources );
  5600. if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
  5601. if( !empty( $this->status )) $output['STATUS'] = 1;
  5602. if( !empty( $this->transp )) $output['TRANSP'] = 1;
  5603. if( !empty( $this->trigger )) $output['TRIGGER'] = 1;
  5604. if( !empty( $this->tzid )) $output['TZID'] = 1;
  5605. if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname );
  5606. if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETTFROM'] = 1;
  5607. if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1;
  5608. if( !empty( $this->tzurl )) $output['TZURL'] = 1;
  5609. if( !empty( $this->url )) $output['URL'] = 1;
  5610. if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
  5611. return $output;
  5612. break;
  5613. case 'UNIQUE_ID':
  5614. if( empty( $this->unique_id ))
  5615. $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
  5616. return $this->unique_id;
  5617. break;
  5618. }
  5619. }
  5620. /**
  5621. * general component config setting
  5622. *
  5623. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5624. * @since 2.4.8 - 2008-10-24
  5625. * @param string $config
  5626. * @param string $value
  5627. * @return void
  5628. */
  5629. function setConfig( $config, $value ) {
  5630. $res = FALSE;
  5631. switch( strtoupper( $config )) {
  5632. case 'ALLOWEMPTY':
  5633. $this->allowEmpty = $value;
  5634. $subcfg = array( 'ALLOWEMPTY' => $value );
  5635. $res = TRUE;
  5636. break;
  5637. case 'FORMAT':
  5638. $value = trim( $value );
  5639. $this->format = $value;
  5640. $this->_createFormat();
  5641. $subcfg = array( 'FORMAT' => $value );
  5642. $res = TRUE;
  5643. break;
  5644. case 'LANGUAGE':
  5645. // set language for calendar component as defined in [RFC 1766]
  5646. $value = trim( $value );
  5647. $this->language = $value;
  5648. $subcfg = array( 'LANGUAGE' => $value );
  5649. $res = TRUE;
  5650. break;
  5651. case 'NL':
  5652. case 'NEWLINECHAR':
  5653. $this->nl = $value;
  5654. $subcfg = array( 'NL' => $value );
  5655. $res = TRUE;
  5656. break;
  5657. case 'UNIQUE_ID':
  5658. $value = trim( $value );
  5659. $this->unique_id = $value;
  5660. $subcfg = array( 'UNIQUE_ID' => $value );
  5661. $res = TRUE;
  5662. break;
  5663. }
  5664. if( !$res ) return FALSE;
  5665. if( isset( $subcfg ) && !empty( $this->components )) {
  5666. foreach( $subcfg as $cfgkey => $cfgvalue ) {
  5667. foreach( $this->components as $cix => $component ) {
  5668. $res = $component->setConfig( $cfgkey, $cfgvalue );
  5669. if( !$res )
  5670. break 2;
  5671. $this->components[$cix] = $component; // PHP4 compliant
  5672. }
  5673. }
  5674. }
  5675. return $res;
  5676. }
  5677. /*********************************************************************************/
  5678. /**
  5679. * delete component property value
  5680. *
  5681. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5682. * @since 2.5.1 - 2008-11-14
  5683. * @param string $propName
  5684. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  5685. * @return bool, if successfull delete TRUE
  5686. */
  5687. function deleteProperty( $propName, $propix=FALSE ) {
  5688. if( $this->_notExistProp( $propName )) return FALSE;
  5689. $propName = strtoupper( $propName );
  5690. if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
  5691. 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
  5692. if( !$propix )
  5693. $propix = ( isset( $this->propdelix[$propName] )) ? $this->propdelix[$propName] + 2 : 1;
  5694. $this->propdelix[$propName] = --$propix;
  5695. }
  5696. $return = FALSE;
  5697. switch( $propName ) {
  5698. case 'ACTION':
  5699. if( !empty( $this->action )) {
  5700. $this->action = '';
  5701. $return = TRUE;
  5702. }
  5703. break;
  5704. case 'ATTACH':
  5705. return $this->deletePropertyM( $this->attach, $propix );
  5706. break;
  5707. case 'ATTENDEE':
  5708. return $this->deletePropertyM( $this->attendee, $propix );
  5709. break;
  5710. case 'CATEGORIES':
  5711. return $this->deletePropertyM( $this->categories, $propix );
  5712. break;
  5713. case 'CLASS':
  5714. if( !empty( $this->class )) {
  5715. $this->class = '';
  5716. $return = TRUE;
  5717. }
  5718. break;
  5719. case 'COMMENT':
  5720. return $this->deletePropertyM( $this->comment, $propix );
  5721. break;
  5722. case 'COMPLETED':
  5723. if( !empty( $this->completed )) {
  5724. $this->completed = '';
  5725. $return = TRUE;
  5726. }
  5727. break;
  5728. case 'CONTACT':
  5729. return $this->deletePropertyM( $this->contact, $propix );
  5730. break;
  5731. case 'CREATED':
  5732. if( !empty( $this->created )) {
  5733. $this->created = '';
  5734. $return = TRUE;
  5735. }
  5736. break;
  5737. case 'DESCRIPTION':
  5738. return $this->deletePropertyM( $this->description, $propix );
  5739. break;
  5740. case 'DTEND':
  5741. if( !empty( $this->dtend )) {
  5742. $this->dtend = '';
  5743. $return = TRUE;
  5744. }
  5745. break;
  5746. case 'DTSTAMP':
  5747. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  5748. return FALSE;
  5749. if( !empty( $this->dtstamp )) {
  5750. $this->dtstamp = '';
  5751. $return = TRUE;
  5752. }
  5753. break;
  5754. case 'DTSTART':
  5755. if( !empty( $this->dtstart )) {
  5756. $this->dtstart = '';
  5757. $return = TRUE;
  5758. }
  5759. break;
  5760. case 'DUE':
  5761. if( !empty( $this->due )) {
  5762. $this->due = '';
  5763. $return = TRUE;
  5764. }
  5765. break;
  5766. case 'DURATION':
  5767. if( !empty( $this->duration )) {
  5768. $this->duration = '';
  5769. $return = TRUE;
  5770. }
  5771. break;
  5772. case 'EXDATE':
  5773. return $this->deletePropertyM( $this->exdate, $propix );
  5774. break;
  5775. case 'EXRULE':
  5776. return $this->deletePropertyM( $this->exrule, $propix );
  5777. break;
  5778. case 'FREEBUSY':
  5779. return $this->deletePropertyM( $this->freebusy, $propix );
  5780. break;
  5781. case 'GEO':
  5782. if( !empty( $this->geo )) {
  5783. $this->geo = '';
  5784. $return = TRUE;
  5785. }
  5786. break;
  5787. case 'LAST-MODIFIED':
  5788. if( !empty( $this->lastmodified )) {
  5789. $this->lastmodified = '';
  5790. $return = TRUE;
  5791. }
  5792. break;
  5793. case 'LOCATION':
  5794. if( !empty( $this->location )) {
  5795. $this->location = '';
  5796. $return = TRUE;
  5797. }
  5798. break;
  5799. case 'ORGANIZER':
  5800. if( !empty( $this->organizer )) {
  5801. $this->organizer = '';
  5802. $return = TRUE;
  5803. }
  5804. break;
  5805. case 'PERCENT-COMPLETE':
  5806. if( !empty( $this->percentcomplete )) {
  5807. $this->percentcomplete = '';
  5808. $return = TRUE;
  5809. }
  5810. break;
  5811. case 'PRIORITY':
  5812. if( !empty( $this->priority )) {
  5813. $this->priority = '';
  5814. $return = TRUE;
  5815. }
  5816. break;
  5817. case 'RDATE':
  5818. return $this->deletePropertyM( $this->rdate, $propix );
  5819. break;
  5820. case 'RECURRENCE-ID':
  5821. if( !empty( $this->recurrenceid )) {
  5822. $this->recurrenceid = '';
  5823. $return = TRUE;
  5824. }
  5825. break;
  5826. case 'RELATED-TO':
  5827. return $this->deletePropertyM( $this->relatedto, $propix );
  5828. break;
  5829. case 'REPEAT':
  5830. if( !empty( $this->repeat )) {
  5831. $this->repeat = '';
  5832. $return = TRUE;
  5833. }
  5834. break;
  5835. case 'REQUEST-STATUS':
  5836. return $this->deletePropertyM( $this->requeststatus, $propix );
  5837. break;
  5838. case 'RESOURCES':
  5839. return $this->deletePropertyM( $this->resources, $propix );
  5840. break;
  5841. case 'RRULE':
  5842. return $this->deletePropertyM( $this->rrule, $propix );
  5843. break;
  5844. case 'SEQUENCE':
  5845. if( !empty( $this->sequence )) {
  5846. $this->sequence = '';
  5847. $return = TRUE;
  5848. }
  5849. break;
  5850. case 'STATUS':
  5851. if( !empty( $this->status )) {
  5852. $this->status = '';
  5853. $return = TRUE;
  5854. }
  5855. break;
  5856. case 'SUMMARY':
  5857. if( !empty( $this->summary )) {
  5858. $this->summary = '';
  5859. $return = TRUE;
  5860. }
  5861. break;
  5862. case 'TRANSP':
  5863. if( !empty( $this->transp )) {
  5864. $this->transp = '';
  5865. $return = TRUE;
  5866. }
  5867. break;
  5868. case 'TRIGGER':
  5869. if( !empty( $this->trigger )) {
  5870. $this->trigger = '';
  5871. $return = TRUE;
  5872. }
  5873. break;
  5874. case 'TZID':
  5875. if( !empty( $this->tzid )) {
  5876. $this->tzid = '';
  5877. $return = TRUE;
  5878. }
  5879. break;
  5880. case 'TZNAME':
  5881. return $this->deletePropertyM( $this->tzname, $propix );
  5882. break;
  5883. case 'TZOFFSETFROM':
  5884. if( !empty( $this->tzoffsetfrom )) {
  5885. $this->tzoffsetfrom = '';
  5886. $return = TRUE;
  5887. }
  5888. break;
  5889. case 'TZOFFSETTO':
  5890. if( !empty( $this->tzoffsetto )) {
  5891. $this->tzoffsetto = '';
  5892. $return = TRUE;
  5893. }
  5894. break;
  5895. case 'TZURL':
  5896. if( !empty( $this->tzurl )) {
  5897. $this->tzurl = '';
  5898. $return = TRUE;
  5899. }
  5900. break;
  5901. case 'UID':
  5902. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  5903. return FALSE;
  5904. if( !empty( $this->uid )) {
  5905. $this->uid = '';
  5906. $return = TRUE;
  5907. }
  5908. break;
  5909. case 'URL':
  5910. if( !empty( $this->url )) {
  5911. $this->url = '';
  5912. $return = TRUE;
  5913. }
  5914. break;
  5915. default:
  5916. $reduced = '';
  5917. if( $propName != 'X-PROP' ) {
  5918. if( !isset( $this->xprop[$propName] )) return FALSE;
  5919. foreach( $this->xprop as $k => $a ) {
  5920. if(( $k != $propName ) && !empty( $a ))
  5921. $reduced[$k] = $a;
  5922. }
  5923. }
  5924. else {
  5925. if( count( $this->xprop ) <= $propix ) return FALSE;
  5926. $xpropno = 0;
  5927. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  5928. if( $propix != $xpropno )
  5929. $reduced[$xpropkey] = $xpropvalue;
  5930. $xpropno++;
  5931. }
  5932. }
  5933. $this->xprop = $reduced;
  5934. return TRUE;
  5935. }
  5936. return $return;
  5937. }
  5938. /*********************************************************************************/
  5939. /**
  5940. * delete component property value, fixing components with multiple occurencies
  5941. *
  5942. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5943. * @since 2.4.5 - 2008-11-07
  5944. * @param array $multiprop, reference to a component property
  5945. * @param int @propix, default 0
  5946. * @return bool TRUE
  5947. */
  5948. function deletePropertyM( & $multiprop, $propix=0 ) {
  5949. if( !isset( $multiprop[$propix])) return FALSE;
  5950. unset( $multiprop[$propix] );
  5951. if( empty( $multiprop )) $multiprop = '';
  5952. return ( isset( $this->multiprop[$propix] )) ? FALSE : TRUE;
  5953. }
  5954. /**
  5955. * get component property value/params
  5956. *
  5957. * if property has multiply values, consequtive function calls are needed
  5958. *
  5959. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5960. * @since 2.5.1 - 2008-11-02
  5961. * @param string $propName, optional
  5962. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  5963. * @param bool $inclParam=FALSE
  5964. * @param bool $specform=FALSE
  5965. * @return mixed
  5966. */
  5967. function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
  5968. if( $this->_notExistProp( $propName )) return FALSE;
  5969. $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
  5970. if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
  5971. 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
  5972. if( !$propix )
  5973. $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
  5974. $this->propix[$propName] = --$propix;
  5975. }
  5976. switch( $propName ) {
  5977. case 'ACTION':
  5978. if( !empty( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value'];
  5979. break;
  5980. case 'ATTACH':
  5981. if( !isset( $this->attach[$propix] )) return FALSE;
  5982. return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value'];
  5983. break;
  5984. case 'ATTENDEE':
  5985. if( !isset( $this->attendee[$propix] )) return FALSE;
  5986. return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
  5987. break;
  5988. case 'CATEGORIES':
  5989. if( !isset( $this->categories[$propix] )) return FALSE;
  5990. return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value'];
  5991. break;
  5992. case 'CLASS':
  5993. if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
  5994. break;
  5995. case 'COMMENT':
  5996. if( !isset( $this->comment[$propix] )) return FALSE;
  5997. return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
  5998. break;
  5999. case 'COMPLETED':
  6000. if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
  6001. break;
  6002. case 'CONTACT':
  6003. if( !isset( $this->contact[$propix] )) return FALSE;
  6004. return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
  6005. break;
  6006. case 'CREATED':
  6007. if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
  6008. break;
  6009. case 'DESCRIPTION':
  6010. if( !isset( $this->description[$propix] )) return FALSE;
  6011. return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
  6012. break;
  6013. case 'DTEND':
  6014. if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
  6015. break;
  6016. case 'DTSTAMP':
  6017. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  6018. return;
  6019. if( !isset( $this->dtstamp['value'] ))
  6020. $this->_makeDtstamp();
  6021. return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
  6022. break;
  6023. case 'DTSTART':
  6024. if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
  6025. break;
  6026. case 'DUE':
  6027. if( !empty( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value'];
  6028. break;
  6029. case 'DURATION':
  6030. if( !isset( $this->duration['value'] )) return FALSE;
  6031. $value = ( $specform ) ? $this->duration2date() : $this->duration['value'];
  6032. return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
  6033. break;
  6034. case 'EXDATE':
  6035. if( !isset( $this->exdate[$propix] )) return FALSE;
  6036. return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
  6037. break;
  6038. case 'EXRULE':
  6039. if( !isset( $this->exrule[$propix] )) return FALSE;
  6040. return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
  6041. break;
  6042. case 'FREEBUSY':
  6043. if( !isset( $this->freebusy[$propix] )) return FALSE;
  6044. return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
  6045. break;
  6046. case 'GEO':
  6047. if( !empty( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value'];
  6048. break;
  6049. case 'LAST-MODIFIED':
  6050. if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
  6051. break;
  6052. case 'LOCATION':
  6053. if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
  6054. break;
  6055. case 'ORGANIZER':
  6056. if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
  6057. break;
  6058. case 'PERCENT-COMPLETE':
  6059. if( !empty( $this->percentcomplete['value'] )) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value'];
  6060. break;
  6061. case 'PRIORITY':
  6062. if( !empty( $this->priority['value'] )) return ( $inclParam ) ? $this->priority : $this->priority['value'];
  6063. break;
  6064. case 'RDATE':
  6065. if( !isset( $this->rdate[$propix] )) return FALSE;
  6066. return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
  6067. break;
  6068. case 'RECURRENCE-ID':
  6069. if( !empty( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value'];
  6070. break;
  6071. case 'RELATED-TO':
  6072. if( !isset( $this->relatedto[$propix] )) return FALSE;
  6073. return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
  6074. break;
  6075. case 'REPEAT':
  6076. if( !empty( $this->repeat['value'] )) return ( $inclParam ) ? $this->repeat : $this->repeat['value'];
  6077. break;
  6078. case 'REQUEST-STATUS':
  6079. if( !isset( $this->requeststatus[$propix] )) return FALSE;
  6080. return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
  6081. break;
  6082. case 'RESOURCES':
  6083. if( !isset( $this->resources[$propix] )) return FALSE;
  6084. return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
  6085. break;
  6086. case 'RRULE':
  6087. if( !isset( $this->rrule[$propix] )) return FALSE;
  6088. return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
  6089. break;
  6090. case 'SEQUENCE':
  6091. if( !empty( $this->sequence['value'] )) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
  6092. break;
  6093. case 'STATUS':
  6094. if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
  6095. break;
  6096. case 'SUMMARY':
  6097. if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
  6098. break;
  6099. case 'TRANSP':
  6100. if( !empty( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value'];
  6101. break;
  6102. case 'TRIGGER':
  6103. if( !empty( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value'];
  6104. break;
  6105. case 'TZID':
  6106. if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
  6107. break;
  6108. case 'TZNAME':
  6109. if( !isset( $this->tzname[$propix] )) return FALSE;
  6110. return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
  6111. break;
  6112. case 'TZOFFSETFROM':
  6113. if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
  6114. break;
  6115. case 'TZOFFSETTO':
  6116. if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
  6117. break;
  6118. case 'TZURL':
  6119. if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
  6120. break;
  6121. case 'UID':
  6122. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  6123. return FALSE;
  6124. if( empty( $this->uid['value'] ))
  6125. $this->_makeuid();
  6126. return ( $inclParam ) ? $this->uid : $this->uid['value'];
  6127. break;
  6128. case 'URL':
  6129. if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
  6130. break;
  6131. default:
  6132. if( $propName != 'X-PROP' ) {
  6133. if( !isset( $this->xprop[$propName] )) return FALSE;
  6134. return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
  6135. : array( $propName, $this->xprop[$propName]['value'] );
  6136. }
  6137. else {
  6138. if( empty( $this->xprop )) return FALSE;
  6139. $xpropno = 0;
  6140. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  6141. if( $propix == $xpropno )
  6142. return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
  6143. : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
  6144. else
  6145. $xpropno++;
  6146. }
  6147. return FALSE; // not found ??
  6148. }
  6149. }
  6150. return FALSE;
  6151. }
  6152. /**
  6153. * general component property setting
  6154. *
  6155. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6156. * @since 2.5.1 - 2008-11-05
  6157. * @param mixed $args variable number of function arguments,
  6158. * first argument is ALWAYS component name,
  6159. * second ALWAYS component value!
  6160. * @return void
  6161. */
  6162. function setProperty() {
  6163. $numargs = func_num_args();
  6164. if( 1 > $numargs ) return FALSE;
  6165. $arglist = func_get_args();
  6166. if( $this->_notExistProp( $arglist[0] )) return FALSE;
  6167. if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
  6168. return FALSE;
  6169. $arglist[0] = strtoupper( $arglist[0] );
  6170. for( $argix=$numargs; $argix < 12; $argix++ ) {
  6171. if( !isset( $arglist[$argix] ))
  6172. $arglist[$argix] = null;
  6173. }
  6174. switch( $arglist[0] ) {
  6175. case 'ACTION':
  6176. return $this->setAction( $arglist[1], $arglist[2] );
  6177. case 'ATTACH':
  6178. return $this->setAttach( $arglist[1], $arglist[2], $arglist[3] );
  6179. case 'ATTENDEE':
  6180. return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
  6181. case 'CATEGORIES':
  6182. return $this->setCategories( $arglist[1], $arglist[2], $arglist[3] );
  6183. case 'CLASS':
  6184. return $this->setClass( $arglist[1], $arglist[2] );
  6185. case 'COMMENT':
  6186. return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
  6187. case 'COMPLETED':
  6188. return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6189. case 'CONTACT':
  6190. return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
  6191. case 'CREATED':
  6192. return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6193. case 'DESCRIPTION':
  6194. return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
  6195. case 'DTEND':
  6196. return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6197. case 'DTSTAMP':
  6198. return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6199. case 'DTSTART':
  6200. return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6201. case 'DUE':
  6202. return $this->setDue( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6203. case 'DURATION':
  6204. return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
  6205. case 'EXDATE':
  6206. return $this->setExdate( $arglist[1], $arglist[2], $arglist[3] );
  6207. case 'EXRULE':
  6208. return $this->setExrule( $arglist[1], $arglist[2], $arglist[3] );
  6209. case 'FREEBUSY':
  6210. return $this->setFreebusy( $arglist[1], $arglist[2], $arglist[3], $arglist[4] );
  6211. case 'GEO':
  6212. return $this->setGeo( $arglist[1], $arglist[2], $arglist[3] );
  6213. case 'LAST-MODIFIED':
  6214. return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6215. case 'LOCATION':
  6216. return $this->setLocation( $arglist[1], $arglist[2] );
  6217. case 'ORGANIZER':
  6218. return $this->setOrganizer( $arglist[1], $arglist[2] );
  6219. case 'PERCENT-COMPLETE':
  6220. return $this->setPercentComplete( $arglist[1], $arglist[2] );
  6221. case 'PRIORITY':
  6222. return $this->setPriority( $arglist[1], $arglist[2] );
  6223. case 'RDATE':
  6224. return $this->setRdate( $arglist[1], $arglist[2], $arglist[3] );
  6225. case 'RECURRENCE-ID':
  6226. return $this->setRecurrenceid( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6227. case 'RELATED-TO':
  6228. return $this->setRelatedTo( $arglist[1], $arglist[2], $arglist[3] );
  6229. case 'REPEAT':
  6230. return $this->setRepeat( $arglist[1], $arglist[2] );
  6231. case 'REQUEST-STATUS':
  6232. return $this->setRequestStatus( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] );
  6233. case 'RESOURCES':
  6234. return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
  6235. case 'RRULE':
  6236. return $this->setRrule( $arglist[1], $arglist[2], $arglist[3] );
  6237. case 'SEQUENCE':
  6238. return $this->setSequence( $arglist[1], $arglist[2] );
  6239. case 'STATUS':
  6240. return $this->setStatus( $arglist[1], $arglist[2] );
  6241. case 'SUMMARY':
  6242. return $this->setSummary( $arglist[1], $arglist[2] );
  6243. case 'TRANSP':
  6244. return $this->setTransp( $arglist[1], $arglist[2] );
  6245. case 'TRIGGER':
  6246. return $this->setTrigger( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8], $arglist[9], $arglist[10], $arglist[11] );
  6247. case 'TZID':
  6248. return $this->setTzid( $arglist[1], $arglist[2] );
  6249. case 'TZNAME':
  6250. return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
  6251. case 'TZOFFSETFROM':
  6252. return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
  6253. case 'TZOFFSETTO':
  6254. return $this->setTzoffsetto( $arglist[1], $arglist[2] );
  6255. case 'TZURL':
  6256. return $this->setTzurl( $arglist[1], $arglist[2] );
  6257. case 'UID':
  6258. return $this->setUid( $arglist[1], $arglist[2] );
  6259. case 'URL':
  6260. return $this->setUrl( $arglist[1], $arglist[2] );
  6261. default:
  6262. return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
  6263. }
  6264. return FALSE;
  6265. }
  6266. /*********************************************************************************/
  6267. /**
  6268. * parse component unparsed data into properties
  6269. *
  6270. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6271. * @since 2.5.2 - 2008-10-23
  6272. * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
  6273. * @return bool FALSE if error occurs during parsing
  6274. *
  6275. */
  6276. function parse( $unparsedtext=null ) {
  6277. if( $unparsedtext ) {
  6278. $this->unparsed = array();
  6279. if( is_array( $unparsedtext )) {
  6280. $comp = & $this;
  6281. foreach ( $unparsedtext as $line ) {
  6282. if( 'END:VALARM' == strtoupper( substr( $line, 0, 10 ))) {
  6283. $this->setComponent( $comp );
  6284. $comp = & $this;
  6285. continue;
  6286. }
  6287. elseif( 'BEGIN:VALARM' == strtoupper( substr( $line, 0, 12 ))) {
  6288. $comp = new valarm();
  6289. continue;
  6290. }
  6291. else
  6292. $comp->unparsed[] = $line;
  6293. }
  6294. }
  6295. else
  6296. $this->unparsed = array( trim( $unparsedtext ));
  6297. }
  6298. elseif( !isset( $this->unparsed ))
  6299. $this->unparsed = array();
  6300. /* concatenate property values spread over several lines */
  6301. $lastix = -1;
  6302. $propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed'
  6303. , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart'
  6304. , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo'
  6305. , 'last-modified', 'location', 'organizer', 'percent-complete'
  6306. , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat'
  6307. , 'request-status', 'resources', 'rrule', 'sequence', 'status'
  6308. , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
  6309. , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
  6310. $proprows = array();
  6311. foreach( $this->unparsed as $line ) {
  6312. $newProp = FALSE;
  6313. foreach ( $propnames as $propname ) {
  6314. if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
  6315. $newProp = TRUE;
  6316. break;
  6317. }
  6318. }
  6319. if( $newProp ) {
  6320. $newProp = FALSE;
  6321. $lastix++;
  6322. $proprows[$lastix] = $line;
  6323. }
  6324. else {
  6325. /* remove line breaks */
  6326. if(( '\n' == substr( $proprows[$lastix], -2 )) &&
  6327. ( ' ' == substr( $line, 0, 1 ))) {
  6328. $proprows[$lastix] = substr( $proprows[$lastix], 0, strlen( $proprows[$lastix] ) - 2 );
  6329. $line = substr( $line, 1 );
  6330. }
  6331. $proprows[$lastix] .= $line;
  6332. }
  6333. }
  6334. /* parse each property 'line' */
  6335. foreach( $proprows as $line ) {
  6336. $line = str_replace( "\n ", '', $line );
  6337. if( '\n' == substr( $line, -2 ))
  6338. $line = substr( $line, 0, strlen( $line ) - 2 );
  6339. /* get propname, (problem with x-properties, otherwise in previous loop) */
  6340. $cix = $propname = null;
  6341. for( $cix=0; $cix < strlen( $line ); $cix++ ) {
  6342. if( in_array( $line{$cix}, array( ':', ';' )))
  6343. break;
  6344. else {
  6345. $propname .= $line{$cix};
  6346. }
  6347. }
  6348. if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) {
  6349. $propname2 = $propname;
  6350. $propname = 'X-';
  6351. }
  6352. /* rest of the line is opt.params and value */
  6353. $line = substr( $line, $cix );
  6354. /* separate attributes from value */
  6355. $attr = array();
  6356. $attrix = -1;
  6357. $strlen = strlen( $line );
  6358. for( $cix=0; $cix < $strlen; $cix++ ) {
  6359. if(( ':' == $line{$cix} ) &&
  6360. ( '://' != substr( $line, $cix, 3 )) &&
  6361. ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
  6362. $attrEnd = TRUE;
  6363. if(( $cix < ( $strlen - 4 )) &&
  6364. ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
  6365. for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
  6366. if( '://' == substr( $line, $c2ix - 2, 3 )) {
  6367. $attrEnd = FALSE;
  6368. break; // an URI with a portnr!!
  6369. }
  6370. }
  6371. }
  6372. if( $attrEnd) {
  6373. $line = substr( $line, $cix + 1 );
  6374. break;
  6375. }
  6376. }
  6377. if( ';' == $line{$cix} )
  6378. $attr[++$attrix] = null;
  6379. else
  6380. $attr[$attrix] .= $line{$cix};
  6381. }
  6382. /* make attributes in array format */
  6383. $propattr = array();
  6384. foreach( $attr as $attribute ) {
  6385. $attrsplit = explode( '=', $attribute, 2 );
  6386. if( 1 < count( $attrsplit ))
  6387. $propattr[$attrsplit[0]] = $attrsplit[1];
  6388. else
  6389. $propattr[] = $attribute;
  6390. }
  6391. /* call setProperty( $propname.. . */
  6392. switch( $propname ) {
  6393. case 'ATTENDEE':
  6394. foreach( $propattr as $pix => $attr ) {
  6395. $attr2 = explode( ',', $attr );
  6396. if( 1 < count( $attr2 ))
  6397. $propattr[$pix] = $attr2;
  6398. }
  6399. $this->setProperty( $propname, $line, $propattr );
  6400. break;
  6401. case 'CATEGORIES':
  6402. case 'RESOURCES':
  6403. if( FALSE !== strpos( $line, ',' )) {
  6404. $content = explode( ',', $line );
  6405. $clen = count( $content );
  6406. for( $cix = 0; $cix < $clen; $cix++ ) {
  6407. if( "\\" == substr($content[$cix], -1)) {
  6408. $content[$cix] .= ','.$content[$cix + 1];
  6409. unset($content[$cix + 1]);
  6410. $cix++;
  6411. }
  6412. }
  6413. if( 1 < count( $content )) {
  6414. $content = array_values( $content );
  6415. foreach( $content as $cix => $contentPart )
  6416. $content[$cix] = $this->_strunrep( $contentPart );
  6417. $this->setProperty( $propname, $content, $propattr );
  6418. break;
  6419. }
  6420. else
  6421. $line = reset( $content );
  6422. }
  6423. case 'X-':
  6424. $propname = ( isset( $propname2 )) ? $propname2 : $propname;
  6425. case 'COMMENT':
  6426. case 'CONTACT':
  6427. case 'DESCRIPTION':
  6428. case 'LOCATION':
  6429. case 'SUMMARY':
  6430. if( empty( $line ))
  6431. $propattr = null;
  6432. $this->setProperty( $propname, $this->_strunrep( $line ), $propattr );
  6433. unset( $propname2 );
  6434. break;
  6435. case 'REQUEST-STATUS':
  6436. $values = explode( ';', $line, 3 );
  6437. $values[1] = ( !isset( $values[1] )) ? null : $this->_strunrep( $values[1] );
  6438. $values[2] = ( !isset( $values[2] )) ? null : $this->_strunrep( $values[2] );
  6439. $this->setProperty( $propname
  6440. , $values[0] // statcode
  6441. , $values[1] // statdesc
  6442. , $values[2] // extdata
  6443. , $propattr );
  6444. break;
  6445. case 'FREEBUSY':
  6446. $fbtype = ( isset( $propattr['FBTYPE'] )) ? $propattr['FBTYPE'] : ''; // force setting default, if missing
  6447. unset( $propattr['FBTYPE'] );
  6448. $values = explode( ',', $line );
  6449. foreach( $values as $vix => $value ) {
  6450. $value2 = explode( '/', $value );
  6451. if( 1 < count( $value2 ))
  6452. $values[$vix] = $value2;
  6453. }
  6454. $this->setProperty( $propname, $fbtype, $values, $propattr );
  6455. break;
  6456. case 'GEO':
  6457. $value = explode( ';', $line, 2 );
  6458. if( 2 > count( $value ))
  6459. $value[1] = null;
  6460. $this->setProperty( $propname, $value[0], $value[1], $propattr );
  6461. break;
  6462. case 'EXDATE':
  6463. $values = ( !empty( $line )) ? explode( ',', $line ) : null;
  6464. $this->setProperty( $propname, $values, $propattr );
  6465. break;
  6466. case 'RDATE':
  6467. if( empty( $line )) {
  6468. $this->setProperty( $propname, $line, $propattr );
  6469. break;
  6470. }
  6471. $values = explode( ',', $line );
  6472. foreach( $values as $vix => $value ) {
  6473. $value2 = explode( '/', $value );
  6474. if( 1 < count( $value2 ))
  6475. $values[$vix] = $value2;
  6476. }
  6477. $this->setProperty( $propname, $values, $propattr );
  6478. break;
  6479. case 'EXRULE':
  6480. case 'RRULE':
  6481. $values = explode( ';', $line );
  6482. $recur = array();
  6483. foreach( $values as $value2 ) {
  6484. if( empty( $value2 ))
  6485. continue; // ;-char in ending position ???
  6486. $value3 = explode( '=', $value2, 2 );
  6487. $rulelabel = strtoupper( $value3[0] );
  6488. switch( $rulelabel ) {
  6489. case 'BYDAY': {
  6490. $value4 = explode( ',', $value3[1] );
  6491. if( 1 < count( $value4 )) {
  6492. foreach( $value4 as $v5ix => $value5 ) {
  6493. $value6 = array();
  6494. $dayno = $dayname = null;
  6495. $value5 = trim( (string) $value5 );
  6496. if(( ctype_alpha( substr( $value5, -1 ))) &&
  6497. ( ctype_alpha( substr( $value5, -2, 1 )))) {
  6498. $dayname = substr( $value5, -2, 2 );
  6499. if( 2 < strlen( $value5 ))
  6500. $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
  6501. }
  6502. if( $dayno )
  6503. $value6[] = $dayno;
  6504. if( $dayname )
  6505. $value6['DAY'] = $dayname;
  6506. $value4[$v5ix] = $value6;
  6507. }
  6508. }
  6509. else {
  6510. $value4 = array();
  6511. $dayno = $dayname = null;
  6512. $value5 = trim( (string) $value3[1] );
  6513. if(( ctype_alpha( substr( $value5, -1 ))) &&
  6514. ( ctype_alpha( substr( $value5, -2, 1 )))) {
  6515. $dayname = substr( $value5, -2, 2 );
  6516. if( 2 < strlen( $value5 ))
  6517. $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
  6518. }
  6519. if( $dayno )
  6520. $value4[] = $dayno;
  6521. if( $dayname )
  6522. $value4['DAY'] = $dayname;
  6523. }
  6524. $recur[$rulelabel] = $value4;
  6525. break;
  6526. }
  6527. default: {
  6528. $value4 = explode( ',', $value3[1] );
  6529. if( 1 < count( $value4 ))
  6530. $value3[1] = $value4;
  6531. $recur[$rulelabel] = $value3[1];
  6532. break;
  6533. }
  6534. } // end - switch $rulelabel
  6535. } // end - foreach( $values.. .
  6536. $this->setProperty( $propname, $recur, $propattr );
  6537. break;
  6538. default:
  6539. $this->setProperty( $propname, $line, $propattr );
  6540. break;
  6541. } // end switch( $propname.. .
  6542. } // end - foreach( $proprows.. .
  6543. unset( $this->unparsed, $proprows );
  6544. if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) {
  6545. for( $six = 0; $six < count( $this->components ); $six++ ) {
  6546. if( !empty( $this->components[$six]->unparsed ))
  6547. $this->components[$six]->parse();
  6548. }
  6549. }
  6550. }
  6551. /*********************************************************************************/
  6552. /*********************************************************************************/
  6553. /**
  6554. * return a copy of this component
  6555. *
  6556. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6557. * @since 2.2.16 - 2007-11-07
  6558. * @return object
  6559. */
  6560. function copy() {
  6561. $serialized_contents = serialize($this);
  6562. $copy = unserialize($serialized_contents);
  6563. unset( $copy->propix );
  6564. return $copy;
  6565. }
  6566. /*********************************************************************************/
  6567. /*********************************************************************************/
  6568. /**
  6569. * delete calendar subcomponent from component container
  6570. *
  6571. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6572. * @since 2.5.1 - 2008-10-15
  6573. * @param mixed $arg1 ordno / component type / component uid
  6574. * @param mixed $arg2 optional, ordno if arg1 = component type
  6575. * @return void
  6576. */
  6577. function deleteComponent( $arg1, $arg2=FALSE ) {
  6578. if( !isset( $this->components )) return FALSE;
  6579. $argType = $index = null;
  6580. if ( ctype_digit( (string) $arg1 )) {
  6581. $argType = 'INDEX';
  6582. $index = (int) $arg1 - 1;
  6583. }
  6584. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  6585. $argType = strtolower( $arg1 );
  6586. $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
  6587. }
  6588. $cix2dC = 0;
  6589. foreach ( $this->components as $cix => $component) {
  6590. if( empty( $component )) continue;
  6591. unset( $component->propix );
  6592. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  6593. unset( $this->components[$cix] );
  6594. return TRUE;
  6595. }
  6596. elseif( $argType == $component->objName ) {
  6597. if( $index == $cix2dC ) {
  6598. unset( $this->components[$cix] );
  6599. return TRUE;
  6600. }
  6601. $cix2dC++;
  6602. }
  6603. elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
  6604. unset( $this->components[$cix] );
  6605. return TRUE;
  6606. }
  6607. }
  6608. return FALSE;
  6609. }
  6610. /**
  6611. * get calendar component subcomponent from component container
  6612. *
  6613. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6614. * @since 2.5.1 - 2008-10-15
  6615. * @param mixed $arg1 optional, ordno/component type/ component uid
  6616. * @param mixed $arg2 optional, ordno if arg1 = component type
  6617. * @return object
  6618. */
  6619. function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
  6620. if( !isset( $this->components )) return FALSE;
  6621. $index = $argType = null;
  6622. if ( !$arg1 ) {
  6623. $argType = 'INDEX';
  6624. $index = $this->compix['INDEX'] =
  6625. ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
  6626. }
  6627. elseif ( ctype_digit( (string) $arg1 )) {
  6628. $argType = 'INDEX';
  6629. $index = (int) $arg1;
  6630. unset( $this->compix );
  6631. }
  6632. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  6633. unset( $this->compix['INDEX'] );
  6634. $argType = strtolower( $arg1 );
  6635. if( !$arg2 )
  6636. $index = $this->compix[$argType] =
  6637. ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
  6638. else
  6639. $index = (int) $arg2;
  6640. }
  6641. $index -= 1;
  6642. $ckeys = array_keys( $this->components );
  6643. if( !empty( $index) && ( $index > end( $ckeys )))
  6644. return FALSE;
  6645. $cix2gC = 0;
  6646. foreach( $this->components as $cix => $component ) {
  6647. if( empty( $component )) continue;
  6648. unset( $component->propix );
  6649. if(( 'INDEX' == $argType ) && ( $index == $cix ))
  6650. return $component->copy();
  6651. elseif( $argType == $component->objName ) {
  6652. if( $index == $cix2gC )
  6653. return $component->copy();
  6654. $cix2gC++;
  6655. }
  6656. elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' ))) {
  6657. unset( $component->propix );
  6658. return $component->copy();
  6659. }
  6660. }
  6661. /* not found.. . */
  6662. unset( $this->compix );
  6663. return false;
  6664. }
  6665. /**
  6666. * add calendar component as subcomponent to container for subcomponents
  6667. *
  6668. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6669. * @since 1.x.x - 2007-04-24
  6670. * @param object $component calendar component
  6671. * @return void
  6672. */
  6673. function addSubComponent ( $component ) {
  6674. $this->setComponent( $component );
  6675. }
  6676. /**
  6677. * add calendar component as subcomponent to container for subcomponents
  6678. *
  6679. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6680. * @since 2.4.13 - 2008-09-24
  6681. * @param object $component calendar component
  6682. * @param mixed $arg1 optional, ordno/component type/ component uid
  6683. * @param mixed $arg2 optional, ordno if arg1 = component type
  6684. * @return bool
  6685. */
  6686. function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
  6687. if( !isset( $this->components )) return FALSE;
  6688. if( '' >= $component->getConfig( 'language'))
  6689. $component->setConfig( 'language', $this->getConfig( 'language' ));
  6690. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  6691. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  6692. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  6693. $component->setConfig( 'format', $this->getConfig( 'format' ));
  6694. if( !in_array( $component->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
  6695. unset( $component->propix );
  6696. /* make sure dtstamp and uid is set */
  6697. $dummy = $component->getProperty( 'dtstamp' );
  6698. $dummy = $component->getProperty( 'uid' );
  6699. }
  6700. if( !$arg1 ) {
  6701. $this->components[] = $component->copy();
  6702. return TRUE;
  6703. }
  6704. $argType = $index = null;
  6705. if ( ctype_digit( (string) $arg1 )) {
  6706. $argType = 'INDEX';
  6707. $index = (int) $arg1 - 1;
  6708. }
  6709. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  6710. $argType = strtolower( $arg1 );
  6711. $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
  6712. }
  6713. $cix2sC = 0;
  6714. foreach ( $this->components as $cix => $component2 ) {
  6715. if( empty( $component2 )) continue;
  6716. unset( $component2->propix );
  6717. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  6718. $this->components[$cix] = $component->copy();
  6719. return TRUE;
  6720. }
  6721. elseif( $argType == $component2->objName ) {
  6722. if( $index == $cix2sC ) {
  6723. $this->components[$cix] = $component->copy();
  6724. return TRUE;
  6725. }
  6726. $cix2sC++;
  6727. }
  6728. elseif( !$argType && ($arg1 == $component2->getProperty( 'uid' ))) {
  6729. $this->components[$cix] = $component->copy();
  6730. return TRUE;
  6731. }
  6732. }
  6733. /* not found.. . insert anyway.. .*/
  6734. $this->components[] = $component->copy();
  6735. return TRUE;
  6736. }
  6737. /**
  6738. * creates formatted output for subcomponents
  6739. *
  6740. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6741. * @since 2.4.10 - 2008-08-06
  6742. * @return string
  6743. */
  6744. function createSubComponent() {
  6745. $output = null;
  6746. foreach( $this->components as $component ) {
  6747. if( empty( $component )) continue;
  6748. if( '' >= $component->getConfig( 'language'))
  6749. $component->setConfig( 'language', $this->getConfig( 'language' ));
  6750. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  6751. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  6752. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  6753. $component->setConfig( 'format', $this->getConfig( 'format' ));
  6754. $output .= $component->createComponent( $this->xcaldecl );
  6755. }
  6756. return $output;
  6757. }
  6758. /********************************************************************************/
  6759. /**
  6760. * break lines at pos 75
  6761. *
  6762. * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
  6763. * break. Long content lines SHOULD be split into a multiple line
  6764. * representations using a line "folding" technique. That is, a long
  6765. * line can be split between any two characters by inserting a CRLF
  6766. * immediately followed by a single linear white space character (i.e.,
  6767. * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
  6768. * of CRLF followed immediately by a single linear white space character
  6769. * is ignored (i.e., removed) when processing the content type.
  6770. *
  6771. * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
  6772. * the reserved expression "\n" in the arg $string could be broken up by the
  6773. * folding of lines, causing ambiguity in the return string.
  6774. * Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
  6775. *
  6776. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6777. * @since 2.2.8 - 2006-09-03
  6778. * @param string $value
  6779. * @return string
  6780. */
  6781. function _size75( $string ) {
  6782. $strlen = strlen( $string );
  6783. $tmp = $string;
  6784. $string = null;
  6785. while( $strlen > 75 ) {
  6786. $breakAtChar = 75;
  6787. if( substr( $tmp, ( $breakAtChar - 1 ), strlen( '\n' )) == '\n' )
  6788. $breakAtChar = $breakAtChar - 1;
  6789. $string .= substr( $tmp, 0, $breakAtChar );
  6790. $string .= $this->nl;
  6791. $tmp = ' '.substr( $tmp, $breakAtChar );
  6792. $strlen = strlen( $tmp );
  6793. } // while
  6794. $string .= rtrim( $tmp ); // the rest
  6795. if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
  6796. $string .= $this->nl;
  6797. return $string;
  6798. }
  6799. /**
  6800. * special characters management output
  6801. *
  6802. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6803. * @since 2.3.3 - 2007-12-20
  6804. * @param string $string
  6805. * @return string
  6806. */
  6807. function _strrep( $string ) {
  6808. switch( $this->format ) {
  6809. case 'xcal':
  6810. $string = str_replace( '\n', $this->nl, $string);
  6811. $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
  6812. break;
  6813. default:
  6814. $pos = 0;
  6815. while( $pos <= strlen( $string )) {
  6816. $pos = strpos( $string, "\\", $pos );
  6817. if( FALSE === $pos )
  6818. break;
  6819. if( !in_array( $string{($pos + 1)}, array( 'n', 'N', 'r', ',', ';' ))) {
  6820. $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
  6821. $pos += 1;
  6822. }
  6823. $pos += 1;
  6824. }
  6825. if( FALSE !== strpos( $string, '"' ))
  6826. $string = str_replace('"', "'", $string);
  6827. if( FALSE !== strpos( $string, ',' ))
  6828. $string = str_replace(',', '\,', $string);
  6829. if( FALSE !== strpos( $string, ';' ))
  6830. $string = str_replace(';', '\;', $string);
  6831. if( FALSE !== strpos( $string, "\r\n" ))
  6832. $string = str_replace( "\r\n", '\n', $string);
  6833. elseif( FALSE !== strpos( $string, "\r" ))
  6834. $string = str_replace( "\r", '\n', $string);
  6835. if( FALSE !== strpos( $string, '\N' ))
  6836. $string = str_replace( '\N', '\n', $string);
  6837. // if( FALSE !== strpos( $string, $this->nl ))
  6838. $string = str_replace( $this->nl, '\n', $string);
  6839. break;
  6840. }
  6841. return $string;
  6842. }
  6843. /**
  6844. * special characters management input (from iCal file)
  6845. *
  6846. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6847. * @since 2.3.3 - 2007-11-23
  6848. * @param string $string
  6849. * @return string
  6850. */
  6851. function _strunrep( $string ) {
  6852. $string = str_replace( '\\\\', '\\', $string);
  6853. $string = str_replace( '\,', ',', $string);
  6854. $string = str_replace( '\;', ';', $string);
  6855. // $string = str_replace( '\n', $this->nl, $string); // ??
  6856. return $string;
  6857. }
  6858. }
  6859. /*********************************************************************************/
  6860. /*********************************************************************************/
  6861. /**
  6862. * class for calendar component VEVENT
  6863. *
  6864. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6865. * @since 2.5.1 - 2008-10-12
  6866. */
  6867. class vevent extends calendarComponent {
  6868. var $attach;
  6869. var $attendee;
  6870. var $categories;
  6871. var $comment;
  6872. var $contact;
  6873. var $class;
  6874. var $created;
  6875. var $description;
  6876. var $dtend;
  6877. var $dtstart;
  6878. var $duration;
  6879. var $exdate;
  6880. var $exrule;
  6881. var $geo;
  6882. var $lastmodified;
  6883. var $location;
  6884. var $organizer;
  6885. var $priority;
  6886. var $rdate;
  6887. var $recurrenceid;
  6888. var $relatedto;
  6889. var $requeststatus;
  6890. var $resources;
  6891. var $rrule;
  6892. var $sequence;
  6893. var $status;
  6894. var $summary;
  6895. var $transp;
  6896. var $url;
  6897. var $xprop;
  6898. // component subcomponents container
  6899. var $components;
  6900. /**
  6901. * constructor for calendar component VEVENT object
  6902. *
  6903. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6904. * @since 2.5.1 - 2008-10-31
  6905. * @return void
  6906. */
  6907. function vevent() {
  6908. $this->calendarComponent();
  6909. $this->attach = '';
  6910. $this->attendee = '';
  6911. $this->categories = '';
  6912. $this->class = '';
  6913. $this->comment = '';
  6914. $this->contact = '';
  6915. $this->created = '';
  6916. $this->description = '';
  6917. $this->dtstart = '';
  6918. $this->dtend = '';
  6919. $this->duration = '';
  6920. $this->exdate = '';
  6921. $this->exrule = '';
  6922. $this->geo = '';
  6923. $this->lastmodified = '';
  6924. $this->location = '';
  6925. $this->organizer = '';
  6926. $this->priority = '';
  6927. $this->rdate = '';
  6928. $this->recurrenceid = '';
  6929. $this->relatedto = '';
  6930. $this->requeststatus = '';
  6931. $this->resources = '';
  6932. $this->rrule = '';
  6933. $this->sequence = '';
  6934. $this->status = '';
  6935. $this->summary = '';
  6936. $this->transp = '';
  6937. $this->url = '';
  6938. $this->xprop = '';
  6939. $this->components = array();
  6940. }
  6941. /**
  6942. * create formatted output for calendar component VEVENT object instance
  6943. *
  6944. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6945. * @since 2.5.1 - 2008-11-07
  6946. * @param array $xcaldecl
  6947. * @return string
  6948. */
  6949. function createComponent( &$xcaldecl ) {
  6950. $objectname = $this->_createFormat();
  6951. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  6952. $component .= $this->createUid();
  6953. $component .= $this->createDtstamp();
  6954. $component .= $this->createAttach();
  6955. $component .= $this->createAttendee();
  6956. $component .= $this->createCategories();
  6957. $component .= $this->createComment();
  6958. $component .= $this->createContact();
  6959. $component .= $this->createClass();
  6960. $component .= $this->createCreated();
  6961. $component .= $this->createDescription();
  6962. $component .= $this->createDtstart();
  6963. $component .= $this->createDtend();
  6964. $component .= $this->createDuration();
  6965. $component .= $this->createExdate();
  6966. $component .= $this->createExrule();
  6967. $component .= $this->createGeo();
  6968. $component .= $this->createLastModified();
  6969. $component .= $this->createLocation();
  6970. $component .= $this->createOrganizer();
  6971. $component .= $this->createPriority();
  6972. $component .= $this->createRdate();
  6973. $component .= $this->createRrule();
  6974. $component .= $this->createRelatedTo();
  6975. $component .= $this->createRequestStatus();
  6976. $component .= $this->createRecurrenceid();
  6977. $component .= $this->createResources();
  6978. $component .= $this->createSequence();
  6979. $component .= $this->createStatus();
  6980. $component .= $this->createSummary();
  6981. $component .= $this->createTransp();
  6982. $component .= $this->createUrl();
  6983. $component .= $this->createXprop();
  6984. $component .= $this->createSubComponent();
  6985. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  6986. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  6987. foreach( $this->xcaldecl as $localxcaldecl )
  6988. $xcaldecl[] = $localxcaldecl;
  6989. }
  6990. return $component;
  6991. }
  6992. }
  6993. /*********************************************************************************/
  6994. /*********************************************************************************/
  6995. /**
  6996. * class for calendar component VTODO
  6997. *
  6998. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6999. * @since 2.5.1 - 2008-10-12
  7000. */
  7001. class vtodo extends calendarComponent {
  7002. var $attach;
  7003. var $attendee;
  7004. var $categories;
  7005. var $comment;
  7006. var $completed;
  7007. var $contact;
  7008. var $class;
  7009. var $created;
  7010. var $description;
  7011. var $dtstart;
  7012. var $due;
  7013. var $duration;
  7014. var $exdate;
  7015. var $exrule;
  7016. var $geo;
  7017. var $lastmodified;
  7018. var $location;
  7019. var $organizer;
  7020. var $percentcomplete;
  7021. var $priority;
  7022. var $rdate;
  7023. var $recurrenceid;
  7024. var $relatedto;
  7025. var $requeststatus;
  7026. var $resources;
  7027. var $rrule;
  7028. var $sequence;
  7029. var $status;
  7030. var $summary;
  7031. var $url;
  7032. var $xprop;
  7033. // component subcomponents container
  7034. var $components;
  7035. /**
  7036. * constructor for calendar component VTODO object
  7037. *
  7038. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7039. * @since 2.5.1 - 2008-10-31
  7040. * @return void
  7041. */
  7042. function vtodo() {
  7043. $this->calendarComponent();
  7044. $this->attach = '';
  7045. $this->attendee = '';
  7046. $this->categories = '';
  7047. $this->class = '';
  7048. $this->comment = '';
  7049. $this->completed = '';
  7050. $this->contact = '';
  7051. $this->created = '';
  7052. $this->description = '';
  7053. $this->dtstart = '';
  7054. $this->due = '';
  7055. $this->duration = '';
  7056. $this->exdate = '';
  7057. $this->exrule = '';
  7058. $this->geo = '';
  7059. $this->lastmodified = '';
  7060. $this->location = '';
  7061. $this->organizer = '';
  7062. $this->percentcomplete = '';
  7063. $this->priority = '';
  7064. $this->rdate = '';
  7065. $this->recurrenceid = '';
  7066. $this->relatedto = '';
  7067. $this->requeststatus = '';
  7068. $this->resources = '';
  7069. $this->rrule = '';
  7070. $this->sequence = '';
  7071. $this->status = '';
  7072. $this->summary = '';
  7073. $this->url = '';
  7074. $this->xprop = '';
  7075. $this->components = array();
  7076. }
  7077. /**
  7078. * create formatted output for calendar component VTODO object instance
  7079. *
  7080. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7081. * @since 2.5.1 - 2008-11-07
  7082. * @param array $xcaldecl
  7083. * @return string
  7084. */
  7085. function createComponent( &$xcaldecl ) {
  7086. $objectname = $this->_createFormat();
  7087. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7088. $component .= $this->createUid();
  7089. $component .= $this->createDtstamp();
  7090. $component .= $this->createAttach();
  7091. $component .= $this->createAttendee();
  7092. $component .= $this->createCategories();
  7093. $component .= $this->createClass();
  7094. $component .= $this->createComment();
  7095. $component .= $this->createCompleted();
  7096. $component .= $this->createContact();
  7097. $component .= $this->createCreated();
  7098. $component .= $this->createDescription();
  7099. $component .= $this->createDtstart();
  7100. $component .= $this->createDue();
  7101. $component .= $this->createDuration();
  7102. $component .= $this->createExdate();
  7103. $component .= $this->createExrule();
  7104. $component .= $this->createGeo();
  7105. $component .= $this->createLastModified();
  7106. $component .= $this->createLocation();
  7107. $component .= $this->createOrganizer();
  7108. $component .= $this->createPercentComplete();
  7109. $component .= $this->createPriority();
  7110. $component .= $this->createRdate();
  7111. $component .= $this->createRelatedTo();
  7112. $component .= $this->createRequestStatus();
  7113. $component .= $this->createRecurrenceid();
  7114. $component .= $this->createResources();
  7115. $component .= $this->createRrule();
  7116. $component .= $this->createSequence();
  7117. $component .= $this->createStatus();
  7118. $component .= $this->createSummary();
  7119. $component .= $this->createUrl();
  7120. $component .= $this->createXprop();
  7121. $component .= $this->createSubComponent();
  7122. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7123. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7124. foreach( $this->xcaldecl as $localxcaldecl )
  7125. $xcaldecl[] = $localxcaldecl;
  7126. }
  7127. return $component;
  7128. }
  7129. }
  7130. /*********************************************************************************/
  7131. /*********************************************************************************/
  7132. /**
  7133. * class for calendar component VJOURNAL
  7134. *
  7135. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7136. * @since 2.5.1 - 2008-10-12
  7137. */
  7138. class vjournal extends calendarComponent {
  7139. var $attach;
  7140. var $attendee;
  7141. var $categories;
  7142. var $comment;
  7143. var $contact;
  7144. var $class;
  7145. var $created;
  7146. var $description;
  7147. var $dtstart;
  7148. var $exdate;
  7149. var $exrule;
  7150. var $lastmodified;
  7151. var $organizer;
  7152. var $rdate;
  7153. var $recurrenceid;
  7154. var $relatedto;
  7155. var $requeststatus;
  7156. var $rrule;
  7157. var $sequence;
  7158. var $status;
  7159. var $summary;
  7160. var $url;
  7161. var $xprop;
  7162. /**
  7163. * constructor for calendar component VJOURNAL object
  7164. *
  7165. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7166. * @since 2.5.1 - 2008-10-31
  7167. * @return void
  7168. */
  7169. function vjournal() {
  7170. $this->calendarComponent();
  7171. $this->attach = '';
  7172. $this->attendee = '';
  7173. $this->categories = '';
  7174. $this->class = '';
  7175. $this->comment = '';
  7176. $this->contact = '';
  7177. $this->created = '';
  7178. $this->description = '';
  7179. $this->dtstart = '';
  7180. $this->exdate = '';
  7181. $this->exrule = '';
  7182. $this->lastmodified = '';
  7183. $this->organizer = '';
  7184. $this->rdate = '';
  7185. $this->recurrenceid = '';
  7186. $this->relatedto = '';
  7187. $this->requeststatus = '';
  7188. $this->rrule = '';
  7189. $this->sequence = '';
  7190. $this->status = '';
  7191. $this->summary = '';
  7192. $this->url = '';
  7193. $this->xprop = '';
  7194. }
  7195. /**
  7196. * create formatted output for calendar component VJOURNAL object instance
  7197. *
  7198. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7199. * @since 2.5.1 - 2008-10-12
  7200. * @param array $xcaldecl
  7201. * @return string
  7202. */
  7203. function createComponent( &$xcaldecl ) {
  7204. $objectname = $this->_createFormat();
  7205. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7206. $component .= $this->createUid();
  7207. $component .= $this->createDtstamp();
  7208. $component .= $this->createAttach();
  7209. $component .= $this->createAttendee();
  7210. $component .= $this->createCategories();
  7211. $component .= $this->createClass();
  7212. $component .= $this->createComment();
  7213. $component .= $this->createContact();
  7214. $component .= $this->createCreated();
  7215. $component .= $this->createDescription();
  7216. $component .= $this->createDtstart();
  7217. $component .= $this->createExdate();
  7218. $component .= $this->createExrule();
  7219. $component .= $this->createLastModified();
  7220. $component .= $this->createOrganizer();
  7221. $component .= $this->createRdate();
  7222. $component .= $this->createRequestStatus();
  7223. $component .= $this->createRecurrenceid();
  7224. $component .= $this->createRelatedTo();
  7225. $component .= $this->createRrule();
  7226. $component .= $this->createSequence();
  7227. $component .= $this->createStatus();
  7228. $component .= $this->createSummary();
  7229. $component .= $this->createUrl();
  7230. $component .= $this->createXprop();
  7231. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7232. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7233. foreach( $this->xcaldecl as $localxcaldecl )
  7234. $xcaldecl[] = $localxcaldecl;
  7235. }
  7236. return $component;
  7237. }
  7238. }
  7239. /*********************************************************************************/
  7240. /*********************************************************************************/
  7241. /**
  7242. * class for calendar component VFREEBUSY
  7243. *
  7244. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7245. * @since 2.5.1 - 2008-10-12
  7246. */
  7247. class vfreebusy extends calendarComponent {
  7248. var $attendee;
  7249. var $comment;
  7250. var $contact;
  7251. var $dtend;
  7252. var $dtstart;
  7253. var $duration;
  7254. var $freebusy;
  7255. var $organizer;
  7256. var $requeststatus;
  7257. var $url;
  7258. var $xprop;
  7259. // component subcomponents container
  7260. var $components;
  7261. /**
  7262. * constructor for calendar component VFREEBUSY object
  7263. *
  7264. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7265. * @since 2.5.1 - 2008-10-31
  7266. * @return void
  7267. */
  7268. function vfreebusy() {
  7269. $this->calendarComponent();
  7270. $this->attendee = '';
  7271. $this->comment = '';
  7272. $this->contact = '';
  7273. $this->dtend = '';
  7274. $this->dtstart = '';
  7275. $this->duration = '';
  7276. $this->freebusy = '';
  7277. $this->organizer = '';
  7278. $this->requeststatus = '';
  7279. $this->url = '';
  7280. $this->xprop = '';
  7281. }
  7282. /**
  7283. * create formatted output for calendar component VFREEBUSY object instance
  7284. *
  7285. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7286. * @since 2.3.1 - 2007-11-19
  7287. * @param array $xcaldecl
  7288. * @return string
  7289. */
  7290. function createComponent( &$xcaldecl ) {
  7291. $objectname = $this->_createFormat();
  7292. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7293. $component .= $this->createUid();
  7294. $component .= $this->createDtstamp();
  7295. $component .= $this->createAttendee();
  7296. $component .= $this->createComment();
  7297. $component .= $this->createContact();
  7298. $component .= $this->createDtstart();
  7299. $component .= $this->createDtend();
  7300. $component .= $this->createDuration();
  7301. $component .= $this->createFreebusy();
  7302. $component .= $this->createOrganizer();
  7303. $component .= $this->createRequestStatus();
  7304. $component .= $this->createUrl();
  7305. $component .= $this->createXprop();
  7306. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7307. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7308. foreach( $this->xcaldecl as $localxcaldecl )
  7309. $xcaldecl[] = $localxcaldecl;
  7310. }
  7311. return $component;
  7312. }
  7313. }
  7314. /*********************************************************************************/
  7315. /*********************************************************************************/
  7316. /**
  7317. * class for calendar component VALARM
  7318. *
  7319. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7320. * @since 2.5.1 - 2008-10-12
  7321. */
  7322. class valarm extends calendarComponent {
  7323. var $action;
  7324. var $attach;
  7325. var $attendee;
  7326. var $description;
  7327. var $duration;
  7328. var $repeat;
  7329. var $summary;
  7330. var $trigger;
  7331. var $xprop;
  7332. /**
  7333. * constructor for calendar component VALARM object
  7334. *
  7335. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7336. * @since 2.5.1 - 2008-10-31
  7337. * @return void
  7338. */
  7339. function valarm() {
  7340. $this->calendarComponent();
  7341. $this->action = '';
  7342. $this->attach = '';
  7343. $this->attendee = '';
  7344. $this->description = '';
  7345. $this->duration = '';
  7346. $this->repeat = '';
  7347. $this->summary = '';
  7348. $this->trigger = '';
  7349. $this->xprop = '';
  7350. }
  7351. /**
  7352. * create formatted output for calendar component VALARM object instance
  7353. *
  7354. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7355. * @since 2.5.1 - 2008-10-22
  7356. * @param array $xcaldecl
  7357. * @return string
  7358. */
  7359. function createComponent( &$xcaldecl ) {
  7360. $objectname = $this->_createFormat();
  7361. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7362. $component .= $this->createAction();
  7363. $component .= $this->createAttach();
  7364. $component .= $this->createAttendee();
  7365. $component .= $this->createDescription();
  7366. $component .= $this->createDuration();
  7367. $component .= $this->createRepeat();
  7368. $component .= $this->createSummary();
  7369. $component .= $this->createTrigger();
  7370. $component .= $this->createXprop();
  7371. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7372. return $component;
  7373. }
  7374. }
  7375. /**********************************************************************************
  7376. /*********************************************************************************/
  7377. /**
  7378. * class for calendar component VTIMEZONE
  7379. *
  7380. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7381. * @since 2.5.1 - 2008-10-12
  7382. */
  7383. class vtimezone extends calendarComponent {
  7384. var $timezonetype;
  7385. var $comment;
  7386. var $dtstart;
  7387. var $lastmodified;
  7388. var $rdate;
  7389. var $rrule;
  7390. var $tzid;
  7391. var $tzname;
  7392. var $tzoffsetfrom;
  7393. var $tzoffsetto;
  7394. var $tzurl;
  7395. var $xprop;
  7396. // component subcomponents container
  7397. var $components;
  7398. /**
  7399. * constructor for calendar component VTIMEZONE object
  7400. *
  7401. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7402. * @since 2.5.1 - 2008-10-31
  7403. * @param string $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
  7404. * @return void
  7405. */
  7406. function vtimezone( $timezonetype=FALSE ) {
  7407. if( !$timezonetype )
  7408. $this->timezonetype = 'VTIMEZONE';
  7409. else
  7410. $this->timezonetype = strtoupper( $timezonetype );
  7411. $this->calendarComponent();
  7412. $this->comment = '';
  7413. $this->dtstart = '';
  7414. $this->lastmodified = '';
  7415. $this->rdate = '';
  7416. $this->rrule = '';
  7417. $this->tzid = '';
  7418. $this->tzname = '';
  7419. $this->tzoffsetfrom = '';
  7420. $this->tzoffsetto = '';
  7421. $this->tzurl = '';
  7422. $this->xprop = '';
  7423. $this->components = array();
  7424. }
  7425. /**
  7426. * create formatted output for calendar component VTIMEZONE object instance
  7427. *
  7428. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7429. * @since 2.5.1 - 2008-10-25
  7430. * @param array $xcaldecl
  7431. * @return string
  7432. */
  7433. function createComponent( &$xcaldecl ) {
  7434. $objectname = $this->_createFormat();
  7435. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7436. $component .= $this->createTzid();
  7437. $component .= $this->createLastModified();
  7438. $component .= $this->createTzurl();
  7439. $component .= $this->createDtstart();
  7440. $component .= $this->createTzoffsetfrom();
  7441. $component .= $this->createTzoffsetto();
  7442. $component .= $this->createComment();
  7443. $component .= $this->createRdate();
  7444. $component .= $this->createRrule();
  7445. $component .= $this->createTzname();
  7446. $component .= $this->createXprop();
  7447. $component .= $this->createSubComponent();
  7448. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7449. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7450. foreach( $this->xcaldecl as $localxcaldecl )
  7451. $xcaldecl[] = $localxcaldecl;
  7452. }
  7453. return $component;
  7454. }
  7455. }
  7456. ?>