iCalcreator.class.php 323 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501
  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. */
  89. function __construct() {
  90. $this->_makeVersion();
  91. $this->calscale = null;
  92. $this->method = null;
  93. $this->_makeUnique_id();
  94. $this->prodid = null;
  95. $this->xprop = array();
  96. /**
  97. * language = <Text identifying a language, as defined in [RFC 1766]>
  98. */
  99. if( defined( 'ICAL_LANG' ))
  100. $this->setConfig( 'language', ICAL_LANG );
  101. $this->setConfig( 'allowEmpty', TRUE );
  102. $this->setConfig( 'nl', "\n" );
  103. $this->setConfig( 'format', 'iCal');
  104. $this->directory = null;
  105. $this->filename = null;
  106. $this->url = null;
  107. $this->setConfig( 'delimiter', DIRECTORY_SEPARATOR );
  108. $this->xcaldecl = array();
  109. $this->components = array();
  110. }
  111. /*********************************************************************************/
  112. /**
  113. * Property Name: CALSCALE
  114. */
  115. /**
  116. * creates formatted output for calendar property calscale
  117. *
  118. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  119. * @since 2.4.8 - 2008-10-21
  120. * @return string
  121. */
  122. function createCalscale() {
  123. if( empty( $this->calscale )) return FALSE;
  124. switch( $this->format ) {
  125. case 'xcal':
  126. return ' calscale="'.$this->calscale.'"'.$this->nl;
  127. break;
  128. default:
  129. return 'CALSCALE:'.$this->calscale.$this->nl;
  130. break;
  131. }
  132. }
  133. /**
  134. * set calendar property calscale
  135. *
  136. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  137. * @since 2.4.8 - 2008-10-21
  138. * @param string $value
  139. * @return void
  140. */
  141. function setCalscale( $value ) {
  142. if( empty( $value )) return FALSE;
  143. $this->calscale = $value;
  144. }
  145. /*********************************************************************************/
  146. /**
  147. * Property Name: METHOD
  148. */
  149. /**
  150. * creates formatted output for calendar property method
  151. *
  152. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  153. * @since 0.9.7 - 2006-11-20
  154. * @return string
  155. */
  156. function createMethod() {
  157. if( empty( $this->method )) return FALSE;
  158. switch( $this->format ) {
  159. case 'xcal':
  160. return ' method="'.$this->method.'"'.$this->nl;
  161. break;
  162. default:
  163. return 'METHOD:'.$this->method.$this->nl;
  164. break;
  165. }
  166. }
  167. /**
  168. * set calendar property method
  169. *
  170. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  171. * @since 2.4.8 - 2008-20-23
  172. * @param string $value
  173. * @return bool
  174. */
  175. function setMethod( $value ) {
  176. if( empty( $value )) return FALSE;
  177. $this->method = $value;
  178. return TRUE;
  179. }
  180. /*********************************************************************************/
  181. /**
  182. * Property Name: PRODID
  183. *
  184. * The identifier is RECOMMENDED to be the identical syntax to the
  185. * [RFC 822] addr-spec. A good method to assure uniqueness is to put the
  186. * domain name or a domain literal IP address of the host on which.. .
  187. */
  188. /**
  189. * creates formatted output for calendar property prodid
  190. *
  191. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  192. * @since 0.9.7 - 2006-11-20
  193. * @return string
  194. */
  195. function createProdid() {
  196. if( !isset( $this->prodid ))
  197. $this->_makeProdid();
  198. switch( $this->format ) {
  199. case 'xcal':
  200. return ' prodid="'.$this->prodid.'"'.$this->nl;
  201. break;
  202. default:
  203. return 'PRODID:'.$this->prodid.$this->nl;
  204. break;
  205. }
  206. }
  207. /**
  208. * make default value for calendar prodid
  209. *
  210. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  211. * @since 0.3.0 - 2006-08-10
  212. * @return void
  213. */
  214. function _makeProdid() {
  215. $this->prodid = '-//'.$this->unique_id.'//NONSGML '.ICALCREATOR_VERSION.'//'.strtoupper( $this->language );
  216. }
  217. /**
  218. * Conformance: The property MUST be specified once in an iCalendar object.
  219. * Description: The vendor of the implementation SHOULD assure that this
  220. * is a globally unique identifier; using some technique such as an FPI
  221. * value, as defined in [ISO 9070].
  222. */
  223. /**
  224. * make default unique_id for calendar prodid
  225. *
  226. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  227. * @since 0.3.0 - 2006-08-10
  228. * @return void
  229. */
  230. function _makeUnique_id() {
  231. $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
  232. }
  233. /*********************************************************************************/
  234. /**
  235. * Property Name: VERSION
  236. *
  237. * Description: A value of "2.0" corresponds to this memo.
  238. */
  239. /**
  240. * creates formatted output for calendar property version
  241. *
  242. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  243. * @since 0.9.7 - 2006-11-20
  244. * @return string
  245. */
  246. function createVersion() {
  247. if( empty( $this->version ))
  248. $this->_makeVersion();
  249. switch( $this->format ) {
  250. case 'xcal':
  251. return ' version="'.$this->version.'"'.$this->nl;
  252. break;
  253. default:
  254. return 'VERSION:'.$this->version.$this->nl;
  255. break;
  256. }
  257. }
  258. /**
  259. * set default calendar version
  260. *
  261. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  262. * @since 0.3.0 - 2006-08-10
  263. * @return void
  264. */
  265. function _makeVersion() {
  266. $this->version = '2.0';
  267. }
  268. /**
  269. * set calendar version
  270. *
  271. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  272. * @since 2.4.8 - 2008-10-23
  273. * @param string $value
  274. * @return void
  275. */
  276. function setVersion( $value ) {
  277. if( empty( $value )) return FALSE;
  278. $this->version = $value;
  279. return TRUE;
  280. }
  281. /*********************************************************************************/
  282. /**
  283. * Property Name: x-prop
  284. */
  285. /**
  286. * creates formatted output for calendar property x-prop, iCal format only
  287. *
  288. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  289. * @since 2.4.11 - 2008-11-03
  290. * @return string
  291. */
  292. function createXprop() {
  293. if( 'xcal' == $this->format )
  294. return false;
  295. if( 0 >= count( $this->xprop ))
  296. return;
  297. $output = null;
  298. $toolbox = new calendarComponent();
  299. $toolbox->setConfig( 'language', $this->getConfig( 'language' ));
  300. $toolbox->setConfig( 'nl', $this->getConfig( 'nl' ));
  301. $toolbox->_createFormat( $this->getConfig( 'format' ));
  302. foreach( $this->xprop as $label => $xpropPart ) {
  303. if( empty( $xpropPart['value'] )) {
  304. $output .= $toolbox->_createElement( $label );
  305. continue;
  306. }
  307. $attributes = $toolbox->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
  308. if( is_array( $xpropPart['value'] )) {
  309. foreach( $xpropPart['value'] as $pix => $theXpart )
  310. $xpropPart['value'][$pix] = $toolbox->_strrep( $theXpart );
  311. $xpropPart['value'] = implode( ',', $xpropPart['value'] );
  312. }
  313. else
  314. $xpropPart['value'] = $toolbox->_strrep( $xpropPart['value'] );
  315. $output .= $toolbox->_createElement( $label, $attributes, $xpropPart['value'] );
  316. }
  317. return $output;
  318. }
  319. /**
  320. * set calendar property x-prop
  321. *
  322. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  323. * @since 2.4.11 - 2008-11-04
  324. * @param string $label
  325. * @param string $value
  326. * @param array $params optional
  327. * @return bool
  328. */
  329. function setXprop( $label, $value, $params=FALSE ) {
  330. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  331. if( empty( $label )) return FALSE;
  332. $xprop = array( 'value' => $value );
  333. $toolbox = new calendarComponent();
  334. $xprop['params'] = $toolbox->_setParams( $params );
  335. if( !is_array( $this->xprop )) $this->xprop = array();
  336. $this->xprop[strtoupper( $label )] = $xprop;
  337. return TRUE;
  338. }
  339. /*********************************************************************************/
  340. /**
  341. * delete calendar property value
  342. *
  343. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  344. * @since 2.4.5 - 2008-11-14
  345. * @param mixed $propName, bool FALSE => X-property
  346. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  347. * @return bool, if successfull delete
  348. */
  349. function deleteProperty( $propName, $propix=FALSE ) {
  350. $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
  351. if( !$propix )
  352. $propix = ( isset( $this->propdelix[$propName] )) ? $this->propdelix[$propName] + 2 : 1;
  353. $this->propdelix[$propName] = --$propix;
  354. $return = FALSE;
  355. switch( $propName ) {
  356. case 'CALSCALE':
  357. if( isset( $this->calscale )) {
  358. $this->calscale = null;
  359. $return = TRUE;
  360. }
  361. break;
  362. case 'METHOD':
  363. if( isset( $this->method )) {
  364. $this->method = null;
  365. $return = TRUE;
  366. }
  367. break;
  368. default:
  369. $reduced = array();
  370. if( $propName != 'X-PROP' ) {
  371. if( !isset( $this->xprop[$propName] )) return FALSE;
  372. foreach( $this->xprop as $k => $a ) {
  373. if(( $k != $propName ) && !empty( $a ))
  374. $reduced[$k] = $a;
  375. }
  376. }
  377. else {
  378. if( count( $this->xprop ) <= $propix ) return FALSE;
  379. $xpropno = 0;
  380. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  381. if( $propix != $xpropno )
  382. $reduced[$xpropkey] = $xpropvalue;
  383. $xpropno++;
  384. }
  385. }
  386. $this->xprop = $reduced;
  387. return TRUE;
  388. }
  389. return $return;
  390. }
  391. /**
  392. * get calendar property value/params
  393. *
  394. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  395. * @since 2.5.1 - 2008-11-02
  396. * @param string $propName, optional
  397. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  398. * @param bool $inclParam=FALSE
  399. * @return mixed
  400. */
  401. function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) {
  402. $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
  403. if( 'X-PROP' == $propName ) {
  404. if( !$propix )
  405. $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
  406. $this->propix[$propName] = --$propix;
  407. }
  408. switch( $propName ) {
  409. case 'CALSCALE':
  410. return ( !empty( $this->calscale )) ? $this->calscale : null;
  411. break;
  412. case 'METHOD':
  413. return ( !empty( $this->method )) ? $this->method : null;
  414. break;
  415. case 'PRODID':
  416. if( empty( $this->prodid ))
  417. $this->_makeProdid();
  418. return $this->prodid;
  419. break;
  420. case 'VERSION':
  421. return ( !empty( $this->version )) ? $this->version : null;
  422. break;
  423. default:
  424. if( $propName != 'X-PROP' ) {
  425. if( !isset( $this->xprop[$propName] )) return FALSE;
  426. return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
  427. : array( $propName, $this->xprop[$propName]['value'] );
  428. }
  429. else {
  430. if( empty( $this->xprop )) return FALSE;
  431. $xpropno = 0;
  432. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  433. if( $propix == $xpropno )
  434. return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
  435. : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
  436. else
  437. $xpropno++;
  438. }
  439. return FALSE; // not found ??
  440. }
  441. }
  442. return FALSE;
  443. }
  444. /**
  445. * general vcalendar property setting
  446. *
  447. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  448. * @since 2.2.13 - 2007-11-04
  449. * @param mixed $args variable number of function arguments,
  450. * first argument is ALWAYS component name,
  451. * second ALWAYS component value!
  452. * @return bool
  453. */
  454. function setProperty () {
  455. $numargs = func_num_args();
  456. if( 1 > $numargs )
  457. return FALSE;
  458. $arglist = func_get_args();
  459. $arglist[0] = strtoupper( $arglist[0] );
  460. switch( $arglist[0] ) {
  461. case 'CALSCALE':
  462. return $this->setCalscale( $arglist[1] );
  463. case 'METHOD':
  464. return $this->setMethod( $arglist[1] );
  465. case 'VERSION':
  466. return $this->setVersion( $arglist[1] );
  467. default:
  468. if( !isset( $arglist[1] )) $arglist[1] = null;
  469. if( !isset( $arglist[2] )) $arglist[2] = null;
  470. return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
  471. }
  472. return FALSE;
  473. }
  474. /*********************************************************************************/
  475. /**
  476. * get vcalendar config values or * calendar components
  477. *
  478. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  479. * @since 2.4.10 - 2008-10-23
  480. * @param string $config
  481. * @return value
  482. */
  483. function getConfig( $config ) {
  484. switch( strtoupper( $config )) {
  485. case 'ALLOWEMPTY':
  486. return $this->allowEmpty;
  487. break;
  488. case 'COMPSINFO':
  489. unset( $this->compix );
  490. $info = array();
  491. foreach( $this->components as $cix => $component ) {
  492. if( empty( $component )) continue;
  493. unset( $component->propix );
  494. $info[$cix]['ordno'] = $cix + 1;
  495. $info[$cix]['type'] = $component->objName;
  496. $info[$cix]['uid'] = $component->getProperty( 'uid' );
  497. $info[$cix]['props'] = $component->getConfig( 'propinfo' );
  498. $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
  499. unset( $component->propix );
  500. }
  501. return $info;
  502. break;
  503. case 'DELIMITER':
  504. return $this->delimiter;
  505. break;
  506. case 'DIRECTORY':
  507. if( empty( $this->directory ))
  508. $this->directory = '.';
  509. return $this->directory;
  510. break;
  511. case 'DIRFILE':
  512. return $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$this->getConfig( 'filename' );
  513. break;
  514. case 'FILEINFO':
  515. return array( $this->getConfig( 'directory' )
  516. , $this->getConfig( 'filename' )
  517. , $this->getConfig( 'filesize' ));
  518. break;
  519. case 'FILENAME':
  520. if( empty( $this->filename )) {
  521. if( 'xcal' == $this->format )
  522. $this->filename = date( 'YmdHis' ).'.xml'; // recommended xcs.. .
  523. else
  524. $this->filename = date( 'YmdHis' ).'.ics';
  525. }
  526. return $this->filename;
  527. break;
  528. case 'FILESIZE':
  529. $size = 0;
  530. if( empty( $this->url )) {
  531. $dirfile = $this->getConfig( 'dirfile' );
  532. if( FALSE === ( $size = filesize( $dirfile )))
  533. $size = 0;
  534. clearstatcache();
  535. }
  536. return $size;
  537. break;
  538. case 'FORMAT':
  539. return $this->format;
  540. break;
  541. case 'LANGUAGE':
  542. /* get language for calendar component as defined in [RFC 1766] */
  543. return $this->language;
  544. break;
  545. case 'NL':
  546. case 'NEWLINECHAR':
  547. return $this->nl;
  548. break;
  549. case 'UNIQUE_ID':
  550. return $this->unique_id;
  551. break;
  552. case 'URL':
  553. if( !empty( $this->url ))
  554. return $this->url;
  555. else
  556. return FALSE;
  557. break;
  558. }
  559. }
  560. /**
  561. * general vcalendar config setting
  562. *
  563. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  564. * @since 2.4.8 - 2008-10-24
  565. * @param string $config
  566. * @param string $value
  567. * @return void
  568. */
  569. function setConfig( $config, $value ) {
  570. $res = FALSE;
  571. switch( strtoupper( $config )) {
  572. case 'ALLOWEMPTY':
  573. $this->allowEmpty = $value;
  574. $subcfg = array( 'ALLOWEMPTY' => $value );
  575. $res = TRUE;
  576. break;
  577. case 'DELIMITER':
  578. $this->delimiter = $value;
  579. return TRUE;
  580. break;
  581. case 'DIRECTORY':
  582. $value = trim( $value );
  583. $nl = $this->getConfig('delimiter');
  584. if( $nl == substr( $value, ( 0 - strlen( $nl ))))
  585. $value = substr( $value, 0, ( strlen( $value ) - strlen( $nl )));
  586. if( is_dir( $value )) {
  587. /* local directory */
  588. clearstatcache();
  589. $this->directory = $value;
  590. $this->url = null;
  591. return TRUE;
  592. }
  593. else
  594. return FALSE;
  595. break;
  596. case 'FILENAME':
  597. $value = trim( $value );
  598. if( !empty( $this->url )) {
  599. /* remote directory+file - URL */
  600. $this->filename = $value;
  601. return TRUE;
  602. }
  603. $dirfile = $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$value;
  604. if( file_exists( $dirfile )) {
  605. /* local existing file */
  606. if( is_readable( $dirfile ) || is_writable( $dirfile )) {
  607. clearstatcache();
  608. $this->filename = $value;
  609. return TRUE;
  610. }
  611. else
  612. return FALSE;
  613. }
  614. elseif( FALSE !== touch( $dirfile )) {
  615. /* new local file created */
  616. $this->filename = $value;
  617. return TRUE;
  618. }
  619. else
  620. return FALSE;
  621. break;
  622. case 'FORMAT':
  623. $value = trim( $value );
  624. if( 'xcal' == strtolower( $value )) {
  625. $this->format = 'xcal';
  626. $this->attributeDelimiter = $this->nl;
  627. $this->valueInit = null;
  628. }
  629. else {
  630. $this->format = null;
  631. $this->attributeDelimiter = ';';
  632. $this->valueInit = ':';
  633. }
  634. $subcfg = array( 'FORMAT' => $value );
  635. $res = TRUE;
  636. break;
  637. case 'LANGUAGE':
  638. // set language for calendar component as defined in [RFC 1766]
  639. $value = trim( $value );
  640. $this->language = $value;
  641. $subcfg = array( 'LANGUAGE' => $value );
  642. $res = TRUE;
  643. break;
  644. case 'NL':
  645. case 'NEWLINECHAR':
  646. $this->nl = $value;
  647. $subcfg = array( 'NL' => $value );
  648. $res = TRUE;
  649. break;
  650. case 'UNIQUE_ID':
  651. $value = trim( $value );
  652. $this->unique_id = $value;
  653. $subcfg = array( 'UNIQUE_ID' => $value );
  654. $res = TRUE;
  655. break;
  656. case 'URL':
  657. /* remote file - URL */
  658. $value = trim( $value );
  659. $value = str_replace( 'HTTP://', 'http://', $value );
  660. $value = str_replace( 'WEBCAL://', 'http://', $value );
  661. $value = str_replace( 'webcal://', 'http://', $value );
  662. $this->url = $value;
  663. $this->directory = null;
  664. $parts = pathinfo( $value );
  665. return $this->setConfig( 'filename', $parts['basename'] );
  666. break;
  667. }
  668. if( !$res ) return FALSE;
  669. if( isset( $subcfg ) && !empty( $this->components )) {
  670. foreach( $subcfg as $cfgkey => $cfgvalue ) {
  671. foreach( $this->components as $cix => $component ) {
  672. $res = $component->setConfig( $cfgkey, $cfgvalue );
  673. if( !$res )
  674. break 2;
  675. $this->components[$cix] = $component->copy(); // PHP4 compliant
  676. }
  677. }
  678. }
  679. return $res;
  680. }
  681. /*********************************************************************************/
  682. /**
  683. * add calendar component to container
  684. *
  685. * alias to setComponent
  686. *
  687. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  688. * @since 1.x.x - 2007-04-24
  689. * @param object $component calendar component
  690. * @return void
  691. */
  692. function addComponent( $component ) {
  693. $this->setComponent( $component );
  694. }
  695. /**
  696. * delete calendar component from container
  697. *
  698. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  699. * @since 2.4.10 - 2008-08-05
  700. * @param mixed $arg1 ordno / component type / component uid
  701. * @param mixed $arg2 optional, ordno if arg1 = component type
  702. * @return void
  703. */
  704. function deleteComponent( $arg1, $arg2=FALSE ) {
  705. $argType = $index = null;
  706. if ( ctype_digit( (string) $arg1 )) {
  707. $argType = 'INDEX';
  708. $index = (int) $arg1 - 1;
  709. }
  710. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  711. $argType = strtolower( $arg1 );
  712. $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
  713. }
  714. $cix1dC = 0;
  715. foreach ( $this->components as $cix => $component) {
  716. if( empty( $component )) continue;
  717. unset( $component->propix );
  718. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  719. unset( $this->components[$cix] );
  720. return TRUE;
  721. }
  722. elseif( $argType == $component->objName ) {
  723. if( $index == $cix1dC ) {
  724. unset( $this->components[$cix] );
  725. return TRUE;
  726. }
  727. $cix1dC++;
  728. }
  729. elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
  730. unset( $this->components[$cix] );
  731. return TRUE;
  732. }
  733. }
  734. return FALSE;
  735. }
  736. /**
  737. * get calendar component from container
  738. *
  739. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  740. * @since 2.4.10 - 2008-08-06
  741. * @param mixed $arg1 optional, ordno/component type/ component uid
  742. * @param mixed $arg2 optional, ordno if arg1 = component type
  743. * @return object
  744. */
  745. function getComponent( $arg1=FALSE, $arg2=FALSE ) {
  746. $index = $argType = null;
  747. if ( !$arg1 ) {
  748. $argType = 'INDEX';
  749. $index = $this->compix['INDEX'] =
  750. ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
  751. }
  752. elseif ( ctype_digit( (string) $arg1 )) {
  753. $argType = 'INDEX';
  754. $index = (int) $arg1;
  755. unset( $this->compix );
  756. }
  757. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  758. unset( $this->compix['INDEX'] );
  759. $argType = strtolower( $arg1 );
  760. if( !$arg2 )
  761. $index = $this->compix[$argType] =
  762. ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
  763. else
  764. $index = (int) $arg2;
  765. }
  766. $index -= 1;
  767. $ckeys = array_keys( $this->components );
  768. if( !empty( $index) && ( $index > end( $ckeys )))
  769. return FALSE;
  770. $cix1gC = 0;
  771. foreach ( $this->components as $cix => $component) {
  772. if( empty( $component )) continue;
  773. unset( $component->propix );
  774. if(( 'INDEX' == $argType ) && ( $index == $cix ))
  775. return $component->copy();
  776. elseif( $argType == $component->objName ) {
  777. if( $index == $cix1gC )
  778. return $component->copy();
  779. $cix1gC++;
  780. }
  781. elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
  782. unset( $component->propix );
  783. return $component->copy();
  784. }
  785. }
  786. /* not found.. . */
  787. unset( $this->compix );
  788. return FALSE;
  789. }
  790. /**
  791. * select components from calendar on date basis
  792. *
  793. * Ensure DTSTART is set for every component.
  794. * No date controls occurs.
  795. *
  796. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  797. * @since 2.4.16 - 2008-10-18
  798. * @param int $startY optional, start Year, default current Year
  799. * @param int $startM optional, start Month, default current Month
  800. * @param int $startD optional, start Day, default current Day
  801. * @param int $endY optional, end Year, default $startY
  802. * @param int $endY optional, end Month, default $startM
  803. * @param int $endY optional, end Day, default $startD
  804. * @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s)
  805. * @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][]
  806. * TRUE => output : array[] (ignores split)
  807. * @param bool $any optional, TRUE (default) - select component that take place within period
  808. * FALSE - only components that starts within period
  809. * @param bool $split optional, TRUE (default) - one component copy every day it take place during the
  810. * period (implies flat=FALSE)
  811. * FALSE - one occurance of component only in output array</tr>
  812. * @return array or FALSE
  813. */
  814. function selectComponents( $startY=FALSE, $startM=FALSE, $startD=FALSE, $endY=FALSE, $endM=FALSE, $endD=FALSE, $cType=FALSE, $flat=FALSE, $any=TRUE, $split=TRUE ) {
  815. /* check if empty calendar */
  816. if( 0 >= count( $this->components )) return FALSE;
  817. /* check default dates */
  818. if( !$startY ) $startY = date( 'Y' );
  819. if( !$startM ) $startM = date( 'm' );
  820. if( !$startD ) $startD = date( 'd' );
  821. $startDate = mktime( 0, 0, 0, $startM, $startD, $startY );
  822. if( !$endY ) $endY = $startY;
  823. if( !$endM ) $endM = $startM;
  824. if( !$endD ) $endD = $startD;
  825. $endDate = mktime( 23, 59, 59, $endM, $endD, $endY );
  826. /* check component types */
  827. $validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' );
  828. if( is_array( $cType )) {
  829. foreach( $cType as $cix => $theType ) {
  830. $cType[$cix] = $theType = strtolower( $theType );
  831. if( !in_array( $theType, $validTypes ))
  832. $cType[$cix] = 'vevent';
  833. }
  834. $cType = array_unique( $cType );
  835. }
  836. elseif( !empty( $cType )) {
  837. $cType = strtolower( $cType );
  838. if( !in_array( $cType, $validTypes ))
  839. $cType = array( 'vevent' );
  840. else
  841. $cType = array( $cType );
  842. }
  843. else
  844. $cType = $validTypes;
  845. if( 0 >= count( $cType ))
  846. $cType = $validTypes;
  847. /* iterate components */
  848. $result = array();
  849. foreach ( $this->components as $cix => $component ) {
  850. if( empty( $component )) continue;
  851. unset( $component->propix, $start );
  852. /* deselect unvalid type components */
  853. if( !in_array( $component->objName, $cType )) continue;
  854. /* deselect components without dtstart set */
  855. if( FALSE === ( $start = $component->getProperty( 'dtstart' ))) continue;
  856. $dtendExist = $dueExist = $durationExist = $endAllDayEvent = FALSE;
  857. unset( $end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $workstart, $workend ); // clean up
  858. $startWdate = $component->_date2timestamp( $start );
  859. $startDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
  860. /* get end date from dtend/due/duration properties */
  861. $end = $component->getProperty( 'dtend' );
  862. if( !empty( $end )) {
  863. $dtendExist = TRUE;
  864. $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
  865. }
  866. // if( !empty($end)) echo 'selectComp 1 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  867. if( empty($end) && ( $component->objName == 'vtodo' )) {
  868. $end = $component->getProperty( 'due' );
  869. if( !empty( $end )) {
  870. $dueExist = TRUE;
  871. $endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
  872. }
  873. // if( !empty($end)) echo 'selectComp 2 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  874. }
  875. if( !empty( $end ) && !isset( $end['hour'] )) {
  876. /* a DTEND without time part regards an event that ends the day before,
  877. for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */
  878. $endAllDayEvent = TRUE;
  879. $endWdate = mktime( 23, 59, 59, $end['month'], ($end['day'] - 1), $end['year'] );
  880. $end['year'] = date( 'Y', $endWdate );
  881. $end['month'] = date( 'm', $endWdate );
  882. $end['day'] = date( 'd', $endWdate );
  883. $end['hour'] = 23;
  884. $end['min'] = $end['sec'] = 59;
  885. // if( !empty($end)) echo 'selectComp 3 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  886. }
  887. if( empty( $end )) {
  888. $end = $component->getProperty( 'duration', FALSE, FALSE, TRUE );// in dtend (array) format
  889. if( !empty( $end ))
  890. $durationExist = TRUE;
  891. // if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  892. }
  893. if( empty( $end )) { // assume one day duration if missing end date
  894. $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
  895. // if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  896. }
  897. $endWdate = $component->_date2timestamp( $end );
  898. if( $endWdate < $startWdate ) { // MUST be after start date!!
  899. $end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
  900. $endWdate = $component->_date2timestamp( $end );
  901. }
  902. $rdurWsecs = $endWdate - $startWdate; // compute component duration in seconds
  903. $rdur = $component->_date2duration( $start, $end ); // compute component duration, array
  904. /* make a list of optional exclude dates for component occurence from exrule and exdate */
  905. $exdatelist = array();
  906. $workstart = $component->_timestamp2date(( $startDate - $rdurWsecs ), 6);
  907. $workend = $component->_timestamp2date(( $endDate + $rdurWsecs ), 6);
  908. while( FALSE !== ( $exrule = $component->getProperty( 'exrule' ))) // check exrule
  909. $component->_recur2date( $exdatelist, $exrule, $start, $workstart, $workend );
  910. while( FALSE !== ( $exdate = $component->getProperty( 'exdate' ))) { // check exdate
  911. foreach( $exdate as $theExdate ) {
  912. $exWdate = $component->_date2timestamp( $theExdate );
  913. if((( $startDate - $rdurWsecs ) <= $exWdate ) && ( $endDate >= $exWdate ))
  914. $exdatelist[$exWdate] = TRUE;
  915. }
  916. }
  917. /* if 'any' components, check repeating components, removing all excluding dates */
  918. if( TRUE === $any ) {
  919. /* make a list of optional repeating dates for component occurence, rrule, rdate */
  920. $recurlist = array();
  921. while( FALSE !== ( $rrule = $component->getProperty( 'rrule' ))) // check rrule
  922. $component->_recur2date( $recurlist, $rrule, $start, $workstart, $workend );
  923. foreach( $recurlist as $recurkey => $recurvalue ) // key=match date as timestamp
  924. $recurlist[$recurkey] = $rdurWsecs; // add duration in seconds
  925. while( FALSE !== ( $rdate = $component->getProperty( 'rdate' ))) { // check rdate
  926. foreach( $rdate as $theRdate ) {
  927. if( is_array( $theRdate ) && ( 2 == count( $theRdate )) && // all days within PERIOD
  928. array_key_exists( '0', $theRdate ) && array_key_exists( '1', $theRdate )) {
  929. $rstart = $component->_date2timestamp( $theRdate[0] );
  930. if(( $rstart < ( $startDate - $rdurWsecs )) || ( $rstart > $endDate ))
  931. continue;
  932. if( isset( $theRdate[1]['year'] )) // date-date period
  933. $rend = $component->_date2timestamp( $theRdate[1] );
  934. else { // date-duration period
  935. $rend = $component->duration2date( $theRdate[0], $theRdate[1] );
  936. $rend = $component->_date2timestamp( $rend );
  937. }
  938. if((( $startDate - $rdurWsecs ) <= $rstart ) && ( $endDate >= $rstart ))
  939. $recurlist[$rstart] = ( $rstart - $rend ); // set start date + rdate duration in seconds
  940. } // PERIOD end
  941. else { // single date
  942. $theRdate = $component->_date2timestamp( $theRdate );
  943. if((( $startDate - $rdurWsecs ) <= $theRdate ) && ( $endDate >= $theRdate ))
  944. $recurlist[$theRdate] = $rdurWsecs; // set start date + event duration in seconds
  945. }
  946. }
  947. }
  948. if( 0 < count( $recurlist )) {
  949. ksort( $recurlist );
  950. foreach( $recurlist as $recurkey => $durvalue ) {
  951. if((( $startDate - $rdurWsecs ) > $recurkey ) || ( $endDate < $recurkey )) // not within period
  952. continue;
  953. if( isset( $exdatelist[$recurkey] )) // check excluded dates
  954. continue;
  955. if( $startWdate >= $recurkey ) // exclude component start date
  956. continue;
  957. $component2 = $component->copy();
  958. $rstart = $component2->_timestamp2date( $recurkey, 6);
  959. $datevalue = $rstart['month'].'/'.$rstart['day'].'/'.$rstart['year'];
  960. if( isset( $start['hour'] ) || isset( $start['min'] ) || isset( $start['sec'] )) {
  961. $datevalue .= ( isset( $rstart['hour'] )) ? ' '.$rstart['hour'] : ' 00';
  962. $datevalue .= ( isset( $rstart['min'] )) ? ':'.$rstart['min'] : ':00';
  963. $datevalue .= ( isset( $rstart['sec'] )) ? ':'.$rstart['sec'] : ':00';
  964. }
  965. $datestring = date( $startDateFormat, strtotime( $datevalue ));
  966. if( isset( $start['tz'] ))
  967. $datestring .= ' '.$start['tz'];
  968. $component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
  969. $rend = $component2->_timestamp2date(( $recurkey + $durvalue ), 6);
  970. if( $dtendExist || $dueExist ) {
  971. if( $endAllDayEvent ) {
  972. $rend2 = mktime( 0, 0, 0, $rend['month'], ($rend['day'] + 1), $rend['year'] );
  973. $datevalue = date( 'm', $rend2 ).'/'.date( 'd', $rend2 ).'/'.date( 'Y', $rend2 );
  974. }
  975. else {
  976. $datevalue = $rend['month'].'/'.$rend['day'].'/'.$rend['year'];
  977. if( isset( $end['hour'] ) || isset( $end['min'] ) || isset( $end['sec'] )) {
  978. $datevalue .= ( isset( $rend['hour'] )) ? ' '.$rend['hour'] : ' 00';
  979. $datevalue .= ( isset( $rend['min'] )) ? ':'.$rend['min'] : ':00';
  980. $datevalue .= ( isset( $rend['sec'] )) ? ':'.$rend['sec'] : ':00';
  981. }
  982. }
  983. $datestring = date( $endDateFormat, strtotime( $datevalue ));
  984. if( isset( $end['tz'] ))
  985. $datestring .= ' '.$end['tz'];
  986. if( $dtendExist )
  987. $component2->setProperty( 'X-CURRENT-DTEND', $datestring );
  988. elseif( $dueExist )
  989. $component2->setProperty( 'X-CURRENT-DUE', $datestring );
  990. }
  991. $rend = $component2->_date2timestamp( $rend );
  992. $rstart = $recurkey;
  993. /* add repeating components within valid dates to output array, only start date */
  994. if( $flat )
  995. $result[] = $component2->copy(); // copy to output
  996. elseif( $split ) {
  997. if( $rend > $endDate )
  998. $rend = $endDate;
  999. while( $rstart <= $rend ) { // iterate
  1000. $wd = getdate( $rstart );
  1001. if(( $rstart > $startDate ) && // date after dtstart
  1002. !isset( $exdatelist[$rstart] )) // check exclude date
  1003. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component2->copy(); // copy to output
  1004. $rstart += ( 24*60*60 ); // step one day
  1005. }
  1006. }
  1007. elseif(( $rstart >= $startDate ) && // date within period
  1008. !isset( $exdatelist[$rstart] )) { // check exclude date
  1009. $wd = getdate( $rstart );
  1010. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component2->copy(); // copy to output
  1011. }
  1012. }
  1013. }
  1014. /* deselect components with startdate/enddate not within period */
  1015. if(( $endWdate < $startDate ) || ( $startWdate > $endDate )) continue;
  1016. }
  1017. /* deselect components with startdate not within period */
  1018. elseif(( $startWdate < $startDate ) || ( $startWdate > $endDate )) continue;
  1019. /* add selected components within valid dates to output array */
  1020. if( $flat )
  1021. $result[] = $component->copy(); // copy to output;
  1022. elseif( $split ) {
  1023. if( $endWdate > $endDate )
  1024. $endWdate = $endDate; // use period end date
  1025. if( !isset( $exdatelist[$startWdate] )) { // check excluded dates
  1026. if( $startWdate < $startDate )
  1027. $startWdate = $startDate; // use period start date
  1028. while( $startWdate <= $endWdate ) { // iterate
  1029. $wd = getdate( $startWdate );
  1030. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component->copy(); // copy to output
  1031. $startWdate += ( 24*60*60 ); // step one day
  1032. }
  1033. }
  1034. } // use component date
  1035. elseif( !isset( $exdatelist[$startWdate] ) && // check excluded dates
  1036. ( $startWdate >= $startDate )) { // within period
  1037. $wd = getdate( $startWdate );
  1038. $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component->copy(); // copy to output
  1039. }
  1040. }
  1041. if( 0 >= count( $result )) return FALSE;
  1042. elseif( !$flat ) {
  1043. foreach( $result as $y => $yeararr ) {
  1044. foreach( $yeararr as $m => $montharr ) {
  1045. ksort( $result[$y][$m] );
  1046. }
  1047. ksort( $result[$y] );
  1048. }
  1049. ksort( $result );
  1050. }
  1051. return $result;
  1052. }
  1053. /**
  1054. * add calendar component to container
  1055. *
  1056. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1057. * @since 2.4.10 - 2008-08-06
  1058. * @param object $component calendar component
  1059. * @param mixed $arg1 optional, ordno/component type/ component uid
  1060. * @param mixed $arg2 optional, ordno if arg1 = component type
  1061. * @return void
  1062. */
  1063. function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
  1064. if( '' >= $component->getConfig( 'language'))
  1065. $component->setConfig( 'language', $this->getConfig( 'language' ));
  1066. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  1067. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  1068. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  1069. $component->setConfig( 'format', $this->getConfig( 'format' ));
  1070. if( !in_array( $component->objName, array( 'valarm', 'vtimezone' ))) {
  1071. unset( $component->propix );
  1072. /* make sure dtstamp and uid is set */
  1073. $dummy1 = $component->getProperty( 'dtstamp' );
  1074. $dummy2 = $component->getProperty( 'uid' );
  1075. }
  1076. if( !$arg1 ) {
  1077. $this->components[] = $component->copy();
  1078. return TRUE;
  1079. }
  1080. $argType = $index = null;
  1081. if ( ctype_digit( (string) $arg1 )) {
  1082. $argType = 'INDEX';
  1083. $index = (int) $arg1 - 1;
  1084. }
  1085. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  1086. $argType = strtolower( $arg1 );
  1087. $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
  1088. }
  1089. $cix1sC = 0;
  1090. foreach ( $this->components as $cix => $component2) {
  1091. if( empty( $component2 )) continue;
  1092. unset( $component2->propix );
  1093. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  1094. $this->components[$cix] = $component->copy();
  1095. return TRUE;
  1096. }
  1097. elseif( $argType == $component2->objName ) {
  1098. if( $index == $cix1sC ) {
  1099. $this->components[$cix] = $component->copy();
  1100. return TRUE;
  1101. }
  1102. $cix1sC++;
  1103. }
  1104. elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) {
  1105. $this->components[$cix] = $component->copy();
  1106. return TRUE;
  1107. }
  1108. }
  1109. /* not found.. . insert last in chain anyway .. .*/
  1110. $this->components[] = $component->copy();
  1111. return TRUE;
  1112. }
  1113. /**
  1114. * sort iCal compoments, only local date sort
  1115. *
  1116. * ascending sort on properties (if exist) x-current-dtstart, dtstart,
  1117. * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid
  1118. *
  1119. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1120. * @since 2.4.10 - 2008-09-24
  1121. * @return sort param
  1122. *
  1123. */
  1124. function sort() {
  1125. if( is_array( $this->components )) {
  1126. $this->_sortkeys = array( 'year', 'month', 'day', 'hour', 'min', 'sec' );
  1127. usort( $this->components, array( $this, '_cmpfcn' ));
  1128. }
  1129. }
  1130. function _cmpfcn( $a, $b ) {
  1131. if( empty( $a )) return -1;
  1132. if( empty( $b )) return 1;
  1133. if( 'vtimezone' == $a->objName) return -1;
  1134. if( 'vtimezone' == $b->objName) return 1;
  1135. $astart = ( isset( $a->xprop['X-CURRENT-DTSTART']['value'] )) ? $a->_date_time_string( $a->xprop['X-CURRENT-DTSTART']['value'] ) : null;
  1136. if( empty( $astart ) && isset( $a->dtstart['value'] ))
  1137. $astart = & $a->dtstart['value'];
  1138. $bstart = ( isset( $b->xprop['X-CURRENT-DTSTART']['value'] )) ? $b->_date_time_string( $b->xprop['X-CURRENT-DTSTART']['value'] ) : null;
  1139. if( empty( $bstart ) && isset( $b->dtstart['value'] ))
  1140. $bstart = & $b->dtstart['value'];
  1141. if( empty( $astart )) return -1;
  1142. elseif( empty( $bstart )) return 1;
  1143. foreach( $this->_sortkeys as $key ) {
  1144. if ( empty( $astart[$key] )) return -1;
  1145. elseif( empty( $bstart[$key] )) return 1;
  1146. if ( $astart[$key] == $bstart[$key]) continue;
  1147. if (( (int) $astart[$key] ) < ((int) $bstart[$key] ))
  1148. return -1;
  1149. elseif(( (int) $astart[$key] ) > ((int) $bstart[$key] ))
  1150. return 1;
  1151. }
  1152. $c = ( isset( $a->xprop['X-CURRENT-DTEND']['value'] )) ? $a->_date_time_string( $a->xprop['X-CURRENT-DTEND']['value'] ) : null;
  1153. if( empty( $c ) && !empty( $a->dtend['value'] ))
  1154. $c = & $a->dtend['value'];
  1155. if( empty( $c ) && isset( $a->xprop['X-CURRENT-DUE']['value'] ))
  1156. $c = $a->_date_time_string( $a->xprop['X-CURRENT-DUE']['value'] );
  1157. if( empty( $c ) && !empty( $a->due['value'] ))
  1158. $c = & $a->due['value'];
  1159. if( empty( $c ) && !empty( $a->duration['value'] ))
  1160. $c = $a->duration2date();
  1161. $d = ( isset( $b->xprop['X-CURRENT-DTEND']['value'] )) ? $b->_date_time_string( $b->xprop['X-CURRENT-DTEND']['value'] ) : null;
  1162. if( empty( $d ) && !empty( $b->dtend['value'] ))
  1163. $d = & $b->dtend['value'];
  1164. if( empty( $d ) && isset( $b->xprop['X-CURRENT-DUE']['value'] ))
  1165. $d = $b->_date_time_string( $b->xprop['X-CURRENT-DUE']['value'] );
  1166. if( empty( $d ) && !empty( $b->due['value'] ))
  1167. $d = & $b->due['value'];
  1168. if( empty( $d ) && !empty( $b->duration['value'] ))
  1169. $d = $b->duration2date();
  1170. if( empty( $c )) return -1;
  1171. elseif( empty( $d )) return 1;
  1172. foreach( $this->_sortkeys as $key ) {
  1173. if ( !isset( $c[$key] )) return -1;
  1174. elseif( !isset( $d[$key] )) return 1;
  1175. if ( $c[$key] == $d[$key] ) continue;
  1176. if (( (int) $c[$key] ) < ((int) $d[$key])) return -1;
  1177. elseif(( (int) $c[$key] ) > ((int) $d[$key])) return 1;
  1178. }
  1179. if( isset( $a->created['value'] ))
  1180. $e = & $a->created['value'];
  1181. else
  1182. $e = & $a->dtstamp['value'];
  1183. if( isset( $b->created['value'] ))
  1184. $f = & $b->created['value'];
  1185. else
  1186. $f = & $b->dtstamp['value'];
  1187. foreach( $this->_sortkeys as $key ) {
  1188. if( !isset( $e[$key] )) return -1;
  1189. elseif( !isset( $f[$key] )) return 1;
  1190. if ( $e[$key] == $f[$key] ) continue;
  1191. if (( (int) $e[$key] ) < ((int) $f[$key])) return -1;
  1192. elseif(( (int) $e[$key] ) > ((int) $f[$key])) return 1;
  1193. }
  1194. if (( $a->uid['value'] ) <
  1195. ( $b->uid['value'] )) return -1;
  1196. elseif(( $a->uid['value'] ) >
  1197. ( $b->uid['value'] )) return 1;
  1198. return 0;
  1199. }
  1200. /**
  1201. * parse iCal file into vcalendar, components, properties and parameters
  1202. *
  1203. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1204. * @since 2.4.10 - 2008-08-06
  1205. * @param string $filename optional filname (incl. opt. directory/path) or URL
  1206. * @return bool FALSE if error occurs during parsing
  1207. *
  1208. */
  1209. function parse( $filename=FALSE ) {
  1210. if( !$filename ) {
  1211. /* directory/filename previous set via setConfig directory+filename / url */
  1212. if( FALSE === ( $filename = $this->getConfig( 'url' )))
  1213. $filename = $this->getConfig( 'dirfile' );
  1214. }
  1215. elseif(( 'http://' == strtolower( substr( $filename, 0, 7 ))) ||
  1216. ( 'webcal://' == strtolower( substr( $filename, 0, 9 )))) {
  1217. /* remote file - URL */
  1218. $this->setConfig( 'URL', $filename );
  1219. if( !$filename = $this->getConfig( 'url' ))
  1220. return FALSE; /* err 2 */
  1221. }
  1222. else {
  1223. /* local directory/filename */
  1224. $parts = pathinfo( $filename );
  1225. if( !empty( $parts['dirname'] ) && ( '.' != $parts['dirname'] )) {
  1226. if( !$this->setConfig( 'directory', $parts['dirname'] ))
  1227. return FALSE; /* err 3 */
  1228. }
  1229. if( !$this->setConfig( 'filename', $parts['basename'] ))
  1230. return FALSE; /* err 4 */
  1231. }
  1232. if( 'http://' != substr( $filename, 0, 7 )) {
  1233. /* local file error tests */
  1234. if( !is_file( $filename )) /* err 5 */
  1235. return FALSE;
  1236. if( !is_readable( $filename ))
  1237. return FALSE; /* err 6 */
  1238. if( !filesize( $filename ))
  1239. return FALSE; /* err 7 */
  1240. clearstatcache();
  1241. }
  1242. /* READ FILE */
  1243. if( FALSE === ( $rows = file( $filename )))
  1244. return FALSE; /* err 1 */
  1245. /* identify BEGIN:VCALENDAR, MUST be first row */
  1246. if( 'BEGIN:VCALENDAR' != strtoupper( trim( $rows[0] )))
  1247. return FALSE; /* err 8 */
  1248. /* remove empty trailing lines */
  1249. while( '' == trim( $rows[count( $rows ) - 1] )) {
  1250. unset( $rows[count( $rows ) - 1] );
  1251. $rows = array_values( $rows );
  1252. }
  1253. /* identify ending END:VCALENDAR row */
  1254. if( 'END:VCALENDAR' != strtoupper( trim( $rows[count( $rows ) - 1] ))) {
  1255. return FALSE; /* err 9 */
  1256. }
  1257. if( 3 > count( $rows ))
  1258. return FALSE; /* err 10 */
  1259. $comp = $subcomp = null;
  1260. $actcomp = & $this;
  1261. $nl = $this->getConfig( 'nl' );
  1262. $calsync = 0;
  1263. /* identify components and update unparsed data within component */
  1264. foreach( $rows as $line ) {
  1265. if( '' == trim( $line ))
  1266. continue;
  1267. if( $nl == substr( $line, 0 - strlen( $nl )))
  1268. $line = substr( $line, 0, ( strlen( $line ) - strlen( $nl ))).'\n';
  1269. if( 'BEGIN:VCALENDAR' == strtoupper( substr( $line, 0, 15 ))) {
  1270. $calsync++;
  1271. continue;
  1272. }
  1273. elseif( 'END:VCALENDAR' == strtoupper( substr( $line, 0, 13 ))) {
  1274. $calsync--;
  1275. continue;
  1276. }
  1277. elseif( 1 != $calsync )
  1278. return FALSE; /* err 20 */
  1279. if( 'END:' == strtoupper( substr( $line, 0, 4 ))) {
  1280. if( null != $subcomp ) {
  1281. $comp->setComponent( $subcomp );
  1282. $subcomp = null;
  1283. }
  1284. else {
  1285. $this->setComponent( $comp );
  1286. $comp = null;
  1287. }
  1288. $actcomp = null;
  1289. continue;
  1290. } // end - if ( 'END:' ==.. .
  1291. elseif( 'BEGIN:' == strtoupper( substr( $line, 0, 6 ))) {
  1292. $line = str_replace( '\n', '', $line );
  1293. $compname = trim (strtoupper( substr( $line, 6 )));
  1294. if( null != $comp ) {
  1295. if( 'VALARM' == $compname )
  1296. $subcomp = new valarm();
  1297. elseif( 'STANDARD' == $compname )
  1298. $subcomp = new vtimezone( 'STANDARD' );
  1299. elseif( 'DAYLIGHT' == $compname )
  1300. $subcomp = new vtimezone( 'DAYLIGHT' );
  1301. else
  1302. return FALSE; /* err 6 */
  1303. $actcomp = & $subcomp;
  1304. }
  1305. else {
  1306. switch( $compname ) {
  1307. case 'VALARM':
  1308. $comp = new valarm();
  1309. break;
  1310. case 'VEVENT':
  1311. $comp = new vevent();
  1312. break;
  1313. case 'VFREEBUSY':
  1314. $comp = new vfreebusy();
  1315. break;
  1316. case 'VJOURNAL':
  1317. $comp = new vjournal();
  1318. break;
  1319. case 'VTODO':
  1320. $comp = new vtodo();
  1321. break;
  1322. case 'VTIMEZONE':
  1323. $comp = new vtimezone();
  1324. break;
  1325. default:
  1326. return FALSE; // err 7
  1327. break;
  1328. } // end - switch
  1329. $actcomp = & $comp;
  1330. }
  1331. continue;
  1332. } // end - elsif ( 'BEGIN:'.. .
  1333. /* update selected component with unparsed data */
  1334. $actcomp->unparsed[] = $line;
  1335. } // end - foreach( rows.. .
  1336. /* parse data for calendar (this) object */
  1337. if( is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) {
  1338. /* concatenate property values spread over several lines */
  1339. $lastix = -1;
  1340. $propnames = array( 'calscale','method','prodid','version','x-' );
  1341. $proprows = array();
  1342. foreach( $this->unparsed as $line ) {
  1343. $newProp = FALSE;
  1344. foreach ( $propnames as $propname ) {
  1345. if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
  1346. $newProp = TRUE;
  1347. break;
  1348. }
  1349. }
  1350. if( $newProp ) {
  1351. $newProp = FALSE;
  1352. $lastix++;
  1353. $proprows[$lastix] = $line;
  1354. }
  1355. else {
  1356. /* remove line breaks */
  1357. if(( '\n' == substr( $proprows[$lastix], -2 )) &&
  1358. ( ' ' == substr( $line, 0, 1 ))) {
  1359. $proprows[$lastix] = substr( $proprows[$lastix], 0, strlen( $proprows[$lastix] ) - 2 );
  1360. $line = substr( $line, 1 );
  1361. }
  1362. $proprows[$lastix] .= $line;
  1363. }
  1364. }
  1365. $toolbox = new calendarComponent();
  1366. foreach( $proprows as $line ) {
  1367. if( '\n' == substr( $line, -2 ))
  1368. $line = substr( $line, 0, strlen( $line ) - 2 );
  1369. /* get propname */
  1370. $cix = $propname = null;
  1371. for( $cix=0; $cix < strlen( $line ); $cix++ ) {
  1372. if( in_array( $line{$cix}, array( ':', ';' )))
  1373. break;
  1374. else
  1375. $propname .= $line{$cix};
  1376. }
  1377. /* ignore version/prodid properties */
  1378. if( in_array( strtoupper( $propname ), array( 'VERSION', 'PRODID' )))
  1379. continue;
  1380. $line = substr( $line, $cix);
  1381. /* separate attributes from value */
  1382. $attr = array();
  1383. $attrix = -1;
  1384. $strlen = strlen( $line );
  1385. for( $cix=0; $cix < $strlen; $cix++ ) {
  1386. if(( ':' == $line{$cix} ) &&
  1387. ( '://' != substr( $line, $cix, 3 )) &&
  1388. ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
  1389. $attrEnd = TRUE;
  1390. if(( $cix < ( $strlen - 4 )) &&
  1391. ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
  1392. for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
  1393. if( '://' == substr( $line, $c2ix - 2, 3 )) {
  1394. $attrEnd = FALSE;
  1395. break; // an URI with a portnr!!
  1396. }
  1397. }
  1398. }
  1399. if( $attrEnd) {
  1400. $line = substr( $line, $cix + 1 );
  1401. break;
  1402. }
  1403. }
  1404. if( ';' == $line{$cix} )
  1405. $attr[++$attrix] = null;
  1406. else
  1407. $attr[$attrix] .= $line{$cix};
  1408. }
  1409. /* make attributes in array format */
  1410. $propattr = array();
  1411. foreach( $attr as $attribute ) {
  1412. $attrsplit = explode( '=', $attribute, 2 );
  1413. if( 1 < count( $attrsplit ))
  1414. $propattr[$attrsplit[0]] = $attrsplit[1];
  1415. else
  1416. $propattr[] = $attribute;
  1417. }
  1418. /* update Property */
  1419. if( FALSE !== strpos( $line, ',' )) {
  1420. $content = explode( ',', $line );
  1421. $clen = count( $content );
  1422. for( $cix = 0; $cix < $clen; $cix++ ) {
  1423. if( "\\" == substr( $content[$cix], -1 )) {
  1424. $content[$cix] .= ','.$content[$cix + 1];
  1425. unset( $content[$cix + 1] );
  1426. $cix++;
  1427. }
  1428. }
  1429. if( 1 < count( $content )) {
  1430. foreach( $content as $cix => $contentPart )
  1431. $content[$cix] = $toolbox->_strunrep( $contentPart );
  1432. $this->setProperty( $propname, $content, $propattr );
  1433. continue;
  1434. }
  1435. else
  1436. $line = reset( $content );
  1437. $line = $toolbox->_strunrep( $line );
  1438. }
  1439. $this->setProperty( $propname, trim( $line ), $propattr );
  1440. } // end - foreach( $this->unparsed.. .
  1441. } // end - if( is_array( $this->unparsed.. .
  1442. /* parse Components */
  1443. if( is_array( $this->components ) && ( 0 < count( $this->components ))) {
  1444. for( $six = 0; $six < count( $this->components ); $six++ ) {
  1445. if( !empty( $this->components[$six] ))
  1446. $this->components[$six]->parse();
  1447. }
  1448. }
  1449. else
  1450. return FALSE; /* err 91 or something.. . */
  1451. return TRUE;
  1452. }
  1453. /*********************************************************************************/
  1454. /**
  1455. * creates formatted output for calendar object instance
  1456. *
  1457. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1458. * @since 2.4.10 - 2008-08-06
  1459. * @return string
  1460. */
  1461. function createCalendar() {
  1462. $calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null;
  1463. switch( $this->format ) {
  1464. case 'xcal':
  1465. $calendarInit1 = '<?xml version="1.0" encoding="UTF-8"?>'.$this->nl.
  1466. '<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"'.$this->nl.
  1467. '"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"';
  1468. $calendarInit2 = '>'.$this->nl;
  1469. $calendarStart = '<vcalendar';
  1470. break;
  1471. default:
  1472. $calendarStart = 'BEGIN:VCALENDAR'.$this->nl;
  1473. break;
  1474. }
  1475. $calendarStart .= $this->createCalscale();
  1476. $calendarStart .= $this->createMethod();
  1477. $calendarStart .= $this->createProdid();
  1478. $calendarStart .= $this->createVersion();
  1479. switch( $this->format ) {
  1480. case 'xcal':
  1481. $nlstrlen = strlen( $this->nl );
  1482. if( $this->nl == substr( $calendarStart, ( 0 - $nlstrlen )))
  1483. $calendarStart = substr( $calendarStart, 0, ( strlen( $calendarStart ) - $nlstrlen ));
  1484. $calendarStart .= '>'.$this->nl;
  1485. break;
  1486. default:
  1487. break;
  1488. }
  1489. $calendar .= $this->createXprop();
  1490. foreach( $this->components as $component ) {
  1491. if( empty( $component )) continue;
  1492. if( '' >= $component->getConfig( 'language'))
  1493. $component->setConfig( 'language', $this->getConfig( 'language' ));
  1494. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  1495. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  1496. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  1497. $component->setConfig( 'format', $this->getConfig( 'format' ));
  1498. $calendar .= $component->createComponent( $this->xcaldecl );
  1499. }
  1500. if(( 0 < count( $this->xcaldecl )) && ( 'xcal' == $this->format )) { // xCal only
  1501. $calendarInit1 .= $this->nl.'['.$this->nl;
  1502. $old_xcaldecl = array();
  1503. foreach( $this->xcaldecl as $declix => $declPart ) {
  1504. if(( 0 < count( $old_xcaldecl)) &&
  1505. ( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) &&
  1506. ( in_array( $declPart['external'], $old_xcaldecl['external'] )))
  1507. continue; // no duplicate uri and ext. references
  1508. $calendarxCaldecl .= '<!';
  1509. foreach( $declPart as $declKey => $declValue ) {
  1510. switch( $declKey ) { // index
  1511. case 'xmldecl': // no 1
  1512. $calendarxCaldecl .= $declValue.' ';
  1513. break;
  1514. case 'uri': // no 2
  1515. $calendarxCaldecl .= $declValue.' ';
  1516. $old_xcaldecl['uri'][] = $declValue;
  1517. break;
  1518. case 'ref': // no 3
  1519. $calendarxCaldecl .= $declValue.' ';
  1520. break;
  1521. case 'external': // no 4
  1522. $calendarxCaldecl .= '"'.$declValue.'" ';
  1523. $old_xcaldecl['external'][] = $declValue;
  1524. break;
  1525. case 'type': // no 5
  1526. $calendarxCaldecl .= $declValue.' ';
  1527. break;
  1528. case 'type2': // no 6
  1529. $calendarxCaldecl .= $declValue;
  1530. break;
  1531. }
  1532. }
  1533. $calendarxCaldecl .= '>'.$this->nl;
  1534. }
  1535. $calendarInit2 = ']'.$calendarInit2;
  1536. }
  1537. switch( $this->format ) {
  1538. case 'xcal':
  1539. $calendar .= '</vcalendar>'.$this->nl;
  1540. break;
  1541. default:
  1542. $calendar .= 'END:VCALENDAR'.$this->nl;
  1543. break;
  1544. }
  1545. return $calendarInit1.$calendarxCaldecl.$calendarInit2.$calendarStart.$calendar;
  1546. }
  1547. /**
  1548. * a HTTP redirect header is sent with created, updated and/or parsed calendar
  1549. *
  1550. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1551. * @since 2.2.12 - 2007-10-23
  1552. * @return redirect
  1553. */
  1554. function returnCalendar() {
  1555. $filename = $this->getConfig( 'filename' );
  1556. $output = $this->createCalendar();
  1557. $filesize = strlen( $output );
  1558. // if( headers_sent( $filename, $linenum ))
  1559. // die( "Headers already sent in $filename on line $linenum\n" );
  1560. if( 'xcal' == $this->format )
  1561. header( 'Content-Type: application/calendar+xml; charset=utf-8' );
  1562. else
  1563. header( 'Content-Type: text/calendar; charset=utf-8' );
  1564. header( 'Content-Length: '.$filesize );
  1565. header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
  1566. header( 'Cache-Control: max-age=10' );
  1567. echo $output;
  1568. die();
  1569. }
  1570. /**
  1571. * save content in a file
  1572. *
  1573. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1574. * @since 2.2.12 - 2007-12-30
  1575. * @param string $directory optional
  1576. * @param string $filename optional
  1577. * @param string $delimiter optional
  1578. * @return bool
  1579. */
  1580. function saveCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE ) {
  1581. if( $directory )
  1582. $this->setConfig( 'directory', $directory );
  1583. if( $filename )
  1584. $this->setConfig( 'filename', $filename );
  1585. if( $delimiter && ($delimiter != DIRECTORY_SEPARATOR ))
  1586. $this->setConfig( 'delimiter', $delimiter );
  1587. if( FALSE === ( $dirfile = $this->getConfig( 'url' )))
  1588. $dirfile = $this->getConfig( 'dirfile' );
  1589. $iCalFile = @fopen( $dirfile, 'w' );
  1590. if( $iCalFile ) {
  1591. if( FALSE === fwrite( $iCalFile, $this->createCalendar() ))
  1592. return FALSE;
  1593. fclose( $iCalFile );
  1594. return TRUE;
  1595. }
  1596. else
  1597. return FALSE;
  1598. }
  1599. /**
  1600. * if recent version of calendar file exists (default one hour), an HTTP redirect header is sent
  1601. * else FALSE is returned
  1602. *
  1603. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1604. * @since 2.2.12 - 2007-10-28
  1605. * @param string $directory optional alt. int timeout
  1606. * @param string $filename optional
  1607. * @param string $delimiter optional
  1608. * @param int timeout optional, default 3600 sec
  1609. * @return redirect/FALSE
  1610. */
  1611. function useCachedCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE, $timeout=3600) {
  1612. if ( $directory && ctype_digit( (string) $directory ) && !$filename ) {
  1613. $timeout = (int) $directory;
  1614. $directory = FALSE;
  1615. }
  1616. if( $directory )
  1617. $this->setConfig( 'directory', $directory );
  1618. if( $filename )
  1619. $this->setConfig( 'filename', $filename );
  1620. if( $delimiter && ( $delimiter != DIRECTORY_SEPARATOR ))
  1621. $this->setConfig( 'delimiter', $delimiter );
  1622. $filesize = $this->getConfig( 'filesize' );
  1623. if( 0 >= $filesize )
  1624. return FALSE;
  1625. $dirfile = $this->getConfig( 'dirfile' );
  1626. if( time() - filemtime( $dirfile ) < $timeout) {
  1627. clearstatcache();
  1628. $dirfile = $this->getConfig( 'dirfile' );
  1629. $filename = $this->getConfig( 'filename' );
  1630. // if( headers_sent( $filename, $linenum ))
  1631. // die( "Headers already sent in $filename on line $linenum\n" );
  1632. if( 'xcal' == $this->format )
  1633. header( 'Content-Type: application/calendar+xml; charset=utf-8' );
  1634. else
  1635. header( 'Content-Type: text/calendar; charset=utf-8' );
  1636. header( 'Content-Length: '.$filesize );
  1637. header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
  1638. header( 'Cache-Control: max-age=10' );
  1639. $fp = @$fopen( $dirfile, 'r' );
  1640. if( $fp ) {
  1641. fpassthru( $fp );
  1642. fclose( $fp );
  1643. }
  1644. die();
  1645. }
  1646. else
  1647. return FALSE;
  1648. }
  1649. }
  1650. /*********************************************************************************/
  1651. /*********************************************************************************/
  1652. /**
  1653. * abstract class for calendar components
  1654. *
  1655. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1656. * @since 2.4.19 - 2008-10-12
  1657. */
  1658. class calendarComponent {
  1659. // component property variables
  1660. var $uid;
  1661. var $dtstamp;
  1662. // component config variables
  1663. var $allowEmpty;
  1664. var $language;
  1665. var $nl;
  1666. var $unique_id;
  1667. var $format;
  1668. var $objName; // created automatically at instance creation
  1669. // component internal variables
  1670. var $componentStart1;
  1671. var $componentStart2;
  1672. var $componentEnd1;
  1673. var $componentEnd2;
  1674. var $elementStart1;
  1675. var $elementStart2;
  1676. var $elementEnd1;
  1677. var $elementEnd2;
  1678. var $intAttrDelimiter;
  1679. var $attributeDelimiter;
  1680. var $valueInit;
  1681. // component xCal declaration container
  1682. var $xcaldecl;
  1683. /**
  1684. * constructor for calendar component object
  1685. *
  1686. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1687. * @since 2.4.19 - 2008-10-23
  1688. */
  1689. function __construct() {
  1690. $this->objName = ( isset( $this->timezonetype )) ?
  1691. strtolower( $this->timezonetype ) : get_class ( $this );
  1692. $this->uid = array();
  1693. $this->dtstamp = array();
  1694. $this->language = null;
  1695. $this->nl = null;
  1696. $this->unique_id = null;
  1697. $this->format = null;
  1698. $this->allowEmpty = TRUE;
  1699. $this->xcaldecl = array();
  1700. $this->_createFormat();
  1701. $this->_makeDtstamp();
  1702. }
  1703. /*********************************************************************************/
  1704. /**
  1705. * Property Name: ACTION
  1706. */
  1707. /**
  1708. * creates formatted output for calendar component property action
  1709. *
  1710. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1711. * @since 2.4.8 - 2008-10-22
  1712. * @return string
  1713. */
  1714. function createAction() {
  1715. if( empty( $this->action )) return FALSE;
  1716. if( empty( $this->action['value'] ))
  1717. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE;
  1718. $attributes = $this->_createParams( $this->action['params'] );
  1719. return $this->_createElement( 'ACTION', $attributes, $this->action['value'] );
  1720. }
  1721. /**
  1722. * set calendar component property action
  1723. *
  1724. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1725. * @since 2.4.8 - 2008-11-04
  1726. * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
  1727. * @param mixed $params
  1728. * @return bool
  1729. */
  1730. function setAction( $value, $params=FALSE ) {
  1731. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1732. $this->action = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  1733. return TRUE;
  1734. }
  1735. /*********************************************************************************/
  1736. /**
  1737. * Property Name: ATTACH
  1738. */
  1739. /**
  1740. * creates formatted output for calendar component property attach
  1741. *
  1742. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1743. * @since 0.9.7 - 2006-11-23
  1744. * @return string
  1745. */
  1746. function createAttach() {
  1747. if( empty( $this->attach )) return FALSE;
  1748. $output = null;
  1749. foreach( $this->attach as $attachPart ) {
  1750. if(! empty( $attachPart['value'] )) {
  1751. $attributes = $this->_createParams( $attachPart['params'] );
  1752. $output .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] );
  1753. }
  1754. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' );
  1755. }
  1756. return $output;
  1757. }
  1758. /**
  1759. * set calendar component property attach
  1760. *
  1761. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1762. * @since 2.5.1 - 2008-11-06
  1763. * @param string $value
  1764. * @param array $params, optional
  1765. * @param integer $index, optional
  1766. * @return bool
  1767. */
  1768. function setAttach( $value, $params=FALSE, $index=FALSE ) {
  1769. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1770. $this->_setMval( $this->attach, $value, $params, FALSE, $index );
  1771. return TRUE;
  1772. }
  1773. /*********************************************************************************/
  1774. /**
  1775. * Property Name: ATTENDEE
  1776. */
  1777. /**
  1778. * creates formatted output for calendar component property attendee
  1779. *
  1780. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1781. * @since 2.4.8 - 2008-09-23
  1782. * @return string
  1783. */
  1784. function createAttendee() {
  1785. if( empty( $this->attendee )) return FALSE;
  1786. $output = null;
  1787. foreach( $this->attendee as $attendeePart ) { // start foreach 1
  1788. if( empty( $attendeePart['value'] )) {
  1789. if( $this->getConfig( 'allowEmpty' ))
  1790. $output .= $this->_createElement( 'ATTENDEE' );
  1791. continue;
  1792. }
  1793. $attendee1 = $attendee2 = $attendeeLANG = $attendeeCN = null;
  1794. foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2
  1795. if( 'value' == $paramlabel )
  1796. $attendee2 .= 'MAILTO:'.$paramvalue;
  1797. elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
  1798. foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
  1799. $attendee11 = $attendee12 = null;
  1800. if( is_int( $optparamlabel )) {
  1801. $attendee1 .= $this->intAttrDelimiter.$optparamvalue;
  1802. continue;
  1803. }
  1804. switch( $optparamlabel ) { // start switch
  1805. case 'CUTYPE':
  1806. case 'PARTSTAT':
  1807. case 'ROLE':
  1808. case 'RSVP':
  1809. $attendee1 .= $this->intAttrDelimiter.$optparamlabel.'="'.$optparamvalue.'"';
  1810. break;
  1811. case 'SENT-BY':
  1812. $attendee1 .= $this->intAttrDelimiter.'SENT-BY="MAILTO:'.$optparamvalue.'"';
  1813. break;
  1814. case 'MEMBER':
  1815. $attendee11 = $this->intAttrDelimiter.'MEMBER=';
  1816. //no break
  1817. case 'DELEGATED-TO':
  1818. $attendee11 = ( !$attendee11 ) ? $this->intAttrDelimiter.'DELEGATED-TO=' : $attendee11;
  1819. //no break
  1820. case 'DELEGATED-FROM':
  1821. $attendee11 = ( !$attendee11 ) ? $this->intAttrDelimiter.'DELEGATED-FROM=' : $attendee11;
  1822. foreach( $optparamvalue as $cix => $calUserAddress ) {
  1823. $attendee12 .= ( $cix ) ? ',' : null;
  1824. $attendee12 .= '"MAILTO:'.$calUserAddress.'"';
  1825. }
  1826. $attendee1 .= $attendee11.$attendee12;
  1827. break;
  1828. case 'CN':
  1829. $attendeeCN .= $this->intAttrDelimiter.'CN="'.$optparamvalue.'"';
  1830. break;
  1831. case 'DIR':
  1832. $attendee1 .= $this->intAttrDelimiter.'DIR="'.$optparamvalue.'"';
  1833. break;
  1834. case 'LANGUAGE':
  1835. $attendeeLANG .= $this->intAttrDelimiter.'LANGUAGE='.$optparamvalue;
  1836. break;
  1837. default:
  1838. $attendee1 .= $this->intAttrDelimiter."$optparamlabel=$optparamvalue";
  1839. break;
  1840. } // end switch
  1841. } // end foreach 3
  1842. } // end elseif
  1843. } // end foreach 2
  1844. $output .= $this->_createElement( 'ATTENDEE', $attendee1.$attendeeLANG.$attendeeCN, $attendee2 );
  1845. } // end foreach 1
  1846. return $output;
  1847. }
  1848. /**
  1849. * set calendar component property attach
  1850. *
  1851. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1852. * @since 2.5.1 - 2008-11-05
  1853. * @param string $value
  1854. * @param array $params, optional
  1855. * @param integer $index, optional
  1856. * @return bool
  1857. */
  1858. function setAttendee( $value, $params=FALSE, $index=FALSE ) {
  1859. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1860. $value = str_replace ( 'MAILTO:', '', $value );
  1861. $value = str_replace ( 'mailto:', '', $value );
  1862. $params2 = array();
  1863. if( is_array($params )) {
  1864. $optarrays = array();
  1865. foreach( $params as $optparamlabel => $optparamvalue ) {
  1866. $optparamlabel = strtoupper( $optparamlabel );
  1867. switch( $optparamlabel ) {
  1868. case 'MEMBER':
  1869. case 'DELEGATED-TO':
  1870. case 'DELEGATED-FROM':
  1871. if( is_array( $optparamvalue )) {
  1872. foreach( $optparamvalue as $part ) {
  1873. $part = str_replace( 'MAILTO:', '', $part );
  1874. $part = str_replace( 'mailto:', '', $part );
  1875. if(( '"' == $part{0} ) && ( '"' == $part{strlen($part)-1} ))
  1876. $part = substr( $part, 1, ( strlen($part)-2 ));
  1877. $optarrays[$optparamlabel][] = $part;
  1878. }
  1879. }
  1880. else {
  1881. $part = str_replace( 'MAILTO:', '', $optparamvalue );
  1882. $part = str_replace( 'mailto:', '', $part );
  1883. if(( '"' == $part{0} ) && ( '"' == $part{strlen($part)-1} ))
  1884. $part = substr( $part, 1, ( strlen($part)-2 ));
  1885. $optarrays[$optparamlabel][] = $part;
  1886. }
  1887. break;
  1888. default:
  1889. if( 'SENT-BY' == $optparamlabel ) {
  1890. $optparamvalue = str_replace( 'MAILTO:', '', $optparamvalue );
  1891. $optparamvalue = str_replace( 'mailto:', '', $optparamvalue );
  1892. }
  1893. if(( '"' == substr( $optparamvalue, 0, 1 )) &&
  1894. ( '"' == substr( $optparamvalue, -1 )))
  1895. $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
  1896. $params2[$optparamlabel] = $optparamvalue;
  1897. break;
  1898. } // end switch( $optparamlabel.. .
  1899. } // end foreach( $optparam.. .
  1900. foreach( $optarrays as $optparamlabel => $optparams )
  1901. $params2[$optparamlabel] = $optparams;
  1902. }
  1903. // remove defaults
  1904. $this->_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' );
  1905. $this->_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
  1906. $this->_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' );
  1907. $this->_existRem( $params2, 'RSVP', 'FALSE' );
  1908. // check language setting
  1909. if( isset( $params2['CN' ] )) {
  1910. $lang = $this->getConfig( 'language' );
  1911. if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
  1912. $params2['LANGUAGE' ] = $lang;
  1913. }
  1914. $this->_setMval( $this->attendee, $value, $params2, FALSE, $index );
  1915. return TRUE;
  1916. }
  1917. /*********************************************************************************/
  1918. /**
  1919. * Property Name: CATEGORIES
  1920. */
  1921. /**
  1922. * creates formatted output for calendar component property categories
  1923. *
  1924. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1925. * @since 2.4.8 - 2008-10-22
  1926. * @return string
  1927. */
  1928. function createCategories() {
  1929. if( empty( $this->categories )) return FALSE;
  1930. $output = null;
  1931. foreach( $this->categories as $category ) {
  1932. if( empty( $category['value'] )) {
  1933. if ( $this->getConfig( 'allowEmpty' ))
  1934. $output .= $this->_createElement( 'CATEGORIES' );
  1935. continue;
  1936. }
  1937. $attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' ));
  1938. if( is_array( $category['value'] )) {
  1939. foreach( $category['value'] as $cix => $categoryPart )
  1940. $category['value'][$cix] = $this->_strrep( $categoryPart );
  1941. $content = implode( ',', $category['value'] );
  1942. }
  1943. else
  1944. $content = $this->_strrep( $category['value'] );
  1945. $output .= $this->_createElement( 'CATEGORIES', $attributes, $content );
  1946. }
  1947. return $output;
  1948. }
  1949. /**
  1950. * set calendar component property categories
  1951. *
  1952. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1953. * @since 2.5.1 - 2008-11-06
  1954. * @param mixed $value
  1955. * @param array $params, optional
  1956. * @param integer $index, optional
  1957. * @return bool
  1958. */
  1959. function setCategories( $value, $params=FALSE, $index=FALSE ) {
  1960. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1961. $this->_setMval( $this->categories, $value, $params, FALSE, $index );
  1962. return TRUE;
  1963. }
  1964. /*********************************************************************************/
  1965. /**
  1966. * Property Name: CLASS
  1967. */
  1968. /**
  1969. * creates formatted output for calendar component property class
  1970. *
  1971. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1972. * @since 0.9.7 - 2006-11-20
  1973. * @return string
  1974. */
  1975. function createClass() {
  1976. if( empty( $this->class )) return FALSE;
  1977. if( empty( $this->class['value'] ))
  1978. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE;
  1979. $attributes = $this->_createParams( $this->class['params'] );
  1980. return $this->_createElement( 'CLASS', $attributes, $this->class['value'] );
  1981. }
  1982. /**
  1983. * set calendar component property class
  1984. *
  1985. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  1986. * @since 2.4.8 - 2008-11-04
  1987. * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
  1988. * @param array $params optional
  1989. * @return bool
  1990. */
  1991. function setClass( $value, $params=FALSE ) {
  1992. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  1993. $this->class = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  1994. return TRUE;
  1995. }
  1996. /*********************************************************************************/
  1997. /**
  1998. * Property Name: COMMENT
  1999. */
  2000. /**
  2001. * creates formatted output for calendar component property comment
  2002. *
  2003. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2004. * @since 2.4.8 - 2008-10-22
  2005. * @return string
  2006. */
  2007. function createComment() {
  2008. if( empty( $this->comment )) return FALSE;
  2009. $output = null;
  2010. foreach( $this->comment as $commentPart ) {
  2011. if( empty( $commentPart['value'] )) {
  2012. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
  2013. continue;
  2014. }
  2015. $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
  2016. $content = $this->_strrep( $commentPart['value'] );
  2017. $output .= $this->_createElement( 'COMMENT', $attributes, $content );
  2018. }
  2019. return $output;
  2020. }
  2021. /**
  2022. * set calendar component property comment
  2023. *
  2024. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2025. * @since 2.5.1 - 2008-11-06
  2026. * @param string $value
  2027. * @param array $params, optional
  2028. * @param integer $index, optional
  2029. * @return bool
  2030. */
  2031. function setComment( $value, $params=FALSE, $index=FALSE ) {
  2032. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2033. $this->_setMval( $this->comment, $value, $params, FALSE, $index );
  2034. return TRUE;
  2035. }
  2036. /*********************************************************************************/
  2037. /**
  2038. * Property Name: COMPLETED
  2039. */
  2040. /**
  2041. * creates formatted output for calendar component property completed
  2042. *
  2043. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2044. * @since 2.4.8 - 2008-10-22
  2045. * @return string
  2046. */
  2047. function createCompleted( ) {
  2048. if( empty( $this->completed )) return FALSE;
  2049. if( !isset( $this->completed['value']['year'] ) &&
  2050. !isset( $this->completed['value']['month'] ) &&
  2051. !isset( $this->completed['value']['day'] ) &&
  2052. !isset( $this->completed['value']['hour'] ) &&
  2053. !isset( $this->completed['value']['min'] ) &&
  2054. !isset( $this->completed['value']['sec'] ))
  2055. if( $this->getConfig( 'allowEmpty' ))
  2056. return $this->_createElement( 'COMPLETED' );
  2057. else return FALSE;
  2058. $formatted = $this->_format_date_time( $this->completed['value'], 7 );
  2059. $attributes = $this->_createParams( $this->completed['params'] );
  2060. return $this->_createElement( 'COMPLETED', $attributes, $formatted );
  2061. }
  2062. /**
  2063. * set calendar component property completed
  2064. *
  2065. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2066. * @since 2.4.8 - 2008-10-23
  2067. * @param mixed $year
  2068. * @param mixed $month optional
  2069. * @param int $day optional
  2070. * @param int $hour optional
  2071. * @param int $min optional
  2072. * @param int $sec optional
  2073. * @param array $params optional
  2074. * @return bool
  2075. */
  2076. function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2077. if( empty( $year )) {
  2078. if( $this->getConfig( 'allowEmpty' )) {
  2079. $this->completed = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2080. return TRUE;
  2081. }
  2082. else
  2083. return FALSE;
  2084. }
  2085. $this->completed = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2086. return TRUE;
  2087. }
  2088. /*********************************************************************************/
  2089. /**
  2090. * Property Name: CONTACT
  2091. */
  2092. /**
  2093. * creates formatted output for calendar component property contact
  2094. *
  2095. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2096. * @since 2.4.8 - 2008-10-23
  2097. * @return string
  2098. */
  2099. function createContact() {
  2100. if( empty( $this->contact )) return FALSE;
  2101. $output = null;
  2102. foreach( $this->contact as $contact ) {
  2103. if( !empty( $contact['value'] )) {
  2104. $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
  2105. $content = $this->_strrep( $contact['value'] );
  2106. $output .= $this->_createElement( 'CONTACT', $attributes, $content );
  2107. }
  2108. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
  2109. }
  2110. return $output;
  2111. }
  2112. /**
  2113. * set calendar component property contact
  2114. *
  2115. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2116. * @since 2.5.1 - 2008-11-05
  2117. * @param string $value
  2118. * @param array $params, optional
  2119. * @param integer $index, optional
  2120. * @return bool
  2121. */
  2122. function setContact( $value, $params=FALSE, $index=FALSE ) {
  2123. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2124. $this->_setMval( $this->contact, $value, $params, FALSE, $index );
  2125. return TRUE;
  2126. }
  2127. /*********************************************************************************/
  2128. /**
  2129. * Property Name: CREATED
  2130. */
  2131. /**
  2132. * creates formatted output for calendar component property created
  2133. *
  2134. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2135. * @since 2.4.8 - 2008-10-21
  2136. * @return string
  2137. */
  2138. function createCreated() {
  2139. if( empty( $this->created )) return FALSE;
  2140. $formatted = $this->_format_date_time( $this->created['value'], 7 );
  2141. $attributes = $this->_createParams( $this->created['params'] );
  2142. return $this->_createElement( 'CREATED', $attributes, $formatted );
  2143. }
  2144. /**
  2145. * set calendar component property created
  2146. *
  2147. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2148. * @since 2.4.8 - 2008-10-23
  2149. * @param mixed $year optional
  2150. * @param mixed $month optional
  2151. * @param int $day optional
  2152. * @param int $hour optional
  2153. * @param int $min optional
  2154. * @param int $sec optional
  2155. * @param mixed $params optional
  2156. * @return bool
  2157. */
  2158. function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2159. if( !isset( $year )) {
  2160. $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
  2161. }
  2162. $this->created = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2163. return TRUE;
  2164. }
  2165. /*********************************************************************************/
  2166. /**
  2167. * Property Name: DESCRIPTION
  2168. */
  2169. /**
  2170. * creates formatted output for calendar component property description
  2171. *
  2172. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2173. * @since 2.4.8 - 2008-10-22
  2174. * @return string
  2175. */
  2176. function createDescription() {
  2177. if( empty( $this->description )) return FALSE;
  2178. $output = null;
  2179. foreach( $this->description as $description ) {
  2180. if( !empty( $description['value'] )) {
  2181. $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
  2182. $content = $this->_strrep( $description['value'] );
  2183. $output .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
  2184. }
  2185. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
  2186. }
  2187. return $output;
  2188. }
  2189. /**
  2190. * set calendar component property description
  2191. *
  2192. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2193. * @since 2.5.1 - 2008-11-05
  2194. * @param string $value
  2195. * @param array $params, optional
  2196. * @param integer $index, optional
  2197. * @return bool
  2198. */
  2199. function setDescription( $value, $params=FALSE, $index=FALSE ) {
  2200. if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; }
  2201. $this->_setMval( $this->description, $value, $params, FALSE, $index );
  2202. return TRUE;
  2203. }
  2204. /*********************************************************************************/
  2205. /**
  2206. * Property Name: DTEND
  2207. */
  2208. /**
  2209. * creates formatted output for calendar component property dtend
  2210. *
  2211. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2212. * @since 2.4.8 - 2008-10-21
  2213. * @return string
  2214. */
  2215. function createDtend() {
  2216. if( empty( $this->dtend )) return FALSE;
  2217. if( !isset( $this->dtend['value']['year'] ) &&
  2218. !isset( $this->dtend['value']['month'] ) &&
  2219. !isset( $this->dtend['value']['day'] ) &&
  2220. !isset( $this->dtend['value']['hour'] ) &&
  2221. !isset( $this->dtend['value']['min'] ) &&
  2222. !isset( $this->dtend['value']['sec'] ))
  2223. if( $this->getConfig( 'allowEmpty' ))
  2224. return $this->_createElement( 'DTEND' );
  2225. else return FALSE;
  2226. $formatted = $this->_format_date_time( $this->dtend['value'] );
  2227. $attributes = $this->_createParams( $this->dtend['params'] );
  2228. return $this->_createElement( 'DTEND', $attributes, $formatted );
  2229. }
  2230. /**
  2231. * set calendar component property dtend
  2232. *
  2233. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2234. * @since 2.4.8 - 2008-10-23
  2235. * @param mixed $year
  2236. * @param mixed $month optional
  2237. * @param int $day optional
  2238. * @param int $hour optional
  2239. * @param int $min optional
  2240. * @param int $sec optional
  2241. * @param string $tz optional
  2242. * @param array params optional
  2243. * @return bool
  2244. */
  2245. function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  2246. if( empty( $year )) {
  2247. if( $this->getConfig( 'allowEmpty' )) {
  2248. $this->dtend = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2249. return TRUE;
  2250. }
  2251. else
  2252. return FALSE;
  2253. }
  2254. $this->dtend = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
  2255. return TRUE;
  2256. }
  2257. /*********************************************************************************/
  2258. /**
  2259. * Property Name: DTSTAMP
  2260. */
  2261. /**
  2262. * creates formatted output for calendar component property dtstamp
  2263. *
  2264. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2265. * @since 2.4.4 - 2008-03-07
  2266. * @return string
  2267. */
  2268. function createDtstamp() {
  2269. if( !isset( $this->dtstamp['value']['year'] ) &&
  2270. !isset( $this->dtstamp['value']['month'] ) &&
  2271. !isset( $this->dtstamp['value']['day'] ) &&
  2272. !isset( $this->dtstamp['value']['hour'] ) &&
  2273. !isset( $this->dtstamp['value']['min'] ) &&
  2274. !isset( $this->dtstamp['value']['sec'] ))
  2275. $this->_makeDtstamp();
  2276. $formatted = $this->_format_date_time( $this->dtstamp['value'], 7 );
  2277. $attributes = $this->_createParams( $this->dtstamp['params'] );
  2278. return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
  2279. }
  2280. /**
  2281. * computes datestamp for calendar component object instance dtstamp
  2282. *
  2283. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2284. * @since 1.x.x - 2007-05-13
  2285. * @return void
  2286. */
  2287. function _makeDtstamp() {
  2288. $this->dtstamp['value'] = array( 'year' => date( 'Y' )
  2289. , 'month' => date( 'm' )
  2290. , 'day' => date( 'd' )
  2291. , 'hour' => date( 'H' )
  2292. , 'min' => date( 'i' )
  2293. , 'sec' => date( 's' ) - date( 'Z' ));
  2294. $this->dtstamp['params'] = null;
  2295. }
  2296. /**
  2297. * set calendar component property dtstamp
  2298. *
  2299. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2300. * @since 2.4.8 - 2008-10-23
  2301. * @param mixed $year
  2302. * @param mixed $month optional
  2303. * @param int $day optional
  2304. * @param int $hour optional
  2305. * @param int $min optional
  2306. * @param int $sec optional
  2307. * @param array $params optional
  2308. * @return TRUE
  2309. */
  2310. function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2311. if( empty( $year ))
  2312. $this->_makeDtstamp();
  2313. else
  2314. $this->dtstamp = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2315. return TRUE;
  2316. }
  2317. /*********************************************************************************/
  2318. /**
  2319. * Property Name: DTSTART
  2320. */
  2321. /**
  2322. * creates formatted output for calendar component property dtstart
  2323. *
  2324. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2325. * @since 2.4.16 - 2008-10-26
  2326. * @return string
  2327. */
  2328. function createDtstart() {
  2329. if( empty( $this->dtstart )) return FALSE;
  2330. if( !isset( $this->dtstart['value']['year'] ) &&
  2331. !isset( $this->dtstart['value']['month'] ) &&
  2332. !isset( $this->dtstart['value']['day'] ) &&
  2333. !isset( $this->dtstart['value']['hour'] ) &&
  2334. !isset( $this->dtstart['value']['min'] ) &&
  2335. !isset( $this->dtstart['value']['sec'] ))
  2336. if( $this->getConfig( 'allowEmpty' ))
  2337. return $this->_createElement( 'DTSTART' );
  2338. else return FALSE;
  2339. if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
  2340. unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
  2341. $formatted = $this->_format_date_time( $this->dtstart['value'] );
  2342. $attributes = $this->_createParams( $this->dtstart['params'] );
  2343. return $this->_createElement( 'DTSTART', $attributes, $formatted );
  2344. }
  2345. /**
  2346. * set calendar component property dtstart
  2347. *
  2348. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2349. * @since 2.4.16 - 2008-11-04
  2350. * @param mixed $year
  2351. * @param mixed $month optional
  2352. * @param int $day optional
  2353. * @param int $hour optional
  2354. * @param int $min optional
  2355. * @param int $sec optional
  2356. * @param string $tz optional
  2357. * @param array $params optional
  2358. * @return bool
  2359. */
  2360. function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  2361. if( empty( $year )) {
  2362. if( $this->getConfig( 'allowEmpty' )) {
  2363. $this->dtstart = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2364. return TRUE;
  2365. }
  2366. else
  2367. return FALSE;
  2368. }
  2369. $this->dtstart = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart' );
  2370. return TRUE;
  2371. }
  2372. /*********************************************************************************/
  2373. /**
  2374. * Property Name: DUE
  2375. */
  2376. /**
  2377. * creates formatted output for calendar component property due
  2378. *
  2379. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2380. * @since 2.4.8 - 2008-10-22
  2381. * @return string
  2382. */
  2383. function createDue() {
  2384. if( empty( $this->due )) return FALSE;
  2385. if( !isset( $this->due['value']['year'] ) &&
  2386. !isset( $this->due['value']['month'] ) &&
  2387. !isset( $this->due['value']['day'] ) &&
  2388. !isset( $this->due['value']['hour'] ) &&
  2389. !isset( $this->due['value']['min'] ) &&
  2390. !isset( $this->due['value']['sec'] ))
  2391. if( $this->getConfig( 'allowEmpty' ))
  2392. return $this->_createElement( 'DUE' );
  2393. else return FALSE;
  2394. $formatted = $this->_format_date_time( $this->due['value'] );
  2395. $attributes = $this->_createParams( $this->due['params'] );
  2396. return $this->_createElement( 'DUE', $attributes, $formatted );
  2397. }
  2398. /**
  2399. * set calendar component property due
  2400. *
  2401. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2402. * @since 2.4.8 - 2008-11-04
  2403. * @param mixed $year
  2404. * @param mixed $month optional
  2405. * @param int $day optional
  2406. * @param int $hour optional
  2407. * @param int $min optional
  2408. * @param int $sec optional
  2409. * @param array $params optional
  2410. * @return bool
  2411. */
  2412. function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  2413. if( empty( $year )) {
  2414. if( $this->getConfig( 'allowEmpty' )) {
  2415. $this->due = array( 'value' => null, 'params' => $this->_setParams( $params ));
  2416. return TRUE;
  2417. }
  2418. else
  2419. return FALSE;
  2420. }
  2421. $this->due = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
  2422. return TRUE;
  2423. }
  2424. /*********************************************************************************/
  2425. /**
  2426. * Property Name: DURATION
  2427. */
  2428. /**
  2429. * creates formatted output for calendar component property duration
  2430. *
  2431. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2432. * @since 2.4.8 - 2008-10-21
  2433. * @return string
  2434. */
  2435. function createDuration() {
  2436. if( empty( $this->duration )) return FALSE;
  2437. if( !isset( $this->duration['value']['week'] ) &&
  2438. !isset( $this->duration['value']['day'] ) &&
  2439. !isset( $this->duration['value']['hour'] ) &&
  2440. !isset( $this->duration['value']['min'] ) &&
  2441. !isset( $this->duration['value']['sec'] ))
  2442. if( $this->getConfig( 'allowEmpty' ))
  2443. return $this->_createElement( 'DURATION', array(), null );
  2444. else return FALSE;
  2445. $attributes = $this->_createParams( $this->duration['params'] );
  2446. return $this->_createElement( 'DURATION', $attributes, $this->_format_duration( $this->duration['value'] ));
  2447. }
  2448. /**
  2449. * set calendar component property duration
  2450. *
  2451. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2452. * @since 2.4.8 - 2008-11-04
  2453. * @param mixed $week
  2454. * @param mixed $day optional
  2455. * @param int $hour optional
  2456. * @param int $min optional
  2457. * @param int $sec optional
  2458. * @param array $params optional
  2459. * @return bool
  2460. */
  2461. function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2462. if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
  2463. if( is_array( $week ) && ( 1 <= count( $week )))
  2464. $this->duration = array( 'value' => $this->_duration_array( $week ), 'params' => $this->_setParams( $day ));
  2465. elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
  2466. $week = trim( $week );
  2467. if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
  2468. $week = substr( $week, 1 );
  2469. $this->duration = array( 'value' => $this->_duration_string( $week ), 'params' => $this->_setParams( $day ));
  2470. }
  2471. elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
  2472. return FALSE;
  2473. else
  2474. $this->duration = array( 'value' => $this->_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => $this->_setParams( $params ));
  2475. return TRUE;
  2476. }
  2477. /*********************************************************************************/
  2478. /**
  2479. * Property Name: EXDATE
  2480. */
  2481. /**
  2482. * creates formatted output for calendar component property exdate
  2483. *
  2484. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2485. * @since 2.4.8 - 2008-10-22
  2486. * @return string
  2487. */
  2488. function createExdate() {
  2489. if( empty( $this->exdate )) return FALSE;
  2490. $output = null;
  2491. foreach( $this->exdate as $ex => $theExdate ) {
  2492. if( empty( $theExdate['value'] )) {
  2493. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'EXDATE' );
  2494. continue;
  2495. }
  2496. $content = $attributes = null;
  2497. foreach( $theExdate['value'] as $eix => $exdatePart ) {
  2498. $parno = count( $exdatePart );
  2499. $formatted = $this->_format_date_time( $exdatePart, $parno );
  2500. if( isset( $theExdate['params']['TZID'] ))
  2501. $formatted = str_replace( 'Z', '', $formatted);
  2502. if( 0 < $eix ) {
  2503. if( isset( $theExdate['value'][0]['tz'] )) {
  2504. if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) ||
  2505. ( 'Z' == $theExdate['value'][0]['tz'] )) {
  2506. if( 'Z' != substr( $formatted, -1 ))
  2507. $formatted .= 'Z';
  2508. }
  2509. else
  2510. $formatted = str_replace( 'Z', '', $formatted );
  2511. }
  2512. else
  2513. $formatted = str_replace( 'Z', '', $formatted );
  2514. }
  2515. $content .= ( 0 < $eix ) ? ','.$formatted : $formatted;
  2516. }
  2517. $attributes .= $this->_createParams( $theExdate['params'] );
  2518. $output .= $this->_createElement( 'EXDATE', $attributes, $content );
  2519. }
  2520. return $output;
  2521. }
  2522. /**
  2523. * set calendar component property exdate
  2524. *
  2525. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2526. * @since 2.5.1 - 2008-11-05
  2527. * @param array exdates
  2528. * @param array $params, optional
  2529. * @param integer $index, optional
  2530. * @return bool
  2531. */
  2532. function setExdate( $exdates, $params=FALSE, $index=FALSE ) {
  2533. if( empty( $exdates )) {
  2534. if( $this->getConfig( 'allowEmpty' )) {
  2535. $this->_setMval( $this->exdate, null, $params, FALSE, $index );
  2536. return TRUE;
  2537. }
  2538. else
  2539. return FALSE;
  2540. }
  2541. $input = array( 'params' => $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
  2542. /* ev. check 1:st date and save ev. timezone **/
  2543. $this->_chkdatecfg( reset( $exdates ), $parno, $input['params'] );
  2544. $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
  2545. foreach( $exdates as $eix => $theExdate ) {
  2546. if( $this->_isArrayTimestampDate( $theExdate ))
  2547. $exdatea = $this->_timestamp2date( $theExdate, $parno );
  2548. elseif( is_array( $theExdate ))
  2549. $exdatea = $this->_date_time_array( $theExdate, $parno );
  2550. elseif( 8 <= strlen( trim( $theExdate ))) // ex. 2006-08-03 10:12:18
  2551. $exdatea = $this->_date_time_string( $theExdate, $parno );
  2552. if( 3 == $parno )
  2553. unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] );
  2554. elseif( isset( $exdatea['tz'] ))
  2555. $exdatea['tz'] = (string) $exdatea['tz'];
  2556. if( isset( $input['params']['TZID'] ) ||
  2557. ( isset( $exdatea['tz'] ) && !$this->_isOffset( $exdatea['tz'] )) ||
  2558. ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
  2559. ( isset( $input['value'][0]['tz'] ) && !$this->_isOffset( $input['value'][0]['tz'] )))
  2560. unset( $exdatea['tz'] );
  2561. $input['value'][] = $exdatea;
  2562. }
  2563. if( 0 >= count( $input['value'] ))
  2564. return FALSE;
  2565. if( 3 == $parno ) {
  2566. $input['params']['VALUE'] = 'DATE';
  2567. unset( $input['params']['TZID'] );
  2568. }
  2569. $this->_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index );
  2570. return TRUE;
  2571. }
  2572. /*********************************************************************************/
  2573. /**
  2574. * Property Name: EXRULE
  2575. */
  2576. /**
  2577. * creates formatted output for calendar component property exrule
  2578. *
  2579. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2580. * @since 2.4.8 - 2008-10-22
  2581. * @return string
  2582. */
  2583. function createExrule() {
  2584. if( empty( $this->exrule )) return FALSE;
  2585. return $this->_format_recur( 'EXRULE', $this->exrule );
  2586. }
  2587. /**
  2588. * set calendar component property exdate
  2589. *
  2590. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2591. * @since 2.5.1 - 2008-11-05
  2592. * @param array $exruleset
  2593. * @param array $params, optional
  2594. * @param integer $index, optional
  2595. * @return bool
  2596. */
  2597. function setExrule( $exruleset, $params=FALSE, $index=FALSE ) {
  2598. if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = null; else return FALSE;
  2599. $this->_setMval( $this->exrule, $this->_setRexrule( $exruleset ), $params, FALSE, $index );
  2600. return TRUE;
  2601. }
  2602. /*********************************************************************************/
  2603. /**
  2604. * Property Name: FREEBUSY
  2605. */
  2606. /**
  2607. * creates formatted output for calendar component property freebusy
  2608. *
  2609. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2610. * @since 2.4.8 - 2008-10-22
  2611. * @return string
  2612. */
  2613. function createFreebusy() {
  2614. if( empty( $this->freebusy )) return FALSE;
  2615. $output = null;
  2616. foreach( $this->freebusy as $freebusyPart ) {
  2617. if( empty( $freebusyPart['value'] )) {
  2618. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' );
  2619. continue;
  2620. }
  2621. $attributes = $content = null;
  2622. if( isset( $freebusyPart['value']['fbtype'] )) {
  2623. $attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype'];
  2624. unset( $freebusyPart['value']['fbtype'] );
  2625. $freebusyPart['value'] = array_values( $freebusyPart['value'] );
  2626. }
  2627. else
  2628. $attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY';
  2629. $attributes .= $this->_createParams( $freebusyPart['params'] );
  2630. $fno = 1;
  2631. $cnt = count( $freebusyPart['value']);
  2632. foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
  2633. $formatted = $this->_format_date_time( $freebusyPeriod[0] );
  2634. $content .= $formatted;
  2635. $content .= '/';
  2636. $cnt2 = count( $freebusyPeriod[1]);
  2637. if( array_key_exists( 'year', $freebusyPeriod[1] )) // date-time
  2638. $cnt2 = 7;
  2639. elseif( array_key_exists( 'week', $freebusyPeriod[1] )) // duration
  2640. $cnt2 = 5;
  2641. if(( 7 == $cnt2 ) && // period= -> date-time
  2642. isset( $freebusyPeriod[1]['year'] ) &&
  2643. isset( $freebusyPeriod[1]['month'] ) &&
  2644. isset( $freebusyPeriod[1]['day'] )) {
  2645. $content .= $this->_format_date_time( $freebusyPeriod[1] );
  2646. }
  2647. else { // period= -> dur-time
  2648. $content .= $this->_format_duration( $freebusyPeriod[1] );
  2649. }
  2650. if( $fno < $cnt )
  2651. $content .= ',';
  2652. $fno++;
  2653. }
  2654. $output .= $this->_createElement( 'FREEBUSY', $attributes, $content );
  2655. }
  2656. return $output;
  2657. }
  2658. /**
  2659. * set calendar component property freebusy
  2660. *
  2661. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2662. * @since 2.5.1 - 2008-11-05
  2663. * @param string $fbType
  2664. * @param array $fbValues
  2665. * @param array $params, optional
  2666. * @param integer $index, optional
  2667. * @return bool
  2668. */
  2669. function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) {
  2670. if( empty( $fbValues )) {
  2671. if( $this->getConfig( 'allowEmpty' )) {
  2672. $this->_setMval( $this->freebusy, null, $params, FALSE, $index );
  2673. return TRUE;
  2674. }
  2675. else
  2676. return FALSE;
  2677. }
  2678. $fbType = strtoupper( $fbType );
  2679. if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) &&
  2680. ( 'X-' != substr( $fbType, 0, 2 )))
  2681. $fbType = 'BUSY';
  2682. $input = array( 'fbtype' => $fbType );
  2683. foreach( $fbValues as $fbPeriod ) { // periods => period
  2684. $freebusyPeriod = array();
  2685. foreach( $fbPeriod as $fbMember ) { // pairs => singlepart
  2686. $freebusyPairMember = array();
  2687. if( is_array( $fbMember )) {
  2688. if( $this->_isArrayDate( $fbMember )) { // date-time value
  2689. $freebusyPairMember = $this->_date_time_array( $fbMember, 7 );
  2690. $freebusyPairMember['tz'] = 'Z';
  2691. }
  2692. elseif( $this->_isArrayTimestampDate( $fbMember )) { // timestamp value
  2693. $freebusyPairMember = $this->_timestamp2date( $fbMember['timestamp'], 7 );
  2694. $freebusyPairMember['tz'] = 'Z';
  2695. }
  2696. else { // array format duration
  2697. $freebusyPairMember = $this->_duration_array( $fbMember );
  2698. }
  2699. }
  2700. elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
  2701. ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
  2702. if( 'P' != $fbMember{0} )
  2703. $fbmember = substr( $fbMember, 1 );
  2704. $freebusyPairMember = $this->_duration_string( $fbMember );
  2705. }
  2706. elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
  2707. $freebusyPairMember = $this->_date_time_string( $fbMember, 7 );
  2708. $freebusyPairMember['tz'] = 'Z';
  2709. }
  2710. $freebusyPeriod[] = $freebusyPairMember;
  2711. }
  2712. $input[] = $freebusyPeriod;
  2713. }
  2714. $this->_setMval( $this->freebusy, $input, $params, FALSE, $index );
  2715. return TRUE;
  2716. }
  2717. /*********************************************************************************/
  2718. /**
  2719. * Property Name: GEO
  2720. */
  2721. /**
  2722. * creates formatted output for calendar component property geo
  2723. *
  2724. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2725. * @since 2.4.8 - 2008-10-21
  2726. * @return string
  2727. */
  2728. function createGeo() {
  2729. if( empty( $this->geo )) return FALSE;
  2730. if( empty( $this->geo['value'] ))
  2731. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE;
  2732. $attributes = $this->_createParams( $this->geo['params'] );
  2733. $content = null;
  2734. $content .= number_format( (float) $this->geo['value']['latitude'], 6, '.', '');
  2735. $content .= ';';
  2736. $content .= number_format( (float) $this->geo['value']['longitude'], 6, '.', '');
  2737. return $this->_createElement( 'GEO', $attributes, $content );
  2738. }
  2739. /**
  2740. * set calendar component property geo
  2741. *
  2742. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2743. * @since 2.4.8 - 2008-11-04
  2744. * @param float $latitude
  2745. * @param float $longitude
  2746. * @param array $params optional
  2747. * @return bool
  2748. */
  2749. function setGeo( $latitude, $longitude, $params=FALSE ) {
  2750. if( !empty( $latitude ) && !empty( $longitude )) {
  2751. if( !is_array( $this->geo )) $this->geo = array();
  2752. $this->geo['value']['latitude'] = $latitude;
  2753. $this->geo['value']['longitude'] = $longitude;
  2754. $this->geo['params'] = $this->_setParams( $params );
  2755. }
  2756. elseif( $this->getConfig( 'allowEmpty' ))
  2757. $this->geo = array( 'value' => null, 'params' => $this->_setParams( $params ) );
  2758. else
  2759. return FALSE;
  2760. return TRUE;
  2761. }
  2762. /*********************************************************************************/
  2763. /**
  2764. * Property Name: LAST-MODIFIED
  2765. */
  2766. /**
  2767. * creates formatted output for calendar component property last-modified
  2768. *
  2769. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2770. * @since 2.4.8 - 2008-10-21
  2771. * @return string
  2772. */
  2773. function createLastModified() {
  2774. if( empty( $this->lastmodified )) return FALSE;
  2775. $attributes = $this->_createParams( $this->lastmodified['params'] );
  2776. $formatted = $this->_format_date_time( $this->lastmodified['value'], 7 );
  2777. return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
  2778. }
  2779. /**
  2780. * set calendar component property completed
  2781. *
  2782. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2783. * @since 2.4.8 - 2008-10-23
  2784. * @param mixed $year optional
  2785. * @param mixed $month optional
  2786. * @param int $day optional
  2787. * @param int $hour optional
  2788. * @param int $min optional
  2789. * @param int $sec optional
  2790. * @param array $params optional
  2791. * @return boll
  2792. */
  2793. function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  2794. if( empty( $year ))
  2795. $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
  2796. $this->lastmodified = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
  2797. return TRUE;
  2798. }
  2799. /*********************************************************************************/
  2800. /**
  2801. * Property Name: LOCATION
  2802. */
  2803. /**
  2804. * creates formatted output for calendar component property location
  2805. *
  2806. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2807. * @since 2.4.8 - 2008-10-22
  2808. * @return string
  2809. */
  2810. function createLocation() {
  2811. if( empty( $this->location )) return FALSE;
  2812. if( empty( $this->location['value'] ))
  2813. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
  2814. $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
  2815. $content = $this->_strrep( $this->location['value'] );
  2816. return $this->_createElement( 'LOCATION', $attributes, $content );
  2817. }
  2818. /**
  2819. * set calendar component property location
  2820. '
  2821. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2822. * @since 2.4.8 - 2008-11-04
  2823. * @param string $value
  2824. * @param array params optional
  2825. * @return bool
  2826. */
  2827. function setLocation( $value, $params=FALSE ) {
  2828. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2829. $this->location = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2830. return TRUE;
  2831. }
  2832. /*********************************************************************************/
  2833. /**
  2834. * Property Name: ORGANIZER
  2835. */
  2836. /**
  2837. * creates formatted output for calendar component property organizer
  2838. *
  2839. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2840. * @since 2.4.8 - 2008-10-21
  2841. * @return string
  2842. */
  2843. function createOrganizer() {
  2844. if( empty( $this->organizer )) return FALSE;
  2845. if( empty( $this->organizer['value'] ))
  2846. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
  2847. $attributes = $this->_createParams( $this->organizer['params']
  2848. , array( 'CN', 'DIR', 'LANGUAGE', 'SENT-BY' ));
  2849. $content = 'MAILTO:'.$this->organizer['value'];
  2850. return $this->_createElement( 'ORGANIZER', $attributes, $content );
  2851. }
  2852. /**
  2853. * set calendar component property organizer
  2854. *
  2855. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2856. * @since 2.4.8 - 2008-11-04
  2857. * @param string $value
  2858. * @param array params optional
  2859. * @return bool
  2860. */
  2861. function setOrganizer( $value, $params=FALSE ) {
  2862. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2863. $value = str_replace ( 'MAILTO:', '', $value );
  2864. $value = str_replace ( 'mailto:', '', $value );
  2865. $this->organizer = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2866. if( isset( $this->organizer['params']['SENT-BY'] )) {
  2867. if( 'MAILTO' == strtoupper( substr( $this->organizer['params']['SENT-BY'], 0, 6 )))
  2868. $this->organizer['params']['SENT-BY'] = substr( $this->organizer['params']['SENT-BY'], 7 );
  2869. }
  2870. return TRUE;
  2871. }
  2872. /*********************************************************************************/
  2873. /**
  2874. * Property Name: PERCENT-COMPLETE
  2875. */
  2876. /**
  2877. * creates formatted output for calendar component property percent-complete
  2878. *
  2879. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2880. * @since 2.4.8 - 2008-10-22
  2881. * @return string
  2882. */
  2883. function createPercentComplete() {
  2884. if( empty( $this->percentcomplete )) return FALSE;
  2885. if( empty( $this->percentcomplete['value'] ))
  2886. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE;
  2887. $attributes = $this->_createParams( $this->percentcomplete['params'] );
  2888. return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] );
  2889. }
  2890. /**
  2891. * set calendar component property percent-complete
  2892. *
  2893. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2894. * @since 2.4.8 - 2008-11-04
  2895. * @param int $value
  2896. * @param array $params optional
  2897. * @return bool
  2898. */
  2899. function setPercentComplete( $value, $params=FALSE ) {
  2900. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2901. $this->percentcomplete = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2902. return TRUE;
  2903. }
  2904. /*********************************************************************************/
  2905. /**
  2906. * Property Name: PRIORITY
  2907. */
  2908. /**
  2909. * creates formatted output for calendar component property priority
  2910. *
  2911. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2912. * @since 2.4.8 - 2008-10-21
  2913. * @return string
  2914. */
  2915. function createPriority() {
  2916. if( empty( $this->priority )) return FALSE;
  2917. if( empty( $this->priority['value'] ))
  2918. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
  2919. $attributes = $this->_createParams( $this->priority['params'] );
  2920. return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
  2921. }
  2922. /**
  2923. * set calendar component property priority
  2924. *
  2925. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2926. * @since 2.4.8 - 2008-11-04
  2927. * @param int $value
  2928. * @param array $params optional
  2929. * @return bool
  2930. */
  2931. function setPriority( $value, $params=FALSE ) {
  2932. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  2933. $this->priority = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  2934. return TRUE;
  2935. }
  2936. /*********************************************************************************/
  2937. /**
  2938. * Property Name: RDATE
  2939. */
  2940. /**
  2941. * creates formatted output for calendar component property rdate
  2942. *
  2943. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  2944. * @since 2.4.16 - 2008-10-26
  2945. * @return string
  2946. */
  2947. function createRdate() {
  2948. if( empty( $this->rdate )) return FALSE;
  2949. $utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
  2950. $output = null;
  2951. if( $utctime )
  2952. unset( $this->rdate['params']['TZID'] );
  2953. foreach( $this->rdate as $theRdate ) {
  2954. if( empty( $theRdate['value'] )) {
  2955. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
  2956. continue;
  2957. }
  2958. if( $utctime )
  2959. unset( $theRdate['params']['TZID'] );
  2960. $attributes = $this->_createParams( $theRdate['params'] );
  2961. $cnt = count( $theRdate['value'] );
  2962. $content = null;
  2963. $rno = 1;
  2964. foreach( $theRdate['value'] as $rpix => $rdatePart ) {
  2965. $contentPart = null;
  2966. if( is_array( $rdatePart ) &&
  2967. isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
  2968. if( $utctime )
  2969. unset( $rdatePart[0]['tz'] );
  2970. $formatted = $this->_format_date_time( $rdatePart[0]); // PERIOD part 1
  2971. if( $utctime || !empty( $theRdate['params']['TZID'] ))
  2972. $formatted = str_replace( 'Z', '', $formatted);
  2973. if( 0 < $rpix ) {
  2974. if( !empty( $rdatePart[0]['tz'] ) && $this->_isOffset( $rdatePart[0]['tz'] )) {
  2975. if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
  2976. }
  2977. else
  2978. $formatted = str_replace( 'Z', '', $formatted );
  2979. }
  2980. $contentPart .= $formatted;
  2981. $contentPart .= '/';
  2982. $cnt2 = count( $rdatePart[1]);
  2983. if( array_key_exists( 'year', $rdatePart[1] )) {
  2984. if( array_key_exists( 'hour', $rdatePart[1] ))
  2985. $cnt2 = 7; // date-time
  2986. else
  2987. $cnt2 = 3; // date
  2988. }
  2989. elseif( array_key_exists( 'week', $rdatePart[1] )) // duration
  2990. $cnt2 = 5;
  2991. if(( 7 == $cnt2 ) && // period= -> date-time
  2992. isset( $rdatePart[1]['year'] ) &&
  2993. isset( $rdatePart[1]['month'] ) &&
  2994. isset( $rdatePart[1]['day'] )) {
  2995. if( $utctime )
  2996. unset( $rdatePart[1]['tz'] );
  2997. $formatted = $this->_format_date_time( $rdatePart[1] ); // PERIOD part 2
  2998. if( $utctime || !empty( $theRdate['params']['TZID'] ))
  2999. $formatted = str_replace( 'Z', '', $formatted);
  3000. if( !empty( $rdatePart[0]['tz'] ) && $this->_isOffset( $rdatePart[0]['tz'] )) {
  3001. if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
  3002. }
  3003. else
  3004. $formatted = str_replace( 'Z', '', $formatted );
  3005. $contentPart .= $formatted;
  3006. }
  3007. else { // period= -> dur-time
  3008. $contentPart .= $this->_format_duration( $rdatePart[1] );
  3009. }
  3010. } // PERIOD end
  3011. else { // SINGLE date start
  3012. if( $utctime )
  3013. unset( $rdatePart['tz'] );
  3014. $formatted = $this->_format_date_time( $rdatePart);
  3015. if( $utctime || !empty( $theRdate['params']['TZID'] ))
  3016. $formatted = str_replace( 'Z', '', $formatted);
  3017. if( !$utctime && ( 0 < $rpix )) {
  3018. if( !empty( $theRdate['value'][0]['tz'] ) && $this->_isOffset( $theRdate['value'][0]['tz'] )) {
  3019. if( 'Z' != substr( $formatted, -1 ))
  3020. $formatted .= 'Z';
  3021. }
  3022. else
  3023. $formatted = str_replace( 'Z', '', $formatted );
  3024. }
  3025. $contentPart .= $formatted;
  3026. }
  3027. $content .= $contentPart;
  3028. if( $rno < $cnt )
  3029. $content .= ',';
  3030. $rno++;
  3031. }
  3032. $output .= $this->_createElement( 'RDATE', $attributes, $content );
  3033. }
  3034. return $output;
  3035. }
  3036. /**
  3037. * set calendar component property rdate
  3038. *
  3039. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3040. * @since 2.5.1 - 2008-11-07
  3041. * @param array $rdates
  3042. * @param array $params, optional
  3043. * @param integer $index, optional
  3044. * @return bool
  3045. */
  3046. function setRdate( $rdates, $params=FALSE, $index=FALSE ) {
  3047. if( empty( $rdates )) {
  3048. if( $this->getConfig( 'allowEmpty' )) {
  3049. $this->_setMval( $this->rdate, null, $params, FALSE, $index );
  3050. return TRUE;
  3051. }
  3052. else
  3053. return FALSE;
  3054. }
  3055. $input = array( 'params' => $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
  3056. if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) {
  3057. unset( $input['params']['TZID'] );
  3058. $input['params']['VALUE'] = 'DATE-TIME';
  3059. }
  3060. /* check if PERIOD, if not set */
  3061. if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) &&
  3062. isset( $rdates[0] ) && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) &&
  3063. isset( $rdates[0][0] ) && isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) &&
  3064. (( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) ||
  3065. $this->_isArrayDate( $rdates[0][0] ))) ||
  3066. ( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] ))))) &&
  3067. ( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] ))))))
  3068. $input['params']['VALUE'] = 'PERIOD';
  3069. /* check 1:st date, upd. $parno (opt) and save ev. timezone **/
  3070. $date = reset( $rdates );
  3071. if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD
  3072. $date = reset( $date );
  3073. $this->_chkdatecfg( $date, $parno, $input['params'] );
  3074. if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
  3075. unset( $input['params']['TZID'] );
  3076. $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default
  3077. foreach( $rdates as $rpix => $theRdate ) {
  3078. $inputa = null;
  3079. if( is_array( $theRdate )) {
  3080. if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD
  3081. foreach( $theRdate as $rix => $rPeriod ) {
  3082. if( is_array( $rPeriod )) {
  3083. if( $this->_isArrayTimestampDate( $rPeriod )) // timestamp
  3084. $inputab = ( isset( $rPeriod['tz'] )) ? $this->_timestamp2date( $rPeriod, $parno ) : $this->_timestamp2date( $rPeriod, 6 );
  3085. elseif( $this->_isArrayDate( $rPeriod ))
  3086. $inputab = ( 3 < count ( $rPeriod )) ? $this->_date_time_array( $rPeriod, $parno ) : $this->_date_time_array( $rPeriod, 6 );
  3087. elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) // text-date
  3088. $inputab = $this->_date_time_string( reset( $rPeriod ), $parno );
  3089. else // array format duration
  3090. $inputab = $this->_duration_array( $rPeriod );
  3091. }
  3092. elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
  3093. ( in_array( $rPeriod{0}, array( 'P', '+', '-' )))) {
  3094. if( 'P' != $rPeriod{0} )
  3095. $rPeriod = substr( $rPeriod, 1 );
  3096. $inputab = $this->_duration_string( $rPeriod );
  3097. }
  3098. elseif( 8 <= strlen( trim( $rPeriod ))) // text date ex. 2006-08-03 10:12:18
  3099. $inputab = $this->_date_time_string( $rPeriod, $parno );
  3100. if( isset( $input['params']['TZID'] ) ||
  3101. ( isset( $inputab['tz'] ) && !$this->_isOffset( $inputab['tz'] )) ||
  3102. ( isset( $inputa[0] ) && ( !isset( $inputa[0]['tz'] ))) ||
  3103. ( isset( $inputa[0]['tz'] ) && !$this->_isOffset( $inputa[0]['tz'] )))
  3104. unset( $inputab['tz'] );
  3105. $inputa[] = $inputab;
  3106. }
  3107. } // PERIOD end
  3108. elseif ( $this->_isArrayTimestampDate( $theRdate )) // timestamp
  3109. $inputa = $this->_timestamp2date( $theRdate, $parno );
  3110. else // date[-time]
  3111. $inputa = $this->_date_time_array( $theRdate, $parno );
  3112. }
  3113. elseif( 8 <= strlen( trim( $theRdate ))) // text date ex. 2006-08-03 10:12:18
  3114. $inputa = $this->_date_time_string( $theRdate, $parno );
  3115. if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
  3116. if( 3 == $parno )
  3117. unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
  3118. elseif( isset( $inputa['tz'] ))
  3119. $inputa['tz'] = (string) $inputa['tz'];
  3120. if( isset( $input['params']['TZID'] ) ||
  3121. ( isset( $inputa['tz'] ) && !$this->_isOffset( $inputa['tz'] )) ||
  3122. ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
  3123. ( isset( $input['value'][0]['tz'] ) && !$this->_isOffset( $input['value'][0]['tz'] )))
  3124. unset( $inputa['tz'] );
  3125. }
  3126. $input['value'][] = $inputa;
  3127. }
  3128. if( 3 == $parno ) {
  3129. $input['params']['VALUE'] = 'DATE';
  3130. unset( $input['params']['TZID'] );
  3131. }
  3132. $this->_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index );
  3133. return TRUE;
  3134. }
  3135. /*********************************************************************************/
  3136. /**
  3137. * Property Name: RECURRENCE-ID
  3138. */
  3139. /**
  3140. * creates formatted output for calendar component property recurrence-id
  3141. *
  3142. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3143. * @since 2.4.8 - 2008-10-21
  3144. * @return string
  3145. */
  3146. function createRecurrenceid() {
  3147. if( empty( $this->recurrenceid )) return FALSE;
  3148. if( empty( $this->recurrenceid['value'] ))
  3149. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
  3150. $formatted = $this->_format_date_time( $this->recurrenceid['value'] );
  3151. $attributes = $this->_createParams( $this->recurrenceid['params'] );
  3152. return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
  3153. }
  3154. /**
  3155. * set calendar component property recurrence-id
  3156. *
  3157. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3158. * @since 2.4.8 - 2008-10-23
  3159. * @param mixed $year
  3160. * @param mixed $month optional
  3161. * @param int $day optional
  3162. * @param int $hour optional
  3163. * @param int $min optional
  3164. * @param int $sec optional
  3165. * @param array $params optional
  3166. * @return bool
  3167. */
  3168. function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
  3169. if( empty( $year )) {
  3170. if( $this->getConfig( 'allowEmpty' )) {
  3171. $this->recurrenceid = array( 'value' => null, 'params' => null );
  3172. return TRUE;
  3173. }
  3174. else
  3175. return FALSE;
  3176. }
  3177. $this->recurrenceid = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
  3178. return TRUE;
  3179. }
  3180. /*********************************************************************************/
  3181. /**
  3182. * Property Name: RELATED-TO
  3183. */
  3184. /**
  3185. * creates formatted output for calendar component property related-to
  3186. *
  3187. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3188. * @since 2.4.8 - 2008-10-23
  3189. * @return string
  3190. */
  3191. function createRelatedTo() {
  3192. if( empty( $this->relatedto )) return FALSE;
  3193. $output = null;
  3194. foreach( $this->relatedto as $relation ) {
  3195. if( empty( $relation['value'] )) {
  3196. if( $this->getConfig( 'allowEmpty' )) $output.= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ));
  3197. continue;
  3198. }
  3199. $attributes = $this->_createParams( $relation['params'] );
  3200. $content = ( 'xcal' != $this->format ) ? '<' : '';
  3201. $content .= $this->_strrep( $relation['value'] );
  3202. $content .= ( 'xcal' != $this->format ) ? '>' : '';
  3203. $output .= $this->_createElement( 'RELATED-TO', $attributes, $content );
  3204. }
  3205. return $output;
  3206. }
  3207. /**
  3208. * set calendar component property related-to
  3209. *
  3210. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3211. * @since 2.5.1 - 2008-11-07
  3212. * @param float $relid
  3213. * @param array $params, optional
  3214. * @param index $index, optional
  3215. * @return bool
  3216. */
  3217. function setRelatedTo( $value, $params=FALSE, $index=FALSE ) {
  3218. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3219. if(( '<' == substr( $value, 0, 1 )) && ( '>' == substr( $value, -1 )))
  3220. $value = substr( $value, 1, ( strlen( $value ) - 2 ));
  3221. $this->_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default
  3222. $this->_setMval( $this->relatedto, $value, $params, FALSE, $index );
  3223. return TRUE;
  3224. }
  3225. /*********************************************************************************/
  3226. /**
  3227. * Property Name: REPEAT
  3228. */
  3229. /**
  3230. * creates formatted output for calendar component property repeat
  3231. *
  3232. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3233. * @since 2.4.8 - 2008-10-21
  3234. * @return string
  3235. */
  3236. function createRepeat() {
  3237. if( empty( $this->repeat )) return FALSE;
  3238. if( empty( $this->repeat['value'] ))
  3239. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE;
  3240. $attributes = $this->_createParams( $this->repeat['params'] );
  3241. return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] );
  3242. }
  3243. /**
  3244. * set calendar component property transp
  3245. *
  3246. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3247. * @since 2.4.8 - 2008-11-04
  3248. * @param string $value
  3249. * @param array $params optional
  3250. * @return void
  3251. */
  3252. function setRepeat( $value, $params=FALSE ) {
  3253. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3254. $this->repeat = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3255. return TRUE;
  3256. }
  3257. /*********************************************************************************/
  3258. /**
  3259. * Property Name: REQUEST-STATUS
  3260. */
  3261. /**
  3262. * creates formatted output for calendar component property request-status
  3263. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3264. * @since 2.4.8 - 2008-10-23
  3265. * @return string
  3266. */
  3267. function createRequestStatus() {
  3268. if( empty( $this->requeststatus )) return FALSE;
  3269. $output = null;
  3270. foreach( $this->requeststatus as $rstat ) {
  3271. if( empty( $rstat['value']['statcode'] )) {
  3272. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' );
  3273. continue;
  3274. }
  3275. $attributes = $this->_createParams( $rstat['params'], array( 'LANGUAGE' ));
  3276. $content = number_format( (float) $rstat['value']['statcode'], 2, '.', '');
  3277. $content .= ';'.$this->_strrep( $rstat['value']['text'] );
  3278. if( isset( $rstat['value']['extdata'] ))
  3279. $content .= ';'.$this->_strrep( $rstat['value']['extdata'] );
  3280. $output .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content );
  3281. }
  3282. return $output;
  3283. }
  3284. /**
  3285. * set calendar component property request-status
  3286. *
  3287. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3288. * @since 2.5.1 - 2008-11-05
  3289. * @param float $statcode
  3290. * @param string $text
  3291. * @param string $extdata, optional
  3292. * @param array $params, optional
  3293. * @param integer $index, optional
  3294. * @return bool
  3295. */
  3296. function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) {
  3297. if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = null; else return FALSE;
  3298. $input = array( 'statcode' => $statcode, 'text' => $text );
  3299. if( $extdata )
  3300. $input['extdata'] = $extdata;
  3301. $this->_setMval( $this->requeststatus, $input, $params, FALSE, $index );
  3302. return TRUE;
  3303. }
  3304. /*********************************************************************************/
  3305. /**
  3306. * Property Name: RESOURCES
  3307. */
  3308. /**
  3309. * creates formatted output for calendar component property resources
  3310. *
  3311. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3312. * @since 2.4.8 - 2008-10-23
  3313. * @return string
  3314. */
  3315. function createResources() {
  3316. if( empty( $this->resources )) return FALSE;
  3317. $output = null;
  3318. foreach( $this->resources as $resource ) {
  3319. if( empty( $resource['value'] )) {
  3320. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
  3321. continue;
  3322. }
  3323. $attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
  3324. if( is_array( $resource['value'] )) {
  3325. foreach( $resource['value'] as $rix => $resourcePart )
  3326. $resource['value'][$rix] = $this->_strrep( $resourcePart );
  3327. $content = implode( ',', $resource['value'] );
  3328. }
  3329. else
  3330. $content = $this->_strrep( $resource['value'] );
  3331. $output .= $this->_createElement( 'RESOURCES', $attributes, $content );
  3332. }
  3333. return $output;
  3334. }
  3335. /**
  3336. * set calendar component property recources
  3337. *
  3338. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3339. * @since 2.5.1 - 2008-11-05
  3340. * @param mixed $value
  3341. * @param array $params, optional
  3342. * @param integer $index, optional
  3343. * @return bool
  3344. */
  3345. function setResources( $value, $params=FALSE, $index=FALSE ) {
  3346. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3347. $this->_setMval( $this->resources, $value, $params, FALSE, $index );
  3348. return TRUE;
  3349. }
  3350. /*********************************************************************************/
  3351. /**
  3352. * Property Name: RRULE
  3353. */
  3354. /**
  3355. * creates formatted output for calendar component property rrule
  3356. *
  3357. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3358. * @since 2.4.8 - 2008-10-21
  3359. * @return string
  3360. */
  3361. function createRrule() {
  3362. if( empty( $this->rrule )) return FALSE;
  3363. return $this->_format_recur( 'RRULE', $this->rrule );
  3364. }
  3365. /**
  3366. * set calendar component property rrule
  3367. *
  3368. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3369. * @since 2.5.1 - 2008-11-05
  3370. * @param array $rruleset
  3371. * @param array $params, optional
  3372. * @param integer $index, optional
  3373. * @return void
  3374. */
  3375. function setRrule( $rruleset, $params=FALSE, $index=FALSE ) {
  3376. if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = null; else return FALSE;
  3377. $this->_setMval( $this->rrule, $this->_setRexrule( $rruleset ), $params, FALSE, $index );
  3378. return TRUE;
  3379. }
  3380. /*********************************************************************************/
  3381. /**
  3382. * Property Name: SEQUENCE
  3383. */
  3384. /**
  3385. * creates formatted output for calendar component property sequence
  3386. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3387. * @since 0.9.7 - 2006-11-20
  3388. * @return string
  3389. */
  3390. function createSequence() {
  3391. if( empty( $this->sequence )) return FALSE;
  3392. if( empty( $this->sequence['value'] ))
  3393. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
  3394. $attributes = $this->_createParams( $this->sequence['params'] );
  3395. return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
  3396. }
  3397. /**
  3398. * set calendar component property sequence
  3399. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3400. * @since 2.4.8 - 2008-11-04
  3401. * @param int $value optional
  3402. * @param array $params optional
  3403. * @return bool
  3404. */
  3405. function setSequence( $value=FALSE, $params=FALSE ) {
  3406. if( empty( $value ))
  3407. $value = ( isset( $this->sequence['value'] ) && ( 0 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : 1;
  3408. $this->sequence = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3409. return TRUE;
  3410. }
  3411. /*********************************************************************************/
  3412. /**
  3413. * Property Name: STATUS
  3414. */
  3415. /**
  3416. * creates formatted output for calendar component property status
  3417. *
  3418. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3419. * @since 2.4.8 - 2008-10-21
  3420. * @return string
  3421. */
  3422. function createStatus() {
  3423. if( empty( $this->status )) return FALSE;
  3424. if( empty( $this->status['value'] ))
  3425. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
  3426. $attributes = $this->_createParams( $this->status['params'] );
  3427. return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
  3428. }
  3429. /**
  3430. * set calendar component property status
  3431. *
  3432. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3433. * @since 2.4.8 - 2008-11-04
  3434. * @param string $value
  3435. * @param mixed $params optional (array or false)
  3436. * @return bool
  3437. */
  3438. function setStatus( $value, $params=FALSE ) {
  3439. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3440. $this->status = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3441. return TRUE;
  3442. }
  3443. /*********************************************************************************/
  3444. /**
  3445. * Property Name: SUMMARY
  3446. */
  3447. /**
  3448. * creates formatted output for calendar component property summary
  3449. *
  3450. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3451. * @since 2.4.8 - 2008-10-21
  3452. * @return string
  3453. */
  3454. function createSummary() {
  3455. if( empty( $this->summary )) return FALSE;
  3456. if( empty( $this->summary['value'] ))
  3457. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
  3458. $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
  3459. $content = $this->_strrep( $this->summary['value'] );
  3460. return $this->_createElement( 'SUMMARY', $attributes, $content );
  3461. }
  3462. /**
  3463. * set calendar component property summary
  3464. *
  3465. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3466. * @since 2.4.8 - 2008-11-04
  3467. * @param string $value
  3468. * @param string $params optional
  3469. * @return bool
  3470. */
  3471. function setSummary( $value, $params=FALSE ) {
  3472. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3473. $this->summary = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3474. return TRUE;
  3475. }
  3476. /*********************************************************************************/
  3477. /**
  3478. * Property Name: TRANSP
  3479. */
  3480. /**
  3481. * creates formatted output for calendar component property transp
  3482. *
  3483. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3484. * @since 2.4.8 - 2008-10-21
  3485. * @return string
  3486. */
  3487. function createTransp() {
  3488. if( empty( $this->transp )) return FALSE;
  3489. if( empty( $this->transp['value'] ))
  3490. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE;
  3491. $attributes = $this->_createParams( $this->transp['params'] );
  3492. return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] );
  3493. }
  3494. /**
  3495. * set calendar component property transp
  3496. *
  3497. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3498. * @since 2.4.8 - 2008-11-04
  3499. * @param string $value
  3500. * @param string $params optional
  3501. * @return bool
  3502. */
  3503. function setTransp( $value, $params=FALSE ) {
  3504. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3505. $this->transp = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3506. return TRUE;
  3507. }
  3508. /*********************************************************************************/
  3509. /**
  3510. * Property Name: TRIGGER
  3511. */
  3512. /**
  3513. * creates formatted output for calendar component property trigger
  3514. *
  3515. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3516. * @since 2.4.16 - 2008-10-21
  3517. * @return string
  3518. */
  3519. function createTrigger() {
  3520. if( empty( $this->trigger )) return FALSE;
  3521. if( empty( $this->trigger['value'] ))
  3522. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE;
  3523. $content = $attributes = null;
  3524. if( isset( $this->trigger['value']['year'] ) &&
  3525. isset( $this->trigger['value']['month'] ) &&
  3526. isset( $this->trigger['value']['day'] ))
  3527. $content .= $this->_format_date_time( $this->trigger['value'] );
  3528. else {
  3529. if( TRUE !== $this->trigger['value']['relatedStart'] )
  3530. $attributes .= $this->intAttrDelimiter.'RELATED=END';
  3531. if( $this->trigger['value']['before'] )
  3532. $content .= '-';
  3533. $content .= $this->_format_duration( $this->trigger['value'] );
  3534. }
  3535. $attributes .= $this->_createParams( $this->trigger['params'] );
  3536. return $this->_createElement( 'TRIGGER', $attributes, $content );
  3537. }
  3538. /**
  3539. * set calendar component property trigger
  3540. *
  3541. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3542. * @since 2.4.16 - 2008-11-04
  3543. * @param mixed $year
  3544. * @param mixed $month optional
  3545. * @param int $day optional
  3546. * @param int $week optional
  3547. * @param int $hour optional
  3548. * @param int $min optional
  3549. * @param int $sec optional
  3550. * @param bool $relatedStart optional
  3551. * @param bool $before optional
  3552. * @param array $params optional
  3553. * @return bool
  3554. */
  3555. function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) {
  3556. if( empty( $year ) && empty( $month ) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec ))
  3557. if( $this->getConfig( 'allowEmpty' )) {
  3558. $this->trigger = array( 'value' => null, 'params' => $this->_setParams( $params ) );
  3559. return TRUE;
  3560. }
  3561. else
  3562. return FALSE;
  3563. if( $this->_isArrayTimestampDate( $year )) { // timestamp
  3564. $params = $this->_setParams( $month );
  3565. $date = $this->_timestamp2date( $year, 7 );
  3566. foreach( $date as $k => $v )
  3567. $$k = $v;
  3568. }
  3569. elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) {
  3570. $params = $this->_setParams( $month );
  3571. if(!(array_key_exists( 'year', $year ) && // exclude date-time
  3572. array_key_exists( 'month', $year ) &&
  3573. array_key_exists( 'day', $year ))) { // so this must be a duration
  3574. if( isset( $params['RELATED'] ) && ( 'END' == $params['RELATED'] ))
  3575. $relatedStart = FALSE;
  3576. else
  3577. $relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE;
  3578. $before = ( array_key_exists( 'before', $year ) && ( TRUE !== $year['before'] )) ? FALSE : TRUE;
  3579. }
  3580. $SSYY = ( array_key_exists( 'year', $year )) ? $year['year'] : null;
  3581. $month = ( array_key_exists( 'month', $year )) ? $year['month'] : null;
  3582. $day = ( array_key_exists( 'day', $year )) ? $year['day'] : null;
  3583. $week = ( array_key_exists( 'week', $year )) ? $year['week'] : null;
  3584. $hour = ( array_key_exists( 'hour', $year )) ? $year['hour'] : 0; //null;
  3585. $min = ( array_key_exists( 'min', $year )) ? $year['min'] : 0; //null;
  3586. $sec = ( array_key_exists( 'sec', $year )) ? $year['sec'] : 0; //null;
  3587. $year = $SSYY;
  3588. }
  3589. elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) { // duration or date in a string
  3590. $params = $this->_setParams( $month );
  3591. if( in_array( $year{0}, array( 'P', '+', '-' ))) { // duration
  3592. $relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == $params['RELATED'] )) ? FALSE : TRUE;
  3593. $before = ( '-' == $year{0} ) ? TRUE : FALSE;
  3594. if( 'P' != $year{0} )
  3595. $year = substr( $year, 1 );
  3596. $date = $this->_duration_string( $year);
  3597. }
  3598. else // date
  3599. $date = $this->_date_time_string( $year, 7 );
  3600. unset( $year, $month, $day );
  3601. foreach( $date as $k => $v )
  3602. $$k = $v;
  3603. }
  3604. else // single values in function input parameters
  3605. $params = $this->_setParams( $params );
  3606. if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date
  3607. $params['VALUE'] = 'DATE-TIME';
  3608. $hour = ( $hour ) ? $hour : 0;
  3609. $min = ( $min ) ? $min : 0;
  3610. $sec = ( $sec ) ? $sec : 0;
  3611. $this->trigger = array( 'params' => $params );
  3612. $this->trigger['value'] = array( 'year' => $year
  3613. , 'month' => $month
  3614. , 'day' => $day
  3615. , 'hour' => $hour
  3616. , 'min' => $min
  3617. , 'sec' => $sec
  3618. , 'tz' => 'Z' );
  3619. return TRUE;
  3620. }
  3621. elseif(( empty( $year ) && empty( $month )) && // duration
  3622. (!empty( $week ) || !empty( $day ) || !empty( $hour ) || !empty( $min ) || !empty( $sec ))) {
  3623. unset( $params['RELATED'] ); // set at output creation (END only)
  3624. unset( $params['VALUE'] ); // 'DURATION' default
  3625. $this->trigger = array( 'params' => $params );
  3626. $relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE;
  3627. $before = ( FALSE !== $before ) ? TRUE : FALSE;
  3628. $this->trigger['value'] = array( 'relatedStart' => $relatedStart
  3629. , 'before' => $before );
  3630. if( !empty( $week )) $this->trigger['value']['week'] = $week;
  3631. if( !empty( $day )) $this->trigger['value']['day'] = $day;
  3632. if( !empty( $hour )) $this->trigger['value']['hour'] = $hour;
  3633. if( !empty( $min )) $this->trigger['value']['min'] = $min;
  3634. if( !empty( $sec )) $this->trigger['value']['sec'] = $sec;
  3635. return TRUE;
  3636. }
  3637. return FALSE;
  3638. }
  3639. /*********************************************************************************/
  3640. /**
  3641. * Property Name: TZID
  3642. */
  3643. /**
  3644. * creates formatted output for calendar component property tzid
  3645. *
  3646. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3647. * @since 2.4.8 - 2008-10-21
  3648. * @return string
  3649. */
  3650. function createTzid() {
  3651. if( empty( $this->tzid )) return FALSE;
  3652. if( empty( $this->tzid['value'] ))
  3653. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
  3654. $attributes = $this->_createParams( $this->tzid['params'] );
  3655. return $this->_createElement( 'TZID', $attributes, $this->_strrep( $this->tzid['value'] ));
  3656. }
  3657. /**
  3658. * set calendar component property tzid
  3659. *
  3660. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3661. * @since 2.4.8 - 2008-11-04
  3662. * @param string $value
  3663. * @param array $params optional
  3664. * @return bool
  3665. */
  3666. function setTzid( $value, $params=FALSE ) {
  3667. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3668. $this->tzid = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3669. return TRUE;
  3670. }
  3671. /*********************************************************************************/
  3672. /**
  3673. * .. .
  3674. * Property Name: TZNAME
  3675. */
  3676. /**
  3677. * creates formatted output for calendar component property tzname
  3678. *
  3679. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3680. * @since 2.4.8 - 2008-10-21
  3681. * @return string
  3682. */
  3683. function createTzname() {
  3684. if( empty( $this->tzname )) return FALSE;
  3685. $output = null;
  3686. foreach( $this->tzname as $theName ) {
  3687. if( !empty( $theName['value'] )) {
  3688. $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
  3689. $output .= $this->_createElement( 'TZNAME', $attributes, $this->_strrep( $theName['value'] ));
  3690. }
  3691. elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
  3692. }
  3693. return $output;
  3694. }
  3695. /**
  3696. * set calendar component property tzname
  3697. *
  3698. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3699. * @since 2.5.1 - 2008-11-05
  3700. * @param string $value
  3701. * @param string $params, optional
  3702. * @param integer $index, optional
  3703. * @return bool
  3704. */
  3705. function setTzname( $value, $params=FALSE, $index=FALSE ) {
  3706. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3707. $this->_setMval( $this->tzname, $value, $params, FALSE, $index );
  3708. return TRUE;
  3709. }
  3710. /*********************************************************************************/
  3711. /**
  3712. * Property Name: TZOFFSETFROM
  3713. */
  3714. /**
  3715. * creates formatted output for calendar component property tzoffsetfrom
  3716. *
  3717. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3718. * @since 2.4.8 - 2008-10-21
  3719. * @return string
  3720. */
  3721. function createTzoffsetfrom() {
  3722. if( empty( $this->tzoffsetfrom )) return FALSE;
  3723. if( empty( $this->tzoffsetfrom['value'] ))
  3724. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
  3725. $attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
  3726. return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
  3727. }
  3728. /**
  3729. * set calendar component property tzoffsetfrom
  3730. *
  3731. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3732. * @since 2.4.8 - 2008-11-04
  3733. * @param string $value
  3734. * @param string $params optional
  3735. * @return bool
  3736. */
  3737. function setTzoffsetfrom( $value, $params=FALSE ) {
  3738. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3739. $this->tzoffsetfrom = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3740. return TRUE;
  3741. }
  3742. /*********************************************************************************/
  3743. /**
  3744. * Property Name: TZOFFSETTO
  3745. */
  3746. /**
  3747. * creates formatted output for calendar component property tzoffsetto
  3748. *
  3749. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3750. * @since 2.4.8 - 2008-10-21
  3751. * @return string
  3752. */
  3753. function createTzoffsetto() {
  3754. if( empty( $this->tzoffsetto )) return FALSE;
  3755. if( empty( $this->tzoffsetto['value'] ))
  3756. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
  3757. $attributes = $this->_createParams( $this->tzoffsetto['params'] );
  3758. return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
  3759. }
  3760. /**
  3761. * set calendar component property tzoffsetto
  3762. *
  3763. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3764. * @since 2.4.8 - 2008-11-04
  3765. * @param string $value
  3766. * @param string $params optional
  3767. * @return bool
  3768. */
  3769. function setTzoffsetto( $value, $params=FALSE ) {
  3770. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3771. $this->tzoffsetto = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3772. return TRUE;
  3773. }
  3774. /*********************************************************************************/
  3775. /**
  3776. * Property Name: TZURL
  3777. */
  3778. /**
  3779. * creates formatted output for calendar component property tzurl
  3780. *
  3781. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3782. * @since 2.4.8 - 2008-10-21
  3783. * @return string
  3784. */
  3785. function createTzurl() {
  3786. if( empty( $this->tzurl )) return FALSE;
  3787. if( empty( $this->tzurl['value'] ))
  3788. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
  3789. $attributes = $this->_createParams( $this->tzurl['params'] );
  3790. return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
  3791. }
  3792. /**
  3793. * set calendar component property tzurl
  3794. *
  3795. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3796. * @since 2.4.8 - 2008-11-04
  3797. * @param string $value
  3798. * @param string $params optional
  3799. * @return boll
  3800. */
  3801. function setTzurl( $value, $params=FALSE ) {
  3802. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3803. $this->tzurl = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3804. return TRUE;
  3805. }
  3806. /*********************************************************************************/
  3807. /**
  3808. * Property Name: UID
  3809. */
  3810. /**
  3811. * creates formatted output for calendar component property uid
  3812. *
  3813. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3814. * @since 0.9.7 - 2006-11-20
  3815. * @return string
  3816. */
  3817. function createUid() {
  3818. if( 0 >= count( $this->uid ))
  3819. $this->_makeuid();
  3820. $attributes = $this->_createParams( $this->uid['params'] );
  3821. return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
  3822. }
  3823. /**
  3824. * create an unique id for this calendar component object instance
  3825. *
  3826. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3827. * @since 2.2.7 - 2007-09-04
  3828. * @return void
  3829. */
  3830. function _makeUid() {
  3831. $date = date('Ymd\THisT');
  3832. $unique = substr(microtime(), 2, 4);
  3833. $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
  3834. $start = 0;
  3835. $end = strlen( $base ) - 1;
  3836. $length = 6;
  3837. $str = null;
  3838. for( $p = 0; $p < $length; $p++ )
  3839. $unique .= $base{mt_rand( $start, $end )};
  3840. $this->uid = array( 'params' => null );
  3841. $this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
  3842. }
  3843. /**
  3844. * set calendar component property uid
  3845. *
  3846. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3847. * @since 2.4.8 - 2008-11-04
  3848. * @param string $value
  3849. * @param string $params optional
  3850. * @return bool
  3851. */
  3852. function setUid( $value, $params=FALSE ) {
  3853. if( empty( $value )) return FALSE; // no allowEmpty check here !!!!
  3854. $this->uid = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3855. return TRUE;
  3856. }
  3857. /*********************************************************************************/
  3858. /**
  3859. * Property Name: URL
  3860. */
  3861. /**
  3862. * creates formatted output for calendar component property url
  3863. *
  3864. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3865. * @since 2.4.8 - 2008-10-21
  3866. * @return string
  3867. */
  3868. function createUrl() {
  3869. if( empty( $this->url )) return FALSE;
  3870. if( empty( $this->url['value'] ))
  3871. return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
  3872. $attributes = $this->_createParams( $this->url['params'] );
  3873. return $this->_createElement( 'URL', $attributes, $this->url['value'] );
  3874. }
  3875. /**
  3876. * set calendar component property url
  3877. *
  3878. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3879. * @since 2.4.8 - 2008-11-04
  3880. * @param string $value
  3881. * @param string $params optional
  3882. * @return bool
  3883. */
  3884. function setUrl( $value, $params=FALSE ) {
  3885. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3886. $this->url = array( 'value' => $value, 'params' => $this->_setParams( $params ));
  3887. return TRUE;
  3888. }
  3889. /*********************************************************************************/
  3890. /**
  3891. * Property Name: x-prop
  3892. */
  3893. /**
  3894. * creates formatted output for calendar component property x-prop
  3895. *
  3896. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3897. * @since 2.4.11 - 2008-10-22
  3898. * @return string
  3899. */
  3900. function createXprop() {
  3901. if( empty( $this->xprop )) return FALSE;
  3902. $output = null;
  3903. foreach( $this->xprop as $label => $xpropPart ) {
  3904. if( empty( $xpropPart['value'] )) {
  3905. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label );
  3906. continue;
  3907. }
  3908. $attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
  3909. if( is_array( $xpropPart['value'] )) {
  3910. foreach( $xpropPart['value'] as $pix => $theXpart )
  3911. $xpropPart['value'][$pix] = $this->_strrep( $theXpart );
  3912. $xpropPart['value'] = implode( ',', $xpropPart['value'] );
  3913. }
  3914. else
  3915. $xpropPart['value'] = $this->_strrep( $xpropPart['value'] );
  3916. $output .= $this->_createElement( $label, $attributes, $xpropPart['value'] );
  3917. }
  3918. return $output;
  3919. }
  3920. /**
  3921. * set calendar component property x-prop
  3922. *
  3923. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3924. * @since 2.4.11 - 2008-11-04
  3925. * @param string $label
  3926. * @param mixed $value
  3927. * @param array $params optional
  3928. * @return bool
  3929. */
  3930. function setXprop( $label, $value, $params=FALSE ) {
  3931. if( empty( $label )) return;
  3932. if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
  3933. $xprop = array( 'value' => $value );
  3934. $toolbox = new calendarComponent();
  3935. $xprop['params'] = $toolbox->_setParams( $params );
  3936. if( !is_array( $this->xprop )) $this->xprop = array();
  3937. $this->xprop[strtoupper( $label )] = $xprop;
  3938. return TRUE;
  3939. }
  3940. /*********************************************************************************/
  3941. /*********************************************************************************/
  3942. /**
  3943. * create element format parts
  3944. *
  3945. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3946. * @since 2.0.6 - 2006-06-20
  3947. * @return string
  3948. */
  3949. function _createFormat() {
  3950. $objectname = null;
  3951. switch( $this->format ) {
  3952. case 'xcal':
  3953. $objectname = ( isset( $this->timezonetype )) ?
  3954. strtolower( $this->timezonetype ) : strtolower( $this->objName );
  3955. $this->componentStart1 = $this->elementStart1 = '<';
  3956. $this->componentStart2 = $this->elementStart2 = '>';
  3957. $this->componentEnd1 = $this->elementEnd1 = '</';
  3958. $this->componentEnd2 = $this->elementEnd2 = '>'.$this->nl;
  3959. $this->intAttrDelimiter = '<!-- -->';
  3960. $this->attributeDelimiter = $this->nl;
  3961. $this->valueInit = null;
  3962. break;
  3963. default:
  3964. $objectname = ( isset( $this->timezonetype )) ?
  3965. strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
  3966. $this->componentStart1 = 'BEGIN:';
  3967. $this->componentStart2 = null;
  3968. $this->componentEnd1 = 'END:';
  3969. $this->componentEnd2 = $this->nl;
  3970. $this->elementStart1 = null;
  3971. $this->elementStart2 = null;
  3972. $this->elementEnd1 = null;
  3973. $this->elementEnd2 = $this->nl;
  3974. $this->intAttrDelimiter = '<!-- -->';
  3975. $this->attributeDelimiter = ';';
  3976. $this->valueInit = ':';
  3977. break;
  3978. }
  3979. return $objectname;
  3980. }
  3981. /**
  3982. * creates formatted output for calendar component property
  3983. *
  3984. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  3985. * @since 2.4.8 - 2008-10-23
  3986. * @param string $label property name
  3987. * @param string $attributes property attributes
  3988. * @param string $content property content (optional)
  3989. * @return string
  3990. */
  3991. function _createElement( $label, $attributes=null, $content=FALSE ) {
  3992. $label = $this->_formatPropertyName( $label );
  3993. $output = $this->elementStart1.$label;
  3994. $categoriesAttrLang = null;
  3995. $attachInlineBinary = FALSE;
  3996. $attachfmttype = null;
  3997. if( !empty( $attributes )) {
  3998. $attributes = trim( $attributes );
  3999. if ( 'xcal' == $this->format) {
  4000. $attributes2 = explode( $this->intAttrDelimiter, $attributes );
  4001. $attributes = null;
  4002. foreach( $attributes2 as $attribute ) {
  4003. $attrKVarr = explode( '=', $attribute );
  4004. if( empty( $attrKVarr[0] ))
  4005. continue;
  4006. if( !isset( $attrKVarr[1] )) {
  4007. $attrValue = $attrKVarr[0];
  4008. $attrKey = null;
  4009. }
  4010. elseif( 2 == count( $attrKVarr)) {
  4011. $attrKey = strtolower( $attrKVarr[0] );
  4012. $attrValue = $attrKVarr[1];
  4013. }
  4014. else {
  4015. $attrKey = strtolower( $attrKVarr[0] );
  4016. unset( $attrKVarr[0] );
  4017. $attrValue = implode( '=', $attrKVarr );
  4018. }
  4019. if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) {
  4020. $attachInlineBinary = TRUE;
  4021. if( 'fmttype' == $attrKey )
  4022. $attachfmttype = $attrKey.'='.$attrValue;
  4023. continue;
  4024. }
  4025. elseif(( 'categories' == $label ) && ( 'language' == $attrKey ))
  4026. $categoriesAttrLang = $attrKey.'='.$attrValue;
  4027. else {
  4028. $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
  4029. $attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null;
  4030. if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) {
  4031. $attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 ));
  4032. $attrValue = str_replace( '"', '', $attrValue );
  4033. }
  4034. $attributes .= '"'.htmlspecialchars( $attrValue ).'"';
  4035. }
  4036. }
  4037. }
  4038. else {
  4039. $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
  4040. }
  4041. }
  4042. if(((( 'attach' == $label ) && !$attachInlineBinary ) ||
  4043. ( in_array( $label, array( 'tzurl', 'url' )))) && ( 'xcal' == $this->format)) {
  4044. $pos = strrpos($content, "/");
  4045. $docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content;
  4046. $this->xcaldecl[] = array( 'xmldecl' => 'ENTITY'
  4047. , 'uri' => $docname
  4048. , 'ref' => 'SYSTEM'
  4049. , 'external' => $content
  4050. , 'type' => 'NDATA'
  4051. , 'type2' => 'BINERY' );
  4052. $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
  4053. $attributes .= 'uri="'.$docname.'"';
  4054. $content = null;
  4055. if( 'attach' == $label ) {
  4056. $attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes );
  4057. $content = $this->_createElement( 'extref', $attributes, null );
  4058. $attributes = null;
  4059. }
  4060. }
  4061. elseif(( 'attach' == $label ) && $attachInlineBinary && ( 'xcal' == $this->format)) {
  4062. $content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute
  4063. }
  4064. $output .= $attributes;
  4065. if( !$content ) {
  4066. switch( $this->format ) {
  4067. case 'xcal':
  4068. $output .= ' /';
  4069. $output .= $this->elementStart2;
  4070. return $output;
  4071. break;
  4072. default:
  4073. $output .= $this->elementStart2.$this->valueInit;
  4074. return $this->_size75( $output );
  4075. break;
  4076. }
  4077. }
  4078. $output .= $this->elementStart2;
  4079. $output .= $this->valueInit.$content;
  4080. switch( $this->format ) {
  4081. case 'xcal':
  4082. return $output.$this->elementEnd1.$label.$this->elementEnd2;
  4083. break;
  4084. default:
  4085. return $this->_size75( $output );
  4086. break;
  4087. }
  4088. }
  4089. /**
  4090. * creates formatted output for calendar component property parameters
  4091. *
  4092. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4093. * @since 0.9.22 - 2007-04-10
  4094. * @param array $params optional
  4095. * @param array $ctrKeys optional
  4096. * @return string
  4097. */
  4098. function _createParams( $params=array(), $ctrKeys=array() ) {
  4099. $attrLANG = $attr1 = $attr2 = null;
  4100. $CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ;
  4101. $LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ;
  4102. $CNattrExist = $LANGattrExist = FALSE;
  4103. if( is_array( $params )) {
  4104. foreach( $params as $paramKey => $paramValue ) {
  4105. if( is_int( $paramKey ))
  4106. $attr2 .= $this->intAttrDelimiter.$paramValue;
  4107. elseif(( 'LANGUAGE' == $paramKey ) && $LANGattrKey ) {
  4108. $attrLANG .= $this->intAttrDelimiter."LANGUAGE=$paramValue";
  4109. $LANGattrExist = TRUE;
  4110. }
  4111. elseif(( 'CN' == $paramKey ) && $CNattrKey ) {
  4112. $attr1 = $this->intAttrDelimiter.'CN="'.$paramValue.'"';
  4113. $CNattrExist = TRUE;
  4114. }
  4115. elseif(( 'ALTREP' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
  4116. $attr2 .= $this->intAttrDelimiter.'ALTREP="'.$paramValue.'"';
  4117. elseif(( 'DIR' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
  4118. $attr2 .= $this->intAttrDelimiter.'DIR="'.$paramValue.'"';
  4119. elseif(( 'SENT-BY' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
  4120. $attr2 .= $this->intAttrDelimiter.'SENT-BY="MAILTO:'.$paramValue.'"';
  4121. else
  4122. $attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue";
  4123. }
  4124. }
  4125. if( !$LANGattrExist ) {
  4126. $lang = $this->getConfig( 'language' );
  4127. if(( $CNattrExist || $LANGattrKey ) && $lang )
  4128. $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang;
  4129. }
  4130. return $attrLANG.$attr1.$attr2;
  4131. }
  4132. /**
  4133. * check a date(-time) for an opt. timezone and if it is a DATE-TIME or DATE
  4134. *
  4135. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4136. * @since 2.4.16 - 2008-10-25
  4137. * @param array $date, date to check
  4138. * @param int $parno, no of date parts (i.e. year, month.. .)
  4139. * @return array $params, property parameters
  4140. */
  4141. function _chkdatecfg( $theDate, & $parno, & $params ) {
  4142. if( isset( $params['TZID'] ))
  4143. $parno = 6;
  4144. elseif( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] ))
  4145. $parno = 3;
  4146. else {
  4147. if( isset( $params['VALUE'] ) && ( 'PERIOD' == $params['VALUE'] ))
  4148. $parno = 7;
  4149. if( is_array( $theDate )) {
  4150. if( isset( $theDate['timestamp'] ))
  4151. $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : null;
  4152. else
  4153. $tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : ( 7 == count( $theDate )) ? end( $theDate ) : null;
  4154. if( !empty( $tzid )) {
  4155. $parno = 7;
  4156. if( !$this->_isOffset( $tzid ))
  4157. $params['TZID'] = $tzid; // save only timezone
  4158. }
  4159. elseif( !$parno && ( 3 == count( $theDate )) &&
  4160. ( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] )))
  4161. $parno = 3;
  4162. else
  4163. $parno = 6;
  4164. }
  4165. else { // string
  4166. $date = trim( $theDate );
  4167. if( 'Z' == substr( $date, -1 ))
  4168. $parno = 7; // UTC DATE-TIME
  4169. elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) &&
  4170. ( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' ))))
  4171. $parno = 3; // DATE
  4172. $date = $this->_date_time_string( $date, $parno );
  4173. if( !empty( $date['tz'] )) {
  4174. $parno = 7;
  4175. if( !$this->_isOffset( $date['tz'] ))
  4176. $params['TZID'] = $date['tz']; // save only timezone
  4177. }
  4178. elseif( empty( $parno ))
  4179. $parno = 6;
  4180. }
  4181. if( isset( $params['TZID'] ))
  4182. $parno = 6;
  4183. }
  4184. }
  4185. /**
  4186. * convert local startdate/enddate (Ymd[His]) to duration
  4187. *
  4188. * uses this component dates if missing input dates
  4189. *
  4190. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4191. * @since 2.2.11 - 2007-11-03
  4192. * @param array $startdate, optional
  4193. * @param array $duration, optional
  4194. * @return array duration
  4195. */
  4196. function _date2duration( $startdate=FALSE, $enddate=FALSE ) {
  4197. if( !$startdate || !$enddate ) {
  4198. if( FALSE === ( $startdate = $this->getProperty( 'dtstart' )))
  4199. return null;
  4200. if( FALSE === ( $enddate = $this->getProperty( 'dtend' ))) // vevent/vfreebusy
  4201. if( FALSE === ( $enddate = $this->getProperty( 'due' ))) // vtodo
  4202. return null;
  4203. }
  4204. if( !$startdate || !$enddate )
  4205. return null;
  4206. $startWdate = mktime( 0, 0, 0, $startdate['month'], $startdate['day'], $startdate['year'] );
  4207. $endWdate = mktime( 0, 0, 0, $enddate['month'], $enddate['day'], $enddate['year'] );
  4208. $wduration = $endWdate - $startWdate;
  4209. $dur = array();
  4210. $dur['week'] = (int) floor( $wduration / ( 7 * 24 * 60 * 60 ));
  4211. $wduration = $wduration % ( 7 * 24 * 60 * 60 );
  4212. $dur['day'] = (int) floor( $wduration / ( 24 * 60 * 60 ));
  4213. $wduration = $wduration % ( 24 * 60 * 60 );
  4214. $dur['hour'] = (int) floor( $wduration / ( 60 * 60 ));
  4215. $wduration = $wduration % ( 60 * 60 );
  4216. $dur['min'] = (int) floor( $wduration / ( 60 ));
  4217. $dur['sec'] = (int) $wduration % ( 60 );
  4218. return $dur;
  4219. }
  4220. /**
  4221. * convert date/datetime to timestamp
  4222. *
  4223. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4224. * @since 2.4.8 - 2008-10-30
  4225. * @param array $datetime datetime/(date)
  4226. * @param string $tz timezone
  4227. * @return timestamp
  4228. */
  4229. function _date2timestamp( $datetime, $tz=null ) {
  4230. $output = null;
  4231. if( !isset( $datetime['hour'] )) $datetime['hour'] = '0';
  4232. if( !isset( $datetime['min'] )) $datetime['min'] = '0';
  4233. if( !isset( $datetime['sec'] )) $datetime['sec'] = '0';
  4234. foreach( $datetime as $dkey => $dvalue ) {
  4235. if( 'tz' != $dkey )
  4236. $datetime[$dkey] = (integer) $dvalue;
  4237. }
  4238. if( $tz )
  4239. $datetime['tz'] = $tz;
  4240. $offset = ( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) ? $this->_tz2offset( $datetime['tz'] ) : 0;
  4241. $output = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year'] );
  4242. return $output;
  4243. }
  4244. /**
  4245. * ensures internal date-time/date format for input date-time/date in array format
  4246. *
  4247. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4248. * @since 0.3.0 - 2006-08-15
  4249. * @param array $datetime
  4250. * @param int $parno optional, default FALSE
  4251. * @return array
  4252. */
  4253. function _date_time_array( $datetime, $parno=FALSE ) {
  4254. $output = array();
  4255. foreach( $datetime as $dateKey => $datePart ) {
  4256. switch ( $dateKey ) {
  4257. case '0':
  4258. case 'year':
  4259. $output['year'] = $datePart;
  4260. break;
  4261. case '1':
  4262. case 'month':
  4263. $output['month'] = $datePart;
  4264. break;
  4265. case '2':
  4266. case 'day':
  4267. $output['day'] = $datePart;
  4268. break;
  4269. }
  4270. if( 3 != $parno ) {
  4271. switch ( $dateKey ) {
  4272. case '0':
  4273. case '1':
  4274. case '2':
  4275. break;
  4276. case '3':
  4277. case 'hour':
  4278. $output['hour'] = $datePart;
  4279. break;
  4280. case '4':
  4281. case 'min':
  4282. $output['min'] = $datePart;
  4283. break;
  4284. case '5':
  4285. case 'sec':
  4286. $output['sec'] = $datePart;
  4287. break;
  4288. case '6':
  4289. case 'tz':
  4290. $output['tz'] = $datePart;
  4291. break;
  4292. }
  4293. }
  4294. }
  4295. if( 3 != $parno ) {
  4296. if( !isset( $output['hour'] ))
  4297. $output['hour'] = 0;
  4298. if( !isset( $output['min'] ))
  4299. $output['min'] = 0;
  4300. if( !isset( $output['sec'] ))
  4301. $output['sec'] = 0;
  4302. }
  4303. return $output;
  4304. }
  4305. /**
  4306. * ensures internal date-time/date format for input date-time/date in string fromat
  4307. *
  4308. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4309. * @since 2.2.10 - 2007-10-19
  4310. * @param array $datetime
  4311. * @param int $parno optional, default FALSE
  4312. * @return array
  4313. */
  4314. function _date_time_string( $datetime, $parno=FALSE ) {
  4315. $datetime = (string) trim( $datetime );
  4316. $tz = null;
  4317. $len = strlen( $datetime ) - 1;
  4318. if( 'Z' == substr( $datetime, -1 )) {
  4319. $tz = 'Z';
  4320. $datetime = trim( substr( $datetime, 0, $len ));
  4321. }
  4322. elseif( ( ctype_digit( substr( $datetime, -2, 2 ))) && // time or date
  4323. ( '-' == substr( $datetime, -3, 1 )) ||
  4324. ( ':' == substr( $datetime, -3, 1 )) ||
  4325. ( '.' == substr( $datetime, -3, 1 ))) {
  4326. $continue = TRUE;
  4327. }
  4328. elseif( ( ctype_digit( substr( $datetime, -4, 4 ))) && // 4 pos offset
  4329. ( ' +' == substr( $datetime, -6, 2 )) ||
  4330. ( ' -' == substr( $datetime, -6, 2 ))) {
  4331. $tz = substr( $datetime, -5, 5 );
  4332. $datetime = substr( $datetime, 0, ($len - 5));
  4333. }
  4334. elseif( ( ctype_digit( substr( $datetime, -6, 6 ))) && // 6 pos offset
  4335. ( ' +' == substr( $datetime, -8, 2 )) ||
  4336. ( ' -' == substr( $datetime, -8, 2 ))) {
  4337. $tz = substr( $datetime, -7, 7 );
  4338. $datetime = substr( $datetime, 0, ($len - 7));
  4339. }
  4340. elseif( ( 6 < $len ) && ( ctype_digit( substr( $datetime, -6, 6 )))) {
  4341. $continue = TRUE;
  4342. }
  4343. elseif( 'T' == substr( $datetime, -7, 1 )) {
  4344. $continue = TRUE;
  4345. }
  4346. else {
  4347. $cx = $tx = 0; // 19970415T133000 US-Eastern
  4348. for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
  4349. if(( ' ' == substr( $datetime, $cx, 1 )) || ctype_digit( substr( $datetime, $cx, 1 )))
  4350. break; // if exists, tz ends here.. . ?
  4351. elseif( ctype_alpha( substr( $datetime, $cx, 1 )) ||
  4352. ( in_array( substr( $datetime, $cx, 1 ), array( '-', '/' ))))
  4353. $tx--; // tz length counter
  4354. }
  4355. if( 0 > $tx ) {
  4356. $tz = substr( $datetime, $tx );
  4357. $datetime = trim( substr( $datetime, 0, $len + $tx + 1 ));
  4358. }
  4359. }
  4360. if( 0 < substr_count( $datetime, '-' )) {
  4361. $datetime = str_replace( '-', '/', $datetime );
  4362. }
  4363. elseif( ctype_digit( substr( $datetime, 0, 8 )) &&
  4364. ( 'T' == substr( $datetime, 8, 1 )) &&
  4365. ctype_digit( substr( $datetime, 9, 6 ))) {
  4366. $datetime = substr( $datetime, 4, 2 )
  4367. .'/'.substr( $datetime, 6, 2 )
  4368. .'/'.substr( $datetime, 0, 4 )
  4369. .' '.substr( $datetime, 9, 2 )
  4370. .':'.substr( $datetime, 11, 2 )
  4371. .':'.substr( $datetime, 13);
  4372. }
  4373. $datestring = date( 'Y-m-d H:i:s', strtotime( $datetime ));
  4374. $tz = trim( $tz );
  4375. $output = array();
  4376. $output['year'] = substr( $datestring, 0, 4 );
  4377. $output['month'] = substr( $datestring, 5, 2 );
  4378. $output['day'] = substr( $datestring, 8, 2 );
  4379. if(( 6 == $parno ) || ( 7 == $parno )) {
  4380. $output['hour'] = substr( $datestring, 11, 2 );
  4381. $output['min'] = substr( $datestring, 14, 2 );
  4382. $output['sec'] = substr( $datestring, 17, 2 );
  4383. if( !empty( $tz ))
  4384. $output['tz'] = $tz;
  4385. }
  4386. elseif( 3 != $parno ) {
  4387. if(( '00' < substr( $datestring, 11, 2 )) ||
  4388. ( '00' < substr( $datestring, 14, 2 )) ||
  4389. ( '00' < substr( $datestring, 17, 2 ))) {
  4390. $output['hour'] = substr( $datestring, 11, 2 );
  4391. $output['min'] = substr( $datestring, 14, 2 );
  4392. $output['sec'] = substr( $datestring, 17, 2 );
  4393. }
  4394. if( !empty( $tz ))
  4395. $output['tz'] = $tz;
  4396. }
  4397. return $output;
  4398. }
  4399. /**
  4400. * ensures internal duration format for input in array format
  4401. *
  4402. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4403. * @since 2.1.1 - 2007-06-24
  4404. * @param array $duration
  4405. * @return array
  4406. */
  4407. function _duration_array( $duration ) {
  4408. $output = array();
  4409. if( is_array( $duration ) &&
  4410. ( 1 == count( $duration )) &&
  4411. isset( $duration['sec'] ) &&
  4412. ( 60 < $duration['sec'] )) {
  4413. $durseconds = $duration['sec'];
  4414. $output['week'] = floor( $durseconds / ( 60 * 60 * 24 * 7 ));
  4415. $durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
  4416. $output['day'] = floor( $durseconds / ( 60 * 60 * 24 ));
  4417. $durseconds = $durseconds % ( 60 * 60 * 24 );
  4418. $output['hour'] = floor( $durseconds / ( 60 * 60 ));
  4419. $durseconds = $durseconds % ( 60 * 60 );
  4420. $output['min'] = floor( $durseconds / ( 60 ));
  4421. $output['sec'] = ( $durseconds % ( 60 ));
  4422. }
  4423. else {
  4424. foreach( $duration as $durKey => $durValue ) {
  4425. if( empty( $durValue )) continue;
  4426. switch ( $durKey ) {
  4427. case '0':
  4428. case 'week':
  4429. $output['week'] = $durValue;
  4430. break;
  4431. case '1':
  4432. case 'day':
  4433. $output['day'] = $durValue;
  4434. break;
  4435. case '2':
  4436. case 'hour':
  4437. $output['hour'] = $durValue;
  4438. break;
  4439. case '3':
  4440. case 'min':
  4441. $output['min'] = $durValue;
  4442. break;
  4443. case '4':
  4444. case 'sec':
  4445. $output['sec'] = $durValue;
  4446. break;
  4447. }
  4448. }
  4449. }
  4450. if( isset( $output['week'] ) && ( 0 < $output['week'] )) {
  4451. unset( $output['day'], $output['hour'], $output['min'], $output['sec'] );
  4452. return $output;
  4453. }
  4454. unset( $output['week'] );
  4455. if( empty( $output['day'] ))
  4456. unset( $output['day'] );
  4457. if ( isset( $output['hour'] ) || isset( $output['min'] ) || isset( $output['sec'] )) {
  4458. if( !isset( $output['hour'] )) $output['hour'] = 0;
  4459. if( !isset( $output['min'] )) $output['min'] = 0;
  4460. if( !isset( $output['sec'] )) $output['sec'] = 0;
  4461. if(( 0 == $output['hour'] ) && ( 0 == $output['min'] ) && ( 0 == $output['sec'] ))
  4462. unset( $output['hour'], $output['min'], $output['sec'] );
  4463. }
  4464. return $output;
  4465. }
  4466. /**
  4467. * convert duration to date in array format based on input or dtstart value
  4468. *
  4469. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4470. * @since 2.4.8 - 2008-10-30
  4471. * @param array $startdate, optional
  4472. * @param array $duration, optional
  4473. * @return array, date format
  4474. */
  4475. function duration2date( $startdate=FALSE, $duration=FALSE ) {
  4476. if( $startdate && $duration ) {
  4477. $d1 = $startdate;
  4478. $dur = $duration;
  4479. }
  4480. elseif( isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) {
  4481. $d1 = $this->dtstart['value'];
  4482. $dur = $this->duration['value'];
  4483. }
  4484. else
  4485. return null;
  4486. $dateOnly = ( isset( $d1['hour'] ) || isset( $d1['min'] ) || isset( $d1['sec'] )) ? FALSE : TRUE;
  4487. $d1['hour'] = ( isset( $d1['hour'] )) ? $d1['hour'] : 0;
  4488. $d1['min'] = ( isset( $d1['min'] )) ? $d1['min'] : 0;
  4489. $d1['sec'] = ( isset( $d1['sec'] )) ? $d1['sec'] : 0;
  4490. $dtend = mktime( $d1['hour'], $d1['min'], $d1['sec'], $d1['month'], $d1['day'], $d1['year'] );
  4491. if( isset( $dur['week'] ))
  4492. $dtend += ( $dur['week'] * 7 * 24 * 60 * 60 );
  4493. if( isset( $dur['day'] ))
  4494. $dtend += ( $dur['day'] * 24 * 60 * 60 );
  4495. if( isset( $dur['hour'] ))
  4496. $dtend += ( $dur['hour'] * 60 *60 );
  4497. if( isset( $dur['min'] ))
  4498. $dtend += ( $dur['min'] * 60 );
  4499. if( isset( $dur['sec'] ))
  4500. $dtend += $dur['sec'];
  4501. $dtend2 = array();
  4502. $dtend2['year'] = date('Y', $dtend );
  4503. $dtend2['month'] = date('m', $dtend );
  4504. $dtend2['day'] = date('d', $dtend );
  4505. $dtend2['hour'] = date('H', $dtend );
  4506. $dtend2['min'] = date('i', $dtend );
  4507. $dtend2['sec'] = date('s', $dtend );
  4508. if( isset( $d1['tz'] ))
  4509. $dtend2['tz'] = $d1['tz'];
  4510. if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
  4511. unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
  4512. return $dtend2;
  4513. }
  4514. /**
  4515. * ensures internal duration format for input in string format
  4516. *
  4517. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4518. * @since 2.0.5 - 2007-03-14
  4519. * @param string $duration
  4520. * @return array
  4521. */
  4522. function _duration_string( $duration ) {
  4523. $duration = (string) trim( $duration );
  4524. while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
  4525. if( 0 < strlen( $duration ))
  4526. $duration = substr( $duration, 1 );
  4527. else
  4528. return false; // no leading P !?!?
  4529. }
  4530. $duration = substr( $duration, 1 ); // skip P
  4531. $duration = str_replace ( 't', 'T', $duration );
  4532. $duration = str_replace ( 'T', '', $duration );
  4533. $output = array();
  4534. $val = null;
  4535. for( $ix=0; $ix < strlen( $duration ); $ix++ ) {
  4536. switch( strtoupper( $duration{$ix} )) {
  4537. case 'W':
  4538. $output['week'] = $val;
  4539. $val = null;
  4540. break;
  4541. case 'D':
  4542. $output['day'] = $val;
  4543. $val = null;
  4544. break;
  4545. case 'H':
  4546. $output['hour'] = $val;
  4547. $val = null;
  4548. break;
  4549. case 'M':
  4550. $output['min'] = $val;
  4551. $val = null;
  4552. break;
  4553. case 'S':
  4554. $output['sec'] = $val;
  4555. $val = null;
  4556. break;
  4557. default:
  4558. if( !ctype_digit( $duration{$ix} ))
  4559. return false; // unknown duration controll character !?!?
  4560. else
  4561. $val .= $duration{$ix};
  4562. }
  4563. }
  4564. return $this->_duration_array( $output );
  4565. }
  4566. /**
  4567. * if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue
  4568. *
  4569. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4570. * @since 2.4.16 - 2008-11-08
  4571. * @param array $array
  4572. * @param string $expkey, expected key
  4573. * @param string $expval, expected value
  4574. * @param int $hitVal optional, return value if found
  4575. * @param int $elseVal optional, return value if not found
  4576. * @param int $preSet optional, return value if already preset
  4577. * @return int
  4578. */
  4579. function _existRem( &$array, $expkey, $expval=FALSE, $hitVal=null, $elseVal=null, $preSet=null ) {
  4580. if( $preSet )
  4581. return $preSet;
  4582. if( !is_array( $array ) || ( 0 == count( $array )))
  4583. return $elseVal;
  4584. foreach( $array as $key => $value ) {
  4585. if( strtoupper( $expkey ) == strtoupper( $key )) {
  4586. if( !$expval || ( strtoupper( $expval ) == strtoupper( $array[$key] ))) {
  4587. unset( $array[$key] );
  4588. return $hitVal;
  4589. }
  4590. }
  4591. }
  4592. return $elseVal;
  4593. }
  4594. /**
  4595. * creates formatted output for calendar component property data value type date/date-time
  4596. *
  4597. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4598. * @since 2.4.8 - 2008-10-30
  4599. * @param array $datetime
  4600. * @param int $parno, optional, default 6
  4601. * @return string
  4602. */
  4603. function _format_date_time( $datetime, $parno=6 ) {
  4604. if( !isset( $datetime['year'] ) &&
  4605. !isset( $datetime['month'] ) &&
  4606. !isset( $datetime['day'] ) &&
  4607. !isset( $datetime['hour'] ) &&
  4608. !isset( $datetime['min'] ) &&
  4609. !isset( $datetime['sec'] ))
  4610. return ;
  4611. $output = null;
  4612. // 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"; }
  4613. foreach( $datetime as $dkey => $dvalue ) {
  4614. if( 'tz' != $dkey )
  4615. $datetime[$dkey] = (integer) $dvalue;
  4616. }
  4617. $output = date('Ymd', mktime( 0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year']));
  4618. if( isset( $datetime['hour'] ) ||
  4619. isset( $datetime['min'] ) ||
  4620. isset( $datetime['sec'] ) ||
  4621. isset( $datetime['tz'] )) {
  4622. if( isset( $datetime['tz'] ) &&
  4623. !isset( $datetime['hour'] ))
  4624. $datetime['hour'] = 0;
  4625. if( isset( $datetime['hour'] ) &&
  4626. !isset( $datetime['min'] ))
  4627. $datetime['min'] = 0;
  4628. if( isset( $datetime['hour'] ) &&
  4629. isset( $datetime['min'] ) &&
  4630. !isset( $datetime['sec'] ))
  4631. $datetime['sec'] = 0;
  4632. $date = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']);
  4633. $output .= date('\THis', $date );
  4634. if( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) {
  4635. $datetime['tz'] = trim( $datetime['tz'] );
  4636. if( 'Z' == $datetime['tz'] )
  4637. $output .= 'Z';
  4638. $offset = $this->_tz2offset( $datetime['tz'] );
  4639. if( 0 != $offset ) {
  4640. $date = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']);
  4641. $output = date( 'Ymd\THis\Z', $date );
  4642. }
  4643. }
  4644. elseif( 7 == $parno )
  4645. $output .= 'Z';
  4646. }
  4647. return $output;
  4648. }
  4649. /**
  4650. * creates formatted output for calendar component property data value type duration
  4651. *
  4652. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4653. * @since 2.4.16 - 2008-10-10
  4654. * @param array $duration ( week, day, hour, min, sec )
  4655. * @return string
  4656. */
  4657. function _format_duration( $duration ) {
  4658. if( !isset( $duration['week'] ) &&
  4659. !isset( $duration['day'] ) &&
  4660. !isset( $duration['hour'] ) &&
  4661. !isset( $duration['min'] ) &&
  4662. !isset( $duration['sec'] ))
  4663. return;
  4664. $output = 'P';
  4665. if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
  4666. $output .= $duration['week'].'W';
  4667. else {
  4668. if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
  4669. $output .= $duration['day'].'D';
  4670. if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
  4671. ( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
  4672. ( isset( $duration['sec']) && ( 0 < $duration['sec'] ))) {
  4673. $output .= 'T';
  4674. $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '0H';
  4675. $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '0M';
  4676. $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '0S';
  4677. }
  4678. }
  4679. return $output;
  4680. }
  4681. /**
  4682. * creates formatted output for calendar component property data value type recur
  4683. *
  4684. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4685. * @since 2.4.8 - 2008-10-22
  4686. * @param array $recurlabel
  4687. * @param array $recurdata
  4688. * @return string
  4689. */
  4690. function _format_recur( $recurlabel, $recurdata ) {
  4691. $output = null;
  4692. foreach( $recurdata as $therule ) {
  4693. if( empty( $therule['value'] )) {
  4694. if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel );
  4695. continue;
  4696. }
  4697. $attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null;
  4698. $content1 = $content2 = null;
  4699. foreach( $therule['value'] as $rulelabel => $rulevalue ) {
  4700. switch( $rulelabel ) {
  4701. case 'FREQ':
  4702. $content1 .= "FREQ=$rulevalue";
  4703. break;
  4704. case 'UNTIL':
  4705. $content2 .= ";UNTIL=";
  4706. $content2 .= $this->_format_date_time( $rulevalue );
  4707. break;
  4708. case 'COUNT':
  4709. case 'INTERVAL':
  4710. case 'WKST':
  4711. $content2 .= ";$rulelabel=$rulevalue";
  4712. break;
  4713. case 'BYSECOND':
  4714. case 'BYMINUTE':
  4715. case 'BYHOUR':
  4716. case 'BYMONTHDAY':
  4717. case 'BYYEARDAY':
  4718. case 'BYWEEKNO':
  4719. case 'BYMONTH':
  4720. case 'BYSETPOS':
  4721. $content2 .= ";$rulelabel=";
  4722. if (is_array( $rulevalue )) {
  4723. foreach( $rulevalue as $vix => $valuePart ) {
  4724. $content2 .= ( $vix ) ? ',' : null;
  4725. $content2 .= $valuePart;
  4726. }
  4727. } else {
  4728. $content2 .= $rulevalue;
  4729. }
  4730. break;
  4731. case 'BYDAY':
  4732. $content2 .= ";$rulelabel=";
  4733. $bydaycnt = 0;
  4734. foreach( $rulevalue as $vix => $valuePart ) {
  4735. $content21 = $content22 = null;
  4736. if( is_array( $valuePart )) {
  4737. $content2 .= ( $bydaycnt ) ? ',' : null;
  4738. foreach( $valuePart as $vix2 => $valuePart2 ) {
  4739. if( 'DAY' != strtoupper( $vix2 ))
  4740. $content21 .= $valuePart2;
  4741. else
  4742. $content22 .= $valuePart2;
  4743. }
  4744. $content2 .= $content21.$content22;
  4745. $bydaycnt++;
  4746. }
  4747. else {
  4748. $content2 .= ( $bydaycnt ) ? ',' : null;
  4749. if( 'DAY' != strtoupper( $vix ))
  4750. $content21 .= $valuePart;
  4751. else {
  4752. $content22 .= $valuePart;
  4753. $bydaycnt++;
  4754. }
  4755. $content2 .= $content21.$content22;
  4756. }
  4757. }
  4758. break;
  4759. default:
  4760. $content2 .= ";$rulelabel=$rulevalue";
  4761. break;
  4762. }
  4763. }
  4764. $output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 );
  4765. }
  4766. return $output;
  4767. }
  4768. /**
  4769. * create property name case - lower/upper
  4770. *
  4771. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4772. * @since 0.9.7 - 2006-11-20
  4773. * @param string $propertyName
  4774. * @return string
  4775. */
  4776. function _formatPropertyName( $propertyName ) {
  4777. switch( $this->format ) {
  4778. case 'xcal':
  4779. return strtolower( $propertyName );
  4780. break;
  4781. default:
  4782. return strtoupper( $propertyName );
  4783. break;
  4784. }
  4785. }
  4786. /**
  4787. * checks if input array contains a date
  4788. *
  4789. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4790. * @since 2.4.16 - 2008-10-25
  4791. * @param array $input
  4792. * @return bool
  4793. */
  4794. function _isArrayDate( $input ) {
  4795. if( isset( $input['week'] ) || ( !in_array( count( $input ), array( 3, 6, 7 ))))
  4796. return FALSE;
  4797. if( 7 == count( $input ))
  4798. return TRUE;
  4799. if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
  4800. return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
  4801. if( isset( $input['day'] ) || isset( $input['hour'] ) || isset( $input['min'] ) || isset( $input['sec'] ))
  4802. return FALSE;
  4803. if( in_array( 0, $input ))
  4804. return FALSE;
  4805. if(( 1970 > $input[0] ) || ( 12 < $input[1] ) || ( 31 < $input[2] ))
  4806. return FALSE;
  4807. if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
  4808. checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
  4809. return TRUE;
  4810. $input = $this->_date_time_string( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
  4811. if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
  4812. return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
  4813. return FALSE;
  4814. }
  4815. /**
  4816. * checks if input array contains a timestamp date
  4817. *
  4818. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4819. * @since 2.4.16 - 2008-10-18
  4820. * @param array $input
  4821. * @return bool
  4822. */
  4823. function _isArrayTimestampDate( $input ) {
  4824. return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
  4825. }
  4826. /**
  4827. * controll if input string contains traling UTC offset
  4828. *
  4829. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4830. * @since 2.4.16 - 2008-10-19
  4831. * @param string $input
  4832. * @return bool
  4833. */
  4834. function _isOffset( $input ) {
  4835. $input = trim( (string) $input );
  4836. if( 'Z' == substr( $input, -1 ))
  4837. return TRUE;
  4838. elseif(( 5 <= strlen( $input )) &&
  4839. ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
  4840. ( '0000' < substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
  4841. return TRUE;
  4842. elseif(( 7 <= strlen( $input )) &&
  4843. ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
  4844. ( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
  4845. return TRUE;
  4846. return FALSE;
  4847. }
  4848. /**
  4849. * check if property not exists within component
  4850. *
  4851. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4852. * @since 2.5.1 - 2008-10-15
  4853. * @param string $propName
  4854. * @return bool
  4855. */
  4856. function _notExistProp( $propName ) {
  4857. if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
  4858. $propName = strtolower( $propName );
  4859. if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; }
  4860. elseif( 'percent-complete' == $propName ) { if( !isset( $this->percentcomplete )) return TRUE; }
  4861. elseif( 'recurrence-id' == $propName ) { if( !isset( $this->recurrenceid )) return TRUE; }
  4862. elseif( 'related-to' == $propName ) { if( !isset( $this->relatedto )) return TRUE; }
  4863. elseif( 'request-status' == $propName ) { if( !isset( $this->requeststatus )) return TRUE; }
  4864. elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE;
  4865. return FALSE;
  4866. }
  4867. /**
  4868. * remakes a recur pattern to an array of dates
  4869. *
  4870. * if missing, UNTIL is set 1 year from startdate (emergency break)
  4871. *
  4872. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  4873. * @since 2.4.16 - 2008-10-18
  4874. * @param array $result, array to update, array([timestamp] => timestamp)
  4875. * @param array $recur, pattern for recurrency (only value part, params ignored)
  4876. * @param array $wdate, component start date
  4877. * @param array $startdate, start date
  4878. * @param array $enddate, optional
  4879. * @return array of recurrence (start-)dates as index
  4880. * @todo BYHOUR, BYMINUTE, BYSECOND, ev. BYSETPOS due to ambiguity, WEEKLY at year end/start
  4881. */
  4882. function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) {
  4883. foreach( $wdate as $k => $v ) if( ctype_digit( $v )) $wdate[$k] = (int) $v;
  4884. $wdatets = $this->_date2timestamp( $wdate );
  4885. $startdatets = $this->_date2timestamp( $startdate );
  4886. if( !$enddate ) {
  4887. $enddate = $startdate;
  4888. $enddate['year'] += 1;
  4889. // echo "recur __in_ ".implode('-',$startdate)." period start ".implode('-',$wdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test###
  4890. }
  4891. $endDatets = $this->_date2timestamp( $enddate ); // fix break
  4892. if( !isset( $recur['COUNT'] ) && !isset( $recur['UNTIL'] ))
  4893. $recur['UNTIL'] = $enddate; // create break
  4894. if( isset( $recur['UNTIL'] )) {
  4895. $tdatets = $this->_date2timestamp( $recur['UNTIL'] );
  4896. if( $endDatets > $tdatets ) {
  4897. $endDatets = $tdatets; // emergency break
  4898. $enddate = $this->_timestamp2date( $endDatets, 6 );
  4899. }
  4900. else
  4901. $recur['UNTIL'] = $this->_timestamp2date( $endDatets, 6 );
  4902. }
  4903. if( $wdatets > $endDatets ) {
  4904. //echo "recur out of date ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
  4905. return array(); // nothing to do.. .
  4906. }
  4907. if( !isset( $recur['FREQ'] )) // "MUST be specified.. ."
  4908. $recur['FREQ'] = 'DAILY'; // ??
  4909. $wkst = ( isset( $recur['WKST'] ) && ( 'SU' == $recur['WKST'] )) ? 24*60*60 : 0; // ??
  4910. if( !isset( $recur['INTERVAL'] ))
  4911. $recur['INTERVAL'] = 1;
  4912. $countcnt = ( !isset( $recur['BYSETPOS'] )) ? 1 : 0; // DTSTART counts as the first occurrence
  4913. /* find out how to step up dates and set index for interval count */
  4914. $step = array();
  4915. if( 'YEARLY' == $recur['FREQ'] )
  4916. $step['year'] = 1;
  4917. elseif( 'MONTHLY' == $recur['FREQ'] )
  4918. $step['month'] = 1;
  4919. elseif( 'WEEKLY' == $recur['FREQ'] )
  4920. $step['day'] = 7;
  4921. else
  4922. $step['day'] = 1;
  4923. if( isset( $step['year'] ) && isset( $recur['BYMONTH'] ))
  4924. $step = array( 'month' => 1 );
  4925. if( empty( $step ) && isset( $recur['BYWEEKNO'] )) // ??
  4926. $step = array( 'day' => 7 );
  4927. if( isset( $recur['BYYEARDAY'] ) || isset( $recur['BYMONTHDAY'] ) || isset( $recur['BYDAY'] ))
  4928. $step = array( 'day' => 1 );
  4929. $intervalarr = array();
  4930. if( 1 < $recur['INTERVAL'] ) {
  4931. $intervalix = $this->_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
  4932. $intervalarr = array( $intervalix => 0 );
  4933. }
  4934. if( isset( $recur['BYSETPOS'] )) { // save start date + weekno
  4935. $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array();
  4936. $bysetposWold = (int) date( 'W', ( $wdatets + $wkst ));
  4937. $bysetposYold = $wdate['year'];
  4938. $bysetposMold = $wdate['month'];
  4939. $bysetposDold = $wdate['day'];
  4940. if( is_array( $recur['BYSETPOS'] )) {
  4941. foreach( $recur['BYSETPOS'] as $bix => $bval )
  4942. $recur['BYSETPOS'][$bix] = (int) $bval;
  4943. }
  4944. else
  4945. $recur['BYSETPOS'] = array( (int) $recur['BYSETPOS'] );
  4946. $this->_stepdate( $enddate, $endDatets, $step); // make sure to count whole last period
  4947. }
  4948. $this->_stepdate( $wdate, $wdatets, $step);
  4949. $year_old = null;
  4950. $daynames = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' );
  4951. /* MAIN LOOP */
  4952. // echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test
  4953. while( TRUE ) {
  4954. if( isset( $endDatets ) && ( $wdatets > $endDatets ))
  4955. break;
  4956. if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
  4957. break;
  4958. if( $year_old != $wdate['year'] ) {
  4959. $year_old = $wdate['year'];
  4960. $daycnts = array();
  4961. $yeardays = $weekno = 0;
  4962. $yeardaycnt = array();
  4963. for( $m = 1; $m <= 12; $m++ ) { // count up and update up-counters
  4964. $daycnts[$m] = array();
  4965. $weekdaycnt = array();
  4966. foreach( $daynames as $dn )
  4967. $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
  4968. $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
  4969. for( $d = 1; $d <= $mcnt; $d++ ) {
  4970. $daycnts[$m][$d] = array();
  4971. if( isset( $recur['BYYEARDAY'] )) {
  4972. $yeardays++;
  4973. $daycnts[$m][$d]['yearcnt_up'] = $yeardays;
  4974. }
  4975. if( isset( $recur['BYDAY'] )) {
  4976. $day = date( 'w', mktime( 0, 0, 0, $m, $d, $wdate['year'] ));
  4977. $day = $daynames[$day];
  4978. $daycnts[$m][$d]['DAY'] = $day;
  4979. $weekdaycnt[$day]++;
  4980. $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day];
  4981. $yeardaycnt[$day]++;
  4982. $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day];
  4983. }
  4984. if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
  4985. $daycnts[$m][$d]['weekno_up'] =(int)date('W',mktime(0,0,$wkst,$m,$d,$wdate['year']));
  4986. }
  4987. }
  4988. $daycnt = 0;
  4989. $yeardaycnt = array();
  4990. if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) {
  4991. $weekno = null;
  4992. for( $d=31; $d > 25; $d-- ) { // get last weekno for year
  4993. if( !$weekno )
  4994. $weekno = $daycnts[12][$d]['weekno_up'];
  4995. elseif( $weekno < $daycnts[12][$d]['weekno_up'] ) {
  4996. $weekno = $daycnts[12][$d]['weekno_up'];
  4997. break;
  4998. }
  4999. }
  5000. }
  5001. for( $m = 12; $m > 0; $m-- ) { // count down and update down-counters
  5002. $weekdaycnt = array();
  5003. foreach( $daynames as $dn )
  5004. $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
  5005. $monthcnt = 0;
  5006. $mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
  5007. for( $d = $mcnt; $d > 0; $d-- ) {
  5008. if( isset( $recur['BYYEARDAY'] )) {
  5009. $daycnt -= 1;
  5010. $daycnts[$m][$d]['yearcnt_down'] = $daycnt;
  5011. }
  5012. if( isset( $recur['BYMONTHDAY'] )) {
  5013. $monthcnt -= 1;
  5014. $daycnts[$m][$d]['monthcnt_down'] = $monthcnt;
  5015. }
  5016. if( isset( $recur['BYDAY'] )) {
  5017. $day = $daycnts[$m][$d]['DAY'];
  5018. $weekdaycnt[$day] -= 1;
  5019. $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day];
  5020. $yeardaycnt[$day] -= 1;
  5021. $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day];
  5022. }
  5023. if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
  5024. $daycnts[$m][$d]['weekno_down'] = ($daycnts[$m][$d]['weekno_up'] - $weekno - 1);
  5025. }
  5026. }
  5027. }
  5028. /* check interval */
  5029. if( 1 < $recur['INTERVAL'] ) {
  5030. /* create interval index */
  5031. $intervalix = $this->_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
  5032. /* check interval */
  5033. $currentKey = array_keys( $intervalarr );
  5034. $currentKey = end( $currentKey ); // get last index
  5035. if( $currentKey != $intervalix )
  5036. $intervalarr = array( $intervalix => ( $intervalarr[$currentKey] + 1 ));
  5037. if(( $recur['INTERVAL'] != $intervalarr[$intervalix] ) &&
  5038. ( 0 != $intervalarr[$intervalix] )) {
  5039. /* step up date */
  5040. //echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
  5041. $this->_stepdate( $wdate, $wdatets, $step);
  5042. continue;
  5043. }
  5044. else // continue within the selected interval
  5045. $intervalarr[$intervalix] = 0;
  5046. //echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
  5047. }
  5048. $updateOK = TRUE;
  5049. if( $updateOK && isset( $recur['BYMONTH'] ))
  5050. $updateOK = $this->_recurBYcntcheck( $recur['BYMONTH']
  5051. , $wdate['month']
  5052. ,($wdate['month'] - 13));
  5053. if( $updateOK && isset( $recur['BYWEEKNO'] ))
  5054. $updateOK = $this->_recurBYcntcheck( $recur['BYWEEKNO']
  5055. , $daycnts[$wdate['month']][$wdate['day']]['weekno_up']
  5056. , $daycnts[$wdate['month']][$wdate['day']]['weekno_down'] );
  5057. if( $updateOK && isset( $recur['BYYEARDAY'] ))
  5058. $updateOK = $this->_recurBYcntcheck( $recur['BYYEARDAY']
  5059. , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up']
  5060. , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down'] );
  5061. if( $updateOK && isset( $recur['BYMONTHDAY'] ))
  5062. $updateOK = $this->_recurBYcntcheck( $recur['BYMONTHDAY']
  5063. , $wdate['day']
  5064. , $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down'] );
  5065. //echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test###
  5066. if( $updateOK && isset( $recur['BYDAY'] )) {
  5067. $updateOK = FALSE;
  5068. $m = $wdate['month'];
  5069. $d = $wdate['day'];
  5070. if( isset( $recur['BYDAY']['DAY'] )) { // single day, opt with year/month day order no
  5071. $daynoexists = $daynosw = $daynamesw = FALSE;
  5072. if( $recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY'] )
  5073. $daynamesw = TRUE;
  5074. if( isset( $recur['BYDAY'][0] )) {
  5075. $daynoexists = TRUE;
  5076. if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) || isset( $recur['BYMONTH'] ))
  5077. $daynosw = $this->_recurBYcntcheck( $recur['BYDAY'][0]
  5078. , $daycnts[$m][$d]['monthdayno_up']
  5079. , $daycnts[$m][$d]['monthdayno_down'] );
  5080. elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
  5081. $daynosw = $this->_recurBYcntcheck( $recur['BYDAY'][0]
  5082. , $daycnts[$m][$d]['yeardayno_up']
  5083. , $daycnts[$m][$d]['yeardayno_down'] );
  5084. }
  5085. if(( $daynoexists && $daynosw && $daynamesw ) ||
  5086. ( !$daynoexists && !$daynosw && $daynamesw )) {
  5087. $updateOK = TRUE;
  5088. }
  5089. //echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
  5090. }
  5091. else {
  5092. foreach( $recur['BYDAY'] as $bydayvalue ) {
  5093. $daynoexists = $daynosw = $daynamesw = FALSE;
  5094. if( isset( $bydayvalue['DAY'] ) &&
  5095. ( $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY'] ))
  5096. $daynamesw = TRUE;
  5097. if( isset( $bydayvalue[0] )) {
  5098. $daynoexists = TRUE;
  5099. if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) ||
  5100. isset( $recur['BYMONTH'] ))
  5101. $daynosw = $this->_recurBYcntcheck( $bydayvalue['0']
  5102. , $daycnts[$m][$d]['monthdayno_up']
  5103. , $daycnts[$m][$d]['monthdayno_down'] );
  5104. elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
  5105. $daynosw = $this->_recurBYcntcheck( $bydayvalue['0']
  5106. , $daycnts[$m][$d]['yeardayno_up']
  5107. , $daycnts[$m][$d]['yeardayno_down'] );
  5108. }
  5109. //echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
  5110. if(( $daynoexists && $daynosw && $daynamesw ) ||
  5111. ( !$daynoexists && !$daynosw && $daynamesw )) {
  5112. $updateOK = TRUE;
  5113. break;
  5114. }
  5115. }
  5116. }
  5117. }
  5118. //echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ###
  5119. /* check BYSETPOS */
  5120. if( $updateOK ) {
  5121. if( isset( $recur['BYSETPOS'] ) &&
  5122. ( in_array( $recur['FREQ'], array( 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY' )))) {
  5123. if( isset( $recur['WEEKLY'] )) {
  5124. if( $bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] )
  5125. $bysetposw1[] = $wdatets;
  5126. else
  5127. $bysetposw2[] = $wdatets;
  5128. }
  5129. else {
  5130. if(( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
  5131. ( $bysetposYold == $wdate['year'] )) ||
  5132. ( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) &&
  5133. (( $bysetposYold == $wdate['year'] ) &&
  5134. ( $bysetposMold == $wdate['month'] ))) ||
  5135. ( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) &&
  5136. (( $bysetposYold == $wdate['year'] ) &&
  5137. ( $bysetposMold == $wdate['month']) &&
  5138. ( $bysetposDold == $wdate['sday'] ))))
  5139. $bysetposymd1[] = $wdatets;
  5140. else
  5141. $bysetposymd2[] = $wdatets;
  5142. }
  5143. }
  5144. else {
  5145. /* update result array if BYSETPOS is set */
  5146. $countcnt++;
  5147. if( $startdatets <= $wdatets ) { // only output within period
  5148. $result[$wdatets] = TRUE;
  5149. //echo "recur ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
  5150. }
  5151. //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
  5152. $updateOK = FALSE;
  5153. }
  5154. }
  5155. /* step up date */
  5156. $this->_stepdate( $wdate, $wdatets, $step);
  5157. /* check if BYSETPOS is set for updating result array */
  5158. if( $updateOK && isset( $recur['BYSETPOS'] )) {
  5159. $bysetpos = FALSE;
  5160. if( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
  5161. ( $bysetposYold != $wdate['year'] )) {
  5162. $bysetpos = TRUE;
  5163. $bysetposYold = $wdate['year'];
  5164. }
  5165. elseif( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] &&
  5166. (( $bysetposYold != $wdate['year'] ) || ( $bysetposMold != $wdate['month'] )))) {
  5167. $bysetpos = TRUE;
  5168. $bysetposYold = $wdate['year'];
  5169. $bysetposMold = $wdate['month'];
  5170. }
  5171. elseif( isset( $recur['FREQ'] ) && ( 'WEEKLY' == $recur['FREQ'] )) {
  5172. $weekno = (int) date( 'W', mktime( 0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year']));
  5173. if( $bysetposWold != $weekno ) {
  5174. $bysetposWold = $weekno;
  5175. $bysetpos = TRUE;
  5176. }
  5177. }
  5178. elseif( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) &&
  5179. (( $bysetposYold != $wdate['year'] ) ||
  5180. ( $bysetposMold != $wdate['month'] ) ||
  5181. ( $bysetposDold != $wdate['sday'] ))) {
  5182. $bysetpos = TRUE;
  5183. $bysetposYold = $wdate['year'];
  5184. $bysetposMold = $wdate['month'];
  5185. $bysetposDold = $wdate['day'];
  5186. }
  5187. if( $bysetpos ) {
  5188. if( isset( $recur['BYWEEKNO'] )) {
  5189. $bysetposarr1 = & $bysetposw1;
  5190. $bysetposarr2 = & $bysetposw2;
  5191. }
  5192. else {
  5193. $bysetposarr1 = & $bysetposymd1;
  5194. $bysetposarr2 = & $bysetposymd2;
  5195. }
  5196. foreach( $recur['BYSETPOS'] as $ix ) {
  5197. if( 0 > $ix ) // both positive and negative BYSETPOS allowed
  5198. $ix = ( count( $bysetposarr1 ) + $ix + 1);
  5199. $ix--;
  5200. if( isset( $bysetposarr1[$ix] )) {
  5201. if( $startdatets <= $bysetposarr1[$ix] ) { // only output within period
  5202. $result[$bysetposarr1[$ix]] = TRUE;
  5203. //echo "recur ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$bysetposarr1[$ix]),6))."<br />\n";//test
  5204. }
  5205. $countcnt++;
  5206. }
  5207. if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
  5208. break;
  5209. }
  5210. $bysetposarr1 = $bysetposarr2;
  5211. $bysetposarr2 = array();
  5212. }
  5213. }
  5214. }
  5215. }
  5216. function _recurBYcntcheck( $BYvalue, $upValue, $downValue ) {
  5217. if( is_array( $BYvalue ) &&
  5218. ( in_array( $upValue, $BYvalue ) || in_array( $downValue, $BYvalue )))
  5219. return TRUE;
  5220. elseif(( $BYvalue == $upValue ) || ( $BYvalue == $downValue ))
  5221. return TRUE;
  5222. else
  5223. return FALSE;
  5224. }
  5225. function _recurIntervalIx( $freq, $date, $wkst ) {
  5226. /* create interval index */
  5227. switch( $freq ) {
  5228. case 'YEARLY':
  5229. $intervalix = $date['year'];
  5230. break;
  5231. case 'MONTHLY':
  5232. $intervalix = $date['year'].'-'.$date['month'];
  5233. break;
  5234. case 'WEEKLY':
  5235. $wdatets = $this->_date2timestamp( $date );
  5236. $intervalix = (int) date( 'W', ( $wdatets + $wkst ));
  5237. break;
  5238. case 'DAILY':
  5239. default:
  5240. $intervalix = $date['year'].'-'.$date['month'].'-'.$date['day'];
  5241. break;
  5242. }
  5243. return $intervalix;
  5244. }
  5245. /**
  5246. * convert input format for exrule and rrule to internal format
  5247. *
  5248. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5249. * @since 2.4.16 - 2008-10-19
  5250. * @param array $rexrule
  5251. * @return array
  5252. */
  5253. function _setRexrule( $rexrule ) {
  5254. $input = array();
  5255. if( empty( $rexrule ))
  5256. return $input;
  5257. foreach( $rexrule as $rexrulelabel => $rexrulevalue ) {
  5258. $rexrulelabel = strtoupper( $rexrulelabel );
  5259. if( 'UNTIL' != $rexrulelabel )
  5260. $input[$rexrulelabel] = $rexrulevalue;
  5261. else {
  5262. if( $this->_isArrayTimestampDate( $rexrulevalue )) // timestamp date
  5263. $input[$rexrulelabel] = $this->_timestamp2date( $rexrulevalue, 6 );
  5264. elseif( $this->_isArrayDate( $rexrulevalue )) // date-time
  5265. $input[$rexrulelabel] = $this->_date_time_array( $rexrulevalue, 6 );
  5266. elseif( 8 <= strlen( trim( $rexrulevalue ))) // ex. 2006-08-03 10:12:18
  5267. $input[$rexrulelabel] = $this->_date_time_string( $rexrulevalue );
  5268. if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] ))
  5269. $input[$rexrulelabel]['tz'] = 'Z';
  5270. }
  5271. }
  5272. return $input;
  5273. }
  5274. /**
  5275. * convert format for input date to internal date with parameters
  5276. *
  5277. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5278. * @since 2.4.17 - 2008-10-31
  5279. * @param mixed $year
  5280. * @param mixed $month optional
  5281. * @param int $day optional
  5282. * @param int $hour optional
  5283. * @param int $min optional
  5284. * @param int $sec optional
  5285. * @param array $params optional
  5286. * @param string $caller optional
  5287. * @return array
  5288. */
  5289. function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null ) {
  5290. $input = $parno = null;
  5291. $localtime = (( 'dtstart' == $caller ) && in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
  5292. if( $this->_isArrayDate( $year )) {
  5293. if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
  5294. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
  5295. if( isset( $input['params']['TZID'] )) {
  5296. $input['params']['VALUE'] = 'DATE-TIME';
  5297. unset( $year['tz'] );
  5298. }
  5299. $hitval = (( !empty( $year['tz'] ) || !empty( $year[6] ))) ? 7 : 6;
  5300. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
  5301. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $year ), $parno );
  5302. $input['value'] = $this->_date_time_array( $year, $parno );
  5303. }
  5304. elseif( $this->_isArrayTimestampDate( $year )) {
  5305. if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
  5306. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
  5307. if( isset( $input['params']['TZID'] )) {
  5308. $input['params']['VALUE'] = 'DATE-TIME';
  5309. unset( $year['tz'] );
  5310. }
  5311. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3 );
  5312. $hitval = ( isset( $year['tz'] )) ? 7 : 6;
  5313. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
  5314. $input['value'] = $this->_timestamp2date( $year, $parno );
  5315. }
  5316. elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
  5317. if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
  5318. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
  5319. if( isset( $input['params']['TZID'] )) {
  5320. $input['params']['VALUE'] = 'DATE-TIME';
  5321. $parno = 6;
  5322. }
  5323. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
  5324. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
  5325. $input['value'] = $this->_date_time_string( $year, $parno );
  5326. }
  5327. else {
  5328. if( is_array( $params )) {
  5329. if( $localtime ) unset ( $params['VALUE'], $params['TZID'] );
  5330. $input['params'] = $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
  5331. }
  5332. elseif( is_array( $tz )) {
  5333. $input['params'] = $this->_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
  5334. $tz = FALSE;
  5335. }
  5336. elseif( is_array( $hour )) {
  5337. $input['params'] = $this->_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
  5338. $hour = $min = $sec = $tz = FALSE;
  5339. }
  5340. if( isset( $input['params']['TZID'] )) {
  5341. $tz = null;
  5342. $input['params']['VALUE'] = 'DATE-TIME';
  5343. }
  5344. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3 );
  5345. $hitval = ( !empty( $tz )) ? 7 : 6;
  5346. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
  5347. $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
  5348. if( 3 != $parno ) {
  5349. $input['value']['hour'] = ( $hour ) ? $hour : '0';
  5350. $input['value']['min'] = ( $min ) ? $min : '0';
  5351. $input['value']['sec'] = ( $sec ) ? $sec : '0';
  5352. if( !empty( $tz ))
  5353. $input['value']['tz'] = $tz;
  5354. }
  5355. }
  5356. if( 3 == $parno ) {
  5357. $input['params']['VALUE'] = 'DATE';
  5358. unset( $input['value']['tz'] );
  5359. unset( $input['params']['TZID'] );
  5360. }
  5361. elseif( isset( $input['params']['TZID'] ))
  5362. unset( $input['value']['tz'] );
  5363. if( $localtime ) unset( $input['value']['tz'], $input['params']['TZID'] );
  5364. if( isset( $input['value']['tz'] ))
  5365. $input['value']['tz'] = (string) $input['value']['tz'];
  5366. if( !empty( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) &&
  5367. ( !$this->_isOffset( $input['value']['tz'] )))
  5368. $input['params']['TZID'] = $input['value']['tz'];
  5369. return $input;
  5370. }
  5371. /**
  5372. * convert format for input date (UTC) to internal date with parameters
  5373. *
  5374. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5375. * @since 2.4.17 - 2008-10-31
  5376. * @param mixed $year
  5377. * @param mixed $month optional
  5378. * @param int $day optional
  5379. * @param int $hour optional
  5380. * @param int $min optional
  5381. * @param int $sec optional
  5382. * @param array $params optional
  5383. * @return array
  5384. */
  5385. function _setDate2( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
  5386. $input = null;
  5387. if( $this->_isArrayDate( $year )) {
  5388. $input['value'] = $this->_date_time_array( $year, 7 );
  5389. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
  5390. }
  5391. elseif( $this->_isArrayTimestampDate( $year )) {
  5392. $input['value'] = $this->_timestamp2date( $year, 7 );
  5393. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
  5394. }
  5395. elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
  5396. $input['value'] = $this->_date_time_string( $year, 7 );
  5397. $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
  5398. }
  5399. else {
  5400. $input['value'] = array( 'year' => $year
  5401. , 'month' => $month
  5402. , 'day' => $day
  5403. , 'hour' => $hour
  5404. , 'min' => $min
  5405. , 'sec' => $sec );
  5406. $input['params'] = $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
  5407. }
  5408. $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
  5409. if( !isset( $input['value']['hour'] ))
  5410. $input['value']['hour'] = 0;
  5411. if( !isset( $input['value']['min'] ))
  5412. $input['value']['min'] = 0;
  5413. if( !isset( $input['value']['sec'] ))
  5414. $input['value']['sec'] = 0;
  5415. if( !isset( $input['value']['tz'] ) || !$this->_isOffset( $input['value']['tz'] ))
  5416. $input['value']['tz'] = 'Z';
  5417. return $input;
  5418. }
  5419. /**
  5420. * check index and set (an indexed) content in multiple value array
  5421. *
  5422. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5423. * @since 2.5.1 - 2008-11-06
  5424. * @param array $valArr
  5425. * @param mixed $value
  5426. * @param array $params
  5427. * @param array $defaults
  5428. * @param int $index
  5429. * @return void
  5430. */
  5431. function _setMval( & $valArr, $value, $params=FALSE, $defaults=FALSE, $index=FALSE ) {
  5432. if( !is_array( $valArr )) $valArr = array();
  5433. if( $index )
  5434. $index = $index - 1;
  5435. elseif( 0 < count( $valArr )) {
  5436. $index = end( array_keys( $valArr ));
  5437. $index += 1;
  5438. }
  5439. else
  5440. $index = 0;
  5441. $valArr[$index] = array( 'value' => $value, 'params' => $this->_setParams( $params, $defaults ));
  5442. ksort( $valArr );
  5443. }
  5444. /**
  5445. * set input (formatted) parameters- component property attributes
  5446. *
  5447. * default parameters can be set, if missing
  5448. *
  5449. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5450. * @since 1.x.x - 2007-05-01
  5451. * @param array $params
  5452. * @param array $defaults
  5453. * @return array
  5454. */
  5455. function _setParams( $params, $defaults=FALSE ) {
  5456. if( !is_array( $params))
  5457. $params = array();
  5458. $input = array();
  5459. foreach( $params as $paramKey => $paramValue ) {
  5460. if( is_array( $paramValue )) {
  5461. foreach( $paramValue as $pkey => $pValue ) {
  5462. if(( '"' == substr( $pValue, 0, 1 )) && ( '"' == substr( $pValue, -1 )))
  5463. $paramValue[$pkey] = substr( $pValue, 1, ( strlen( $pValue ) - 2 ));
  5464. }
  5465. }
  5466. elseif(( '"' == substr( $paramValue, 0, 1 )) && ( '"' == substr( $paramValue, -1 )))
  5467. $paramValue = substr( $paramValue, 1, ( strlen( $paramValue ) - 2 ));
  5468. if( 'VALUE' == strtoupper( $paramKey ))
  5469. $input['VALUE'] = strtoupper( $paramValue );
  5470. else
  5471. $input[strtoupper( $paramKey )] = $paramValue;
  5472. }
  5473. if( is_array( $defaults )) {
  5474. foreach( $defaults as $paramKey => $paramValue ) {
  5475. if( !isset( $input[$paramKey] ))
  5476. $input[$paramKey] = $paramValue;
  5477. }
  5478. }
  5479. return (0 < count( $input )) ? $input : null;
  5480. }
  5481. /**
  5482. * step date, return updated date, array and timpstamp
  5483. *
  5484. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5485. * @since 2.4.16 - 2008-10-18
  5486. * @param array $date, date to step
  5487. * @param int $timestamp
  5488. * @param array $step, default array( 'day' => 1 )
  5489. * @return void
  5490. */
  5491. function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) {
  5492. foreach( $step as $stepix => $stepvalue )
  5493. $date[$stepix] += $stepvalue;
  5494. $timestamp = $this->_date2timestamp( $date );
  5495. $date = $this->_timestamp2date( $timestamp, 6 );
  5496. foreach( $date as $k => $v ) {
  5497. if( ctype_digit( $v ))
  5498. $date[$k] = (int) $v;
  5499. }
  5500. }
  5501. /**
  5502. * convert timestamp to date array
  5503. *
  5504. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5505. * @since 2.4.16 - 2008-11-01
  5506. * @param mixed $timestamp
  5507. * @param int $parno
  5508. * @return array
  5509. */
  5510. function _timestamp2date( $timestamp, $parno=6 ) {
  5511. if( is_array( $timestamp )) {
  5512. if(( 7 == $parno ) && !empty( $timestamp['tz'] ))
  5513. $tz = $timestamp['tz'];
  5514. $timestamp = $timestamp['timestamp'];
  5515. }
  5516. $output = array( 'year' => date( 'Y', $timestamp )
  5517. , 'month' => date( 'm', $timestamp )
  5518. , 'day' => date( 'd', $timestamp ));
  5519. if( 3 != $parno ) {
  5520. $output['hour'] = date( 'H', $timestamp );
  5521. $output['min'] = date( 'i', $timestamp );
  5522. $output['sec'] = date( 's', $timestamp );
  5523. if( isset( $tz ))
  5524. $output['tz'] = $tz;
  5525. }
  5526. return $output;
  5527. }
  5528. /**
  5529. * convert (numeric) local time offset to seconds correcting localtime to GMT
  5530. *
  5531. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5532. * @since 2.4.16 - 2008-10-19
  5533. * @param string $offset
  5534. * @return integer
  5535. */
  5536. function _tz2offset( $tz ) {
  5537. $tz = trim( (string) $tz );
  5538. $offset = 0;
  5539. if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
  5540. (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
  5541. (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
  5542. (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
  5543. return $offset;
  5544. $hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
  5545. $min2sec = (int) substr( $tz, 3, 2 ) * 60;
  5546. $sec = ( 7 == strlen( $tz )) ? (int) substr( $tz, -2 ) : '00';
  5547. $offset = $hours2sec + $min2sec + $sec;
  5548. $offset = ('-' == substr( $tz, 0, 1 )) ? $offset : -1 * $offset;
  5549. return $offset;
  5550. }
  5551. /*********************************************************************************/
  5552. /*********************************************************************************/
  5553. /**
  5554. * get general component config variables or info about subcomponents
  5555. *
  5556. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5557. * @since 2.5.1 - 2008-11-02
  5558. * @param string $config
  5559. * @return value
  5560. */
  5561. function getConfig( $config ) {
  5562. switch( strtoupper( $config )) {
  5563. case 'ALLOWEMPTY':
  5564. return $this->allowEmpty;
  5565. break;
  5566. case 'COMPSINFO':
  5567. unset( $this->compix );
  5568. $info = array();
  5569. if( isset( $this->components )) {
  5570. foreach( $this->components as $cix => $component ) {
  5571. if( empty( $component )) continue;
  5572. unset( $component->propix );
  5573. $info[$cix]['ordno'] = $cix + 1;
  5574. $info[$cix]['type'] = $component->objName;
  5575. $info[$cix]['uid'] = $component->getProperty( 'uid' );
  5576. $info[$cix]['props'] = $component->getConfig( 'propinfo' );
  5577. $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
  5578. unset( $component->propix );
  5579. }
  5580. }
  5581. return $info;
  5582. break;
  5583. case 'FORMAT':
  5584. return $this->format;
  5585. break;
  5586. case 'LANGUAGE':
  5587. // get language for calendar component as defined in [RFC 1766]
  5588. return $this->language;
  5589. break;
  5590. case 'NL':
  5591. case 'NEWLINECHAR':
  5592. return $this->nl;
  5593. break;
  5594. case 'PROPINFO':
  5595. $output = array();
  5596. if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
  5597. if( empty( $this->uid['value'] )) $this->_makeuid();
  5598. $output['UID'] = 1;
  5599. }
  5600. if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
  5601. if( !empty( $this->summary )) $output['SUMMARY'] = 1;
  5602. if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
  5603. if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
  5604. if( !empty( $this->dtend )) $output['DTEND'] = 1;
  5605. if( !empty( $this->due )) $output['DUE'] = 1;
  5606. if( !empty( $this->duration )) $output['DURATION'] = 1;
  5607. if( !empty( $this->rrule )) $output['RRULE'] = count( $this->rrule );
  5608. if( !empty( $this->rdate )) $output['RDATE'] = count( $this->rdate );
  5609. if( !empty( $this->exdate )) $output['EXDATE'] = count( $this->exdate );
  5610. if( !empty( $this->exrule )) $output['EXRULE'] = count( $this->exrule );
  5611. if( !empty( $this->action )) $output['ACTION'] = 1;
  5612. if( !empty( $this->attach )) $output['ATTACH'] = count( $this->attach );
  5613. if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee );
  5614. if( !empty( $this->categories )) $output['CATEGORIES'] = count( $this->categories );
  5615. if( !empty( $this->class )) $output['CLASS'] = 1;
  5616. if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment );
  5617. if( !empty( $this->completed )) $output['COMPLETED'] = 1;
  5618. if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact );
  5619. if( !empty( $this->created )) $output['CREATED'] = 1;
  5620. if( !empty( $this->freebusy )) $output['FREEBUSY'] = count( $this->freebusy );
  5621. if( !empty( $this->geo )) $output['GEO'] = 1;
  5622. if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1;
  5623. if( !empty( $this->location )) $output['LOCATION'] = 1;
  5624. if( !empty( $this->organizer )) $output['ORGANIZER'] = 1;
  5625. if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1;
  5626. if( !empty( $this->priority )) $output['PRIORITY'] = 1;
  5627. if( !empty( $this->recurrenceid )) $output['RECURRENCE-ID'] = 1;
  5628. if( !empty( $this->relatedto )) $output['RELATED-TO'] = count( $this->relatedto );
  5629. if( !empty( $this->repeat )) $output['REPEAT'] = 1;
  5630. if( !empty( $this->requeststatus )) $output['REQUEST-STATUS'] = count( $this->requeststatus );
  5631. if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources );
  5632. if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
  5633. if( !empty( $this->status )) $output['STATUS'] = 1;
  5634. if( !empty( $this->transp )) $output['TRANSP'] = 1;
  5635. if( !empty( $this->trigger )) $output['TRIGGER'] = 1;
  5636. if( !empty( $this->tzid )) $output['TZID'] = 1;
  5637. if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname );
  5638. if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETTFROM'] = 1;
  5639. if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1;
  5640. if( !empty( $this->tzurl )) $output['TZURL'] = 1;
  5641. if( !empty( $this->url )) $output['URL'] = 1;
  5642. if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
  5643. return $output;
  5644. break;
  5645. case 'UNIQUE_ID':
  5646. if( empty( $this->unique_id ))
  5647. $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
  5648. return $this->unique_id;
  5649. break;
  5650. }
  5651. }
  5652. /**
  5653. * general component config setting
  5654. *
  5655. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5656. * @since 2.4.8 - 2008-10-24
  5657. * @param string $config
  5658. * @param string $value
  5659. * @return void
  5660. */
  5661. function setConfig( $config, $value ) {
  5662. $res = FALSE;
  5663. switch( strtoupper( $config )) {
  5664. case 'ALLOWEMPTY':
  5665. $this->allowEmpty = $value;
  5666. $subcfg = array( 'ALLOWEMPTY' => $value );
  5667. $res = TRUE;
  5668. break;
  5669. case 'FORMAT':
  5670. $value = trim( $value );
  5671. $this->format = $value;
  5672. $this->_createFormat();
  5673. $subcfg = array( 'FORMAT' => $value );
  5674. $res = TRUE;
  5675. break;
  5676. case 'LANGUAGE':
  5677. // set language for calendar component as defined in [RFC 1766]
  5678. $value = trim( $value );
  5679. $this->language = $value;
  5680. $subcfg = array( 'LANGUAGE' => $value );
  5681. $res = TRUE;
  5682. break;
  5683. case 'NL':
  5684. case 'NEWLINECHAR':
  5685. $this->nl = $value;
  5686. $subcfg = array( 'NL' => $value );
  5687. $res = TRUE;
  5688. break;
  5689. case 'UNIQUE_ID':
  5690. $value = trim( $value );
  5691. $this->unique_id = $value;
  5692. $subcfg = array( 'UNIQUE_ID' => $value );
  5693. $res = TRUE;
  5694. break;
  5695. }
  5696. if( !$res ) return FALSE;
  5697. if( isset( $subcfg ) && !empty( $this->components )) {
  5698. foreach( $subcfg as $cfgkey => $cfgvalue ) {
  5699. foreach( $this->components as $cix => $component ) {
  5700. $res = $component->setConfig( $cfgkey, $cfgvalue );
  5701. if( !$res )
  5702. break 2;
  5703. $this->components[$cix] = $component; // PHP4 compliant
  5704. }
  5705. }
  5706. }
  5707. return $res;
  5708. }
  5709. /*********************************************************************************/
  5710. /**
  5711. * delete component property value
  5712. *
  5713. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5714. * @since 2.5.1 - 2008-11-14
  5715. * @param string $propName
  5716. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  5717. * @return bool, if successfull delete TRUE
  5718. */
  5719. function deleteProperty( $propName, $propix=FALSE ) {
  5720. if( $this->_notExistProp( $propName )) return FALSE;
  5721. $propName = strtoupper( $propName );
  5722. if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
  5723. 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
  5724. if( !$propix )
  5725. $propix = ( isset( $this->propdelix[$propName] )) ? $this->propdelix[$propName] + 2 : 1;
  5726. $this->propdelix[$propName] = --$propix;
  5727. }
  5728. $return = FALSE;
  5729. switch( $propName ) {
  5730. case 'ACTION':
  5731. if( !empty( $this->action )) {
  5732. $this->action = '';
  5733. $return = TRUE;
  5734. }
  5735. break;
  5736. case 'ATTACH':
  5737. return $this->deletePropertyM( $this->attach, $propix );
  5738. break;
  5739. case 'ATTENDEE':
  5740. return $this->deletePropertyM( $this->attendee, $propix );
  5741. break;
  5742. case 'CATEGORIES':
  5743. return $this->deletePropertyM( $this->categories, $propix );
  5744. break;
  5745. case 'CLASS':
  5746. if( !empty( $this->class )) {
  5747. $this->class = '';
  5748. $return = TRUE;
  5749. }
  5750. break;
  5751. case 'COMMENT':
  5752. return $this->deletePropertyM( $this->comment, $propix );
  5753. break;
  5754. case 'COMPLETED':
  5755. if( !empty( $this->completed )) {
  5756. $this->completed = '';
  5757. $return = TRUE;
  5758. }
  5759. break;
  5760. case 'CONTACT':
  5761. return $this->deletePropertyM( $this->contact, $propix );
  5762. break;
  5763. case 'CREATED':
  5764. if( !empty( $this->created )) {
  5765. $this->created = '';
  5766. $return = TRUE;
  5767. }
  5768. break;
  5769. case 'DESCRIPTION':
  5770. return $this->deletePropertyM( $this->description, $propix );
  5771. break;
  5772. case 'DTEND':
  5773. if( !empty( $this->dtend )) {
  5774. $this->dtend = '';
  5775. $return = TRUE;
  5776. }
  5777. break;
  5778. case 'DTSTAMP':
  5779. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  5780. return FALSE;
  5781. if( !empty( $this->dtstamp )) {
  5782. $this->dtstamp = '';
  5783. $return = TRUE;
  5784. }
  5785. break;
  5786. case 'DTSTART':
  5787. if( !empty( $this->dtstart )) {
  5788. $this->dtstart = '';
  5789. $return = TRUE;
  5790. }
  5791. break;
  5792. case 'DUE':
  5793. if( !empty( $this->due )) {
  5794. $this->due = '';
  5795. $return = TRUE;
  5796. }
  5797. break;
  5798. case 'DURATION':
  5799. if( !empty( $this->duration )) {
  5800. $this->duration = '';
  5801. $return = TRUE;
  5802. }
  5803. break;
  5804. case 'EXDATE':
  5805. return $this->deletePropertyM( $this->exdate, $propix );
  5806. break;
  5807. case 'EXRULE':
  5808. return $this->deletePropertyM( $this->exrule, $propix );
  5809. break;
  5810. case 'FREEBUSY':
  5811. return $this->deletePropertyM( $this->freebusy, $propix );
  5812. break;
  5813. case 'GEO':
  5814. if( !empty( $this->geo )) {
  5815. $this->geo = '';
  5816. $return = TRUE;
  5817. }
  5818. break;
  5819. case 'LAST-MODIFIED':
  5820. if( !empty( $this->lastmodified )) {
  5821. $this->lastmodified = '';
  5822. $return = TRUE;
  5823. }
  5824. break;
  5825. case 'LOCATION':
  5826. if( !empty( $this->location )) {
  5827. $this->location = '';
  5828. $return = TRUE;
  5829. }
  5830. break;
  5831. case 'ORGANIZER':
  5832. if( !empty( $this->organizer )) {
  5833. $this->organizer = '';
  5834. $return = TRUE;
  5835. }
  5836. break;
  5837. case 'PERCENT-COMPLETE':
  5838. if( !empty( $this->percentcomplete )) {
  5839. $this->percentcomplete = '';
  5840. $return = TRUE;
  5841. }
  5842. break;
  5843. case 'PRIORITY':
  5844. if( !empty( $this->priority )) {
  5845. $this->priority = '';
  5846. $return = TRUE;
  5847. }
  5848. break;
  5849. case 'RDATE':
  5850. return $this->deletePropertyM( $this->rdate, $propix );
  5851. break;
  5852. case 'RECURRENCE-ID':
  5853. if( !empty( $this->recurrenceid )) {
  5854. $this->recurrenceid = '';
  5855. $return = TRUE;
  5856. }
  5857. break;
  5858. case 'RELATED-TO':
  5859. return $this->deletePropertyM( $this->relatedto, $propix );
  5860. break;
  5861. case 'REPEAT':
  5862. if( !empty( $this->repeat )) {
  5863. $this->repeat = '';
  5864. $return = TRUE;
  5865. }
  5866. break;
  5867. case 'REQUEST-STATUS':
  5868. return $this->deletePropertyM( $this->requeststatus, $propix );
  5869. break;
  5870. case 'RESOURCES':
  5871. return $this->deletePropertyM( $this->resources, $propix );
  5872. break;
  5873. case 'RRULE':
  5874. return $this->deletePropertyM( $this->rrule, $propix );
  5875. break;
  5876. case 'SEQUENCE':
  5877. if( !empty( $this->sequence )) {
  5878. $this->sequence = '';
  5879. $return = TRUE;
  5880. }
  5881. break;
  5882. case 'STATUS':
  5883. if( !empty( $this->status )) {
  5884. $this->status = '';
  5885. $return = TRUE;
  5886. }
  5887. break;
  5888. case 'SUMMARY':
  5889. if( !empty( $this->summary )) {
  5890. $this->summary = '';
  5891. $return = TRUE;
  5892. }
  5893. break;
  5894. case 'TRANSP':
  5895. if( !empty( $this->transp )) {
  5896. $this->transp = '';
  5897. $return = TRUE;
  5898. }
  5899. break;
  5900. case 'TRIGGER':
  5901. if( !empty( $this->trigger )) {
  5902. $this->trigger = '';
  5903. $return = TRUE;
  5904. }
  5905. break;
  5906. case 'TZID':
  5907. if( !empty( $this->tzid )) {
  5908. $this->tzid = '';
  5909. $return = TRUE;
  5910. }
  5911. break;
  5912. case 'TZNAME':
  5913. return $this->deletePropertyM( $this->tzname, $propix );
  5914. break;
  5915. case 'TZOFFSETFROM':
  5916. if( !empty( $this->tzoffsetfrom )) {
  5917. $this->tzoffsetfrom = '';
  5918. $return = TRUE;
  5919. }
  5920. break;
  5921. case 'TZOFFSETTO':
  5922. if( !empty( $this->tzoffsetto )) {
  5923. $this->tzoffsetto = '';
  5924. $return = TRUE;
  5925. }
  5926. break;
  5927. case 'TZURL':
  5928. if( !empty( $this->tzurl )) {
  5929. $this->tzurl = '';
  5930. $return = TRUE;
  5931. }
  5932. break;
  5933. case 'UID':
  5934. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  5935. return FALSE;
  5936. if( !empty( $this->uid )) {
  5937. $this->uid = '';
  5938. $return = TRUE;
  5939. }
  5940. break;
  5941. case 'URL':
  5942. if( !empty( $this->url )) {
  5943. $this->url = '';
  5944. $return = TRUE;
  5945. }
  5946. break;
  5947. default:
  5948. $reduced = '';
  5949. if( $propName != 'X-PROP' ) {
  5950. if( !isset( $this->xprop[$propName] )) return FALSE;
  5951. foreach( $this->xprop as $k => $a ) {
  5952. if(( $k != $propName ) && !empty( $a ))
  5953. $reduced[$k] = $a;
  5954. }
  5955. }
  5956. else {
  5957. if( count( $this->xprop ) <= $propix ) return FALSE;
  5958. $xpropno = 0;
  5959. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  5960. if( $propix != $xpropno )
  5961. $reduced[$xpropkey] = $xpropvalue;
  5962. $xpropno++;
  5963. }
  5964. }
  5965. $this->xprop = $reduced;
  5966. return TRUE;
  5967. }
  5968. return $return;
  5969. }
  5970. /*********************************************************************************/
  5971. /**
  5972. * delete component property value, fixing components with multiple occurencies
  5973. *
  5974. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5975. * @since 2.4.5 - 2008-11-07
  5976. * @param array $multiprop, reference to a component property
  5977. * @param int @propix, default 0
  5978. * @return bool TRUE
  5979. */
  5980. function deletePropertyM( & $multiprop, $propix=0 ) {
  5981. if( !isset( $multiprop[$propix])) return FALSE;
  5982. unset( $multiprop[$propix] );
  5983. if( empty( $multiprop )) $multiprop = '';
  5984. return ( isset( $this->multiprop[$propix] )) ? FALSE : TRUE;
  5985. }
  5986. /**
  5987. * get component property value/params
  5988. *
  5989. * if property has multiply values, consequtive function calls are needed
  5990. *
  5991. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  5992. * @since 2.5.1 - 2008-11-02
  5993. * @param string $propName, optional
  5994. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  5995. * @param bool $inclParam=FALSE
  5996. * @param bool $specform=FALSE
  5997. * @return mixed
  5998. */
  5999. function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
  6000. if( $this->_notExistProp( $propName )) return FALSE;
  6001. $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
  6002. if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
  6003. 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
  6004. if( !$propix )
  6005. $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
  6006. $this->propix[$propName] = --$propix;
  6007. }
  6008. switch( $propName ) {
  6009. case 'ACTION':
  6010. if( !empty( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value'];
  6011. break;
  6012. case 'ATTACH':
  6013. if( !isset( $this->attach[$propix] )) return FALSE;
  6014. return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value'];
  6015. break;
  6016. case 'ATTENDEE':
  6017. if( !isset( $this->attendee[$propix] )) return FALSE;
  6018. return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
  6019. break;
  6020. case 'CATEGORIES':
  6021. if( !isset( $this->categories[$propix] )) return FALSE;
  6022. return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value'];
  6023. break;
  6024. case 'CLASS':
  6025. if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
  6026. break;
  6027. case 'COMMENT':
  6028. if( !isset( $this->comment[$propix] )) return FALSE;
  6029. return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
  6030. break;
  6031. case 'COMPLETED':
  6032. if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
  6033. break;
  6034. case 'CONTACT':
  6035. if( !isset( $this->contact[$propix] )) return FALSE;
  6036. return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
  6037. break;
  6038. case 'CREATED':
  6039. if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
  6040. break;
  6041. case 'DESCRIPTION':
  6042. if( !isset( $this->description[$propix] )) return FALSE;
  6043. return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
  6044. break;
  6045. case 'DTEND':
  6046. if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
  6047. break;
  6048. case 'DTSTAMP':
  6049. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  6050. return;
  6051. if( !isset( $this->dtstamp['value'] ))
  6052. $this->_makeDtstamp();
  6053. return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
  6054. break;
  6055. case 'DTSTART':
  6056. if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
  6057. break;
  6058. case 'DUE':
  6059. if( !empty( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value'];
  6060. break;
  6061. case 'DURATION':
  6062. if( !isset( $this->duration['value'] )) return FALSE;
  6063. $value = ( $specform ) ? $this->duration2date() : $this->duration['value'];
  6064. return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
  6065. break;
  6066. case 'EXDATE':
  6067. if( !isset( $this->exdate[$propix] )) return FALSE;
  6068. return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
  6069. break;
  6070. case 'EXRULE':
  6071. if( !isset( $this->exrule[$propix] )) return FALSE;
  6072. return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
  6073. break;
  6074. case 'FREEBUSY':
  6075. if( !isset( $this->freebusy[$propix] )) return FALSE;
  6076. return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
  6077. break;
  6078. case 'GEO':
  6079. if( !empty( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value'];
  6080. break;
  6081. case 'LAST-MODIFIED':
  6082. if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
  6083. break;
  6084. case 'LOCATION':
  6085. if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
  6086. break;
  6087. case 'ORGANIZER':
  6088. if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
  6089. break;
  6090. case 'PERCENT-COMPLETE':
  6091. if( !empty( $this->percentcomplete['value'] )) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value'];
  6092. break;
  6093. case 'PRIORITY':
  6094. if( !empty( $this->priority['value'] )) return ( $inclParam ) ? $this->priority : $this->priority['value'];
  6095. break;
  6096. case 'RDATE':
  6097. if( !isset( $this->rdate[$propix] )) return FALSE;
  6098. return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
  6099. break;
  6100. case 'RECURRENCE-ID':
  6101. if( !empty( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value'];
  6102. break;
  6103. case 'RELATED-TO':
  6104. if( !isset( $this->relatedto[$propix] )) return FALSE;
  6105. return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
  6106. break;
  6107. case 'REPEAT':
  6108. if( !empty( $this->repeat['value'] )) return ( $inclParam ) ? $this->repeat : $this->repeat['value'];
  6109. break;
  6110. case 'REQUEST-STATUS':
  6111. if( !isset( $this->requeststatus[$propix] )) return FALSE;
  6112. return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
  6113. break;
  6114. case 'RESOURCES':
  6115. if( !isset( $this->resources[$propix] )) return FALSE;
  6116. return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
  6117. break;
  6118. case 'RRULE':
  6119. if( !isset( $this->rrule[$propix] )) return FALSE;
  6120. return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
  6121. break;
  6122. case 'SEQUENCE':
  6123. if( !empty( $this->sequence['value'] )) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
  6124. break;
  6125. case 'STATUS':
  6126. if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
  6127. break;
  6128. case 'SUMMARY':
  6129. if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
  6130. break;
  6131. case 'TRANSP':
  6132. if( !empty( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value'];
  6133. break;
  6134. case 'TRIGGER':
  6135. if( !empty( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value'];
  6136. break;
  6137. case 'TZID':
  6138. if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
  6139. break;
  6140. case 'TZNAME':
  6141. if( !isset( $this->tzname[$propix] )) return FALSE;
  6142. return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
  6143. break;
  6144. case 'TZOFFSETFROM':
  6145. if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
  6146. break;
  6147. case 'TZOFFSETTO':
  6148. if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
  6149. break;
  6150. case 'TZURL':
  6151. if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
  6152. break;
  6153. case 'UID':
  6154. if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
  6155. return FALSE;
  6156. if( empty( $this->uid['value'] ))
  6157. $this->_makeuid();
  6158. return ( $inclParam ) ? $this->uid : $this->uid['value'];
  6159. break;
  6160. case 'URL':
  6161. if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
  6162. break;
  6163. default:
  6164. if( $propName != 'X-PROP' ) {
  6165. if( !isset( $this->xprop[$propName] )) return FALSE;
  6166. return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
  6167. : array( $propName, $this->xprop[$propName]['value'] );
  6168. }
  6169. else {
  6170. if( empty( $this->xprop )) return FALSE;
  6171. $xpropno = 0;
  6172. foreach( $this->xprop as $xpropkey => $xpropvalue ) {
  6173. if( $propix == $xpropno )
  6174. return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
  6175. : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
  6176. else
  6177. $xpropno++;
  6178. }
  6179. return FALSE; // not found ??
  6180. }
  6181. }
  6182. return FALSE;
  6183. }
  6184. /**
  6185. * general component property setting
  6186. *
  6187. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6188. * @since 2.5.1 - 2008-11-05
  6189. * @param mixed $args variable number of function arguments,
  6190. * first argument is ALWAYS component name,
  6191. * second ALWAYS component value!
  6192. * @return void
  6193. */
  6194. function setProperty() {
  6195. $numargs = func_num_args();
  6196. if( 1 > $numargs ) return FALSE;
  6197. $arglist = func_get_args();
  6198. if( $this->_notExistProp( $arglist[0] )) return FALSE;
  6199. if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
  6200. return FALSE;
  6201. $arglist[0] = strtoupper( $arglist[0] );
  6202. for( $argix=$numargs; $argix < 12; $argix++ ) {
  6203. if( !isset( $arglist[$argix] ))
  6204. $arglist[$argix] = null;
  6205. }
  6206. switch( $arglist[0] ) {
  6207. case 'ACTION':
  6208. return $this->setAction( $arglist[1], $arglist[2] );
  6209. case 'ATTACH':
  6210. return $this->setAttach( $arglist[1], $arglist[2], $arglist[3] );
  6211. case 'ATTENDEE':
  6212. return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
  6213. case 'CATEGORIES':
  6214. return $this->setCategories( $arglist[1], $arglist[2], $arglist[3] );
  6215. case 'CLASS':
  6216. return $this->setClass( $arglist[1], $arglist[2] );
  6217. case 'COMMENT':
  6218. return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
  6219. case 'COMPLETED':
  6220. return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6221. case 'CONTACT':
  6222. return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
  6223. case 'CREATED':
  6224. return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6225. case 'DESCRIPTION':
  6226. return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
  6227. case 'DTEND':
  6228. return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6229. case 'DTSTAMP':
  6230. return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6231. case 'DTSTART':
  6232. return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6233. case 'DUE':
  6234. return $this->setDue( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6235. case 'DURATION':
  6236. return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
  6237. case 'EXDATE':
  6238. return $this->setExdate( $arglist[1], $arglist[2], $arglist[3] );
  6239. case 'EXRULE':
  6240. return $this->setExrule( $arglist[1], $arglist[2], $arglist[3] );
  6241. case 'FREEBUSY':
  6242. return $this->setFreebusy( $arglist[1], $arglist[2], $arglist[3], $arglist[4] );
  6243. case 'GEO':
  6244. return $this->setGeo( $arglist[1], $arglist[2], $arglist[3] );
  6245. case 'LAST-MODIFIED':
  6246. return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
  6247. case 'LOCATION':
  6248. return $this->setLocation( $arglist[1], $arglist[2] );
  6249. case 'ORGANIZER':
  6250. return $this->setOrganizer( $arglist[1], $arglist[2] );
  6251. case 'PERCENT-COMPLETE':
  6252. return $this->setPercentComplete( $arglist[1], $arglist[2] );
  6253. case 'PRIORITY':
  6254. return $this->setPriority( $arglist[1], $arglist[2] );
  6255. case 'RDATE':
  6256. return $this->setRdate( $arglist[1], $arglist[2], $arglist[3] );
  6257. case 'RECURRENCE-ID':
  6258. return $this->setRecurrenceid( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
  6259. case 'RELATED-TO':
  6260. return $this->setRelatedTo( $arglist[1], $arglist[2], $arglist[3] );
  6261. case 'REPEAT':
  6262. return $this->setRepeat( $arglist[1], $arglist[2] );
  6263. case 'REQUEST-STATUS':
  6264. return $this->setRequestStatus( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] );
  6265. case 'RESOURCES':
  6266. return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
  6267. case 'RRULE':
  6268. return $this->setRrule( $arglist[1], $arglist[2], $arglist[3] );
  6269. case 'SEQUENCE':
  6270. return $this->setSequence( $arglist[1], $arglist[2] );
  6271. case 'STATUS':
  6272. return $this->setStatus( $arglist[1], $arglist[2] );
  6273. case 'SUMMARY':
  6274. return $this->setSummary( $arglist[1], $arglist[2] );
  6275. case 'TRANSP':
  6276. return $this->setTransp( $arglist[1], $arglist[2] );
  6277. case 'TRIGGER':
  6278. 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] );
  6279. case 'TZID':
  6280. return $this->setTzid( $arglist[1], $arglist[2] );
  6281. case 'TZNAME':
  6282. return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
  6283. case 'TZOFFSETFROM':
  6284. return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
  6285. case 'TZOFFSETTO':
  6286. return $this->setTzoffsetto( $arglist[1], $arglist[2] );
  6287. case 'TZURL':
  6288. return $this->setTzurl( $arglist[1], $arglist[2] );
  6289. case 'UID':
  6290. return $this->setUid( $arglist[1], $arglist[2] );
  6291. case 'URL':
  6292. return $this->setUrl( $arglist[1], $arglist[2] );
  6293. default:
  6294. return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
  6295. }
  6296. return FALSE;
  6297. }
  6298. /*********************************************************************************/
  6299. /**
  6300. * parse component unparsed data into properties
  6301. *
  6302. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6303. * @since 2.5.2 - 2008-10-23
  6304. * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
  6305. * @return bool FALSE if error occurs during parsing
  6306. *
  6307. */
  6308. function parse( $unparsedtext=null ) {
  6309. if( $unparsedtext ) {
  6310. $this->unparsed = array();
  6311. if( is_array( $unparsedtext )) {
  6312. $comp = & $this;
  6313. foreach ( $unparsedtext as $line ) {
  6314. if( 'END:VALARM' == strtoupper( substr( $line, 0, 10 ))) {
  6315. $this->setComponent( $comp );
  6316. $comp = & $this;
  6317. continue;
  6318. }
  6319. elseif( 'BEGIN:VALARM' == strtoupper( substr( $line, 0, 12 ))) {
  6320. $comp = new valarm();
  6321. continue;
  6322. }
  6323. else
  6324. $comp->unparsed[] = $line;
  6325. }
  6326. }
  6327. else
  6328. $this->unparsed = array( trim( $unparsedtext ));
  6329. }
  6330. elseif( !isset( $this->unparsed ))
  6331. $this->unparsed = array();
  6332. /* concatenate property values spread over several lines */
  6333. $lastix = -1;
  6334. $propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed'
  6335. , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart'
  6336. , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo'
  6337. , 'last-modified', 'location', 'organizer', 'percent-complete'
  6338. , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat'
  6339. , 'request-status', 'resources', 'rrule', 'sequence', 'status'
  6340. , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
  6341. , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
  6342. $proprows = array();
  6343. foreach( $this->unparsed as $line ) {
  6344. $newProp = FALSE;
  6345. foreach ( $propnames as $propname ) {
  6346. if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
  6347. $newProp = TRUE;
  6348. break;
  6349. }
  6350. }
  6351. if( $newProp ) {
  6352. $newProp = FALSE;
  6353. $lastix++;
  6354. $proprows[$lastix] = $line;
  6355. }
  6356. else {
  6357. /* remove line breaks */
  6358. if(( '\n' == substr( $proprows[$lastix], -2 )) &&
  6359. ( ' ' == substr( $line, 0, 1 ))) {
  6360. $proprows[$lastix] = substr( $proprows[$lastix], 0, strlen( $proprows[$lastix] ) - 2 );
  6361. $line = substr( $line, 1 );
  6362. }
  6363. $proprows[$lastix] .= $line;
  6364. }
  6365. }
  6366. /* parse each property 'line' */
  6367. foreach( $proprows as $line ) {
  6368. $line = str_replace( "\n ", '', $line );
  6369. if( '\n' == substr( $line, -2 ))
  6370. $line = substr( $line, 0, strlen( $line ) - 2 );
  6371. /* get propname, (problem with x-properties, otherwise in previous loop) */
  6372. $cix = $propname = null;
  6373. for( $cix=0; $cix < strlen( $line ); $cix++ ) {
  6374. if( in_array( $line{$cix}, array( ':', ';' )))
  6375. break;
  6376. else {
  6377. $propname .= $line{$cix};
  6378. }
  6379. }
  6380. if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) {
  6381. $propname2 = $propname;
  6382. $propname = 'X-';
  6383. }
  6384. /* rest of the line is opt.params and value */
  6385. $line = substr( $line, $cix );
  6386. /* separate attributes from value */
  6387. $attr = array();
  6388. $attrix = -1;
  6389. $strlen = strlen( $line );
  6390. for( $cix=0; $cix < $strlen; $cix++ ) {
  6391. if(( ':' == $line{$cix} ) &&
  6392. ( '://' != substr( $line, $cix, 3 )) &&
  6393. ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
  6394. $attrEnd = TRUE;
  6395. if(( $cix < ( $strlen - 4 )) &&
  6396. ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
  6397. for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
  6398. if( '://' == substr( $line, $c2ix - 2, 3 )) {
  6399. $attrEnd = FALSE;
  6400. break; // an URI with a portnr!!
  6401. }
  6402. }
  6403. }
  6404. if( $attrEnd) {
  6405. $line = substr( $line, $cix + 1 );
  6406. break;
  6407. }
  6408. }
  6409. if( ';' == $line{$cix} )
  6410. $attr[++$attrix] = null;
  6411. else
  6412. $attr[$attrix] .= $line{$cix};
  6413. }
  6414. /* make attributes in array format */
  6415. $propattr = array();
  6416. foreach( $attr as $attribute ) {
  6417. $attrsplit = explode( '=', $attribute, 2 );
  6418. if( 1 < count( $attrsplit ))
  6419. $propattr[$attrsplit[0]] = $attrsplit[1];
  6420. else
  6421. $propattr[] = $attribute;
  6422. }
  6423. /* call setProperty( $propname.. . */
  6424. switch( $propname ) {
  6425. case 'ATTENDEE':
  6426. foreach( $propattr as $pix => $attr ) {
  6427. $attr2 = explode( ',', $attr );
  6428. if( 1 < count( $attr2 ))
  6429. $propattr[$pix] = $attr2;
  6430. }
  6431. $this->setProperty( $propname, $line, $propattr );
  6432. break;
  6433. case 'CATEGORIES':
  6434. case 'RESOURCES':
  6435. if( FALSE !== strpos( $line, ',' )) {
  6436. $content = explode( ',', $line );
  6437. $clen = count( $content );
  6438. for( $cix = 0; $cix < $clen; $cix++ ) {
  6439. if( "\\" == substr($content[$cix], -1)) {
  6440. $content[$cix] .= ','.$content[$cix + 1];
  6441. unset($content[$cix + 1]);
  6442. $cix++;
  6443. }
  6444. }
  6445. if( 1 < count( $content )) {
  6446. $content = array_values( $content );
  6447. foreach( $content as $cix => $contentPart )
  6448. $content[$cix] = $this->_strunrep( $contentPart );
  6449. $this->setProperty( $propname, $content, $propattr );
  6450. break;
  6451. }
  6452. else
  6453. $line = reset( $content );
  6454. }
  6455. //no break
  6456. case 'X-':
  6457. $propname = ( isset( $propname2 )) ? $propname2 : $propname;
  6458. //no break
  6459. case 'COMMENT':
  6460. case 'CONTACT':
  6461. case 'DESCRIPTION':
  6462. case 'LOCATION':
  6463. case 'SUMMARY':
  6464. if( empty( $line ))
  6465. $propattr = null;
  6466. $this->setProperty( $propname, $this->_strunrep( $line ), $propattr );
  6467. unset( $propname2 );
  6468. break;
  6469. case 'REQUEST-STATUS':
  6470. $values = explode( ';', $line, 3 );
  6471. $values[1] = ( !isset( $values[1] )) ? null : $this->_strunrep( $values[1] );
  6472. $values[2] = ( !isset( $values[2] )) ? null : $this->_strunrep( $values[2] );
  6473. $this->setProperty( $propname
  6474. , $values[0] // statcode
  6475. , $values[1] // statdesc
  6476. , $values[2] // extdata
  6477. , $propattr );
  6478. break;
  6479. case 'FREEBUSY':
  6480. $fbtype = ( isset( $propattr['FBTYPE'] )) ? $propattr['FBTYPE'] : ''; // force setting default, if missing
  6481. unset( $propattr['FBTYPE'] );
  6482. $values = explode( ',', $line );
  6483. foreach( $values as $vix => $value ) {
  6484. $value2 = explode( '/', $value );
  6485. if( 1 < count( $value2 ))
  6486. $values[$vix] = $value2;
  6487. }
  6488. $this->setProperty( $propname, $fbtype, $values, $propattr );
  6489. break;
  6490. case 'GEO':
  6491. $value = explode( ';', $line, 2 );
  6492. if( 2 > count( $value ))
  6493. $value[1] = null;
  6494. $this->setProperty( $propname, $value[0], $value[1], $propattr );
  6495. break;
  6496. case 'EXDATE':
  6497. $values = ( !empty( $line )) ? explode( ',', $line ) : null;
  6498. $this->setProperty( $propname, $values, $propattr );
  6499. break;
  6500. case 'RDATE':
  6501. if( empty( $line )) {
  6502. $this->setProperty( $propname, $line, $propattr );
  6503. break;
  6504. }
  6505. $values = explode( ',', $line );
  6506. foreach( $values as $vix => $value ) {
  6507. $value2 = explode( '/', $value );
  6508. if( 1 < count( $value2 ))
  6509. $values[$vix] = $value2;
  6510. }
  6511. $this->setProperty( $propname, $values, $propattr );
  6512. break;
  6513. case 'EXRULE':
  6514. case 'RRULE':
  6515. $values = explode( ';', $line );
  6516. $recur = array();
  6517. foreach( $values as $value2 ) {
  6518. if( empty( $value2 ))
  6519. continue; // ;-char in ending position ???
  6520. $value3 = explode( '=', $value2, 2 );
  6521. $rulelabel = strtoupper( $value3[0] );
  6522. switch( $rulelabel ) {
  6523. case 'BYDAY':
  6524. $value4 = explode( ',', $value3[1] );
  6525. if( 1 < count( $value4 )) {
  6526. foreach( $value4 as $v5ix => $value5 ) {
  6527. $value6 = array();
  6528. $dayno = $dayname = null;
  6529. $value5 = trim( (string) $value5 );
  6530. if(( ctype_alpha( substr( $value5, -1 ))) &&
  6531. ( ctype_alpha( substr( $value5, -2, 1 )))) {
  6532. $dayname = substr( $value5, -2, 2 );
  6533. if( 2 < strlen( $value5 ))
  6534. $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
  6535. }
  6536. if( $dayno )
  6537. $value6[] = $dayno;
  6538. if( $dayname )
  6539. $value6['DAY'] = $dayname;
  6540. $value4[$v5ix] = $value6;
  6541. }
  6542. }
  6543. else {
  6544. $value4 = array();
  6545. $dayno = $dayname = null;
  6546. $value5 = trim( (string) $value3[1] );
  6547. if(( ctype_alpha( substr( $value5, -1 ))) &&
  6548. ( ctype_alpha( substr( $value5, -2, 1 )))) {
  6549. $dayname = substr( $value5, -2, 2 );
  6550. if( 2 < strlen( $value5 ))
  6551. $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
  6552. }
  6553. if( $dayno )
  6554. $value4[] = $dayno;
  6555. if( $dayname )
  6556. $value4['DAY'] = $dayname;
  6557. }
  6558. $recur[$rulelabel] = $value4;
  6559. break;
  6560. default:
  6561. $value4 = explode( ',', $value3[1] );
  6562. if( 1 < count( $value4 ))
  6563. $value3[1] = $value4;
  6564. $recur[$rulelabel] = $value3[1];
  6565. break;
  6566. } // end - switch $rulelabel
  6567. } // end - foreach( $values.. .
  6568. $this->setProperty( $propname, $recur, $propattr );
  6569. break;
  6570. default:
  6571. $this->setProperty( $propname, $line, $propattr );
  6572. break;
  6573. } // end switch( $propname.. .
  6574. } // end - foreach( $proprows.. .
  6575. unset( $this->unparsed, $proprows );
  6576. if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) {
  6577. for( $six = 0; $six < count( $this->components ); $six++ ) {
  6578. if( !empty( $this->components[$six]->unparsed ))
  6579. $this->components[$six]->parse();
  6580. }
  6581. }
  6582. }
  6583. /*********************************************************************************/
  6584. /*********************************************************************************/
  6585. /**
  6586. * return a copy of this component
  6587. *
  6588. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6589. * @since 2.2.16 - 2007-11-07
  6590. * @return object
  6591. */
  6592. function copy() {
  6593. $serialized_contents = serialize($this);
  6594. $copy = unserialize($serialized_contents);
  6595. unset( $copy->propix );
  6596. return $copy;
  6597. }
  6598. /*********************************************************************************/
  6599. /*********************************************************************************/
  6600. /**
  6601. * delete calendar subcomponent from component container
  6602. *
  6603. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6604. * @since 2.5.1 - 2008-10-15
  6605. * @param mixed $arg1 ordno / component type / component uid
  6606. * @param mixed $arg2 optional, ordno if arg1 = component type
  6607. * @return void
  6608. */
  6609. function deleteComponent( $arg1, $arg2=FALSE ) {
  6610. if( !isset( $this->components )) return FALSE;
  6611. $argType = $index = null;
  6612. if ( ctype_digit( (string) $arg1 )) {
  6613. $argType = 'INDEX';
  6614. $index = (int) $arg1 - 1;
  6615. }
  6616. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  6617. $argType = strtolower( $arg1 );
  6618. $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
  6619. }
  6620. $cix2dC = 0;
  6621. foreach ( $this->components as $cix => $component) {
  6622. if( empty( $component )) continue;
  6623. unset( $component->propix );
  6624. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  6625. unset( $this->components[$cix] );
  6626. return TRUE;
  6627. }
  6628. elseif( $argType == $component->objName ) {
  6629. if( $index == $cix2dC ) {
  6630. unset( $this->components[$cix] );
  6631. return TRUE;
  6632. }
  6633. $cix2dC++;
  6634. }
  6635. elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
  6636. unset( $this->components[$cix] );
  6637. return TRUE;
  6638. }
  6639. }
  6640. return FALSE;
  6641. }
  6642. /**
  6643. * get calendar component subcomponent from component container
  6644. *
  6645. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6646. * @since 2.5.1 - 2008-10-15
  6647. * @param mixed $arg1 optional, ordno/component type/ component uid
  6648. * @param mixed $arg2 optional, ordno if arg1 = component type
  6649. * @return object
  6650. */
  6651. function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
  6652. if( !isset( $this->components )) return FALSE;
  6653. $index = $argType = null;
  6654. if ( !$arg1 ) {
  6655. $argType = 'INDEX';
  6656. $index = $this->compix['INDEX'] =
  6657. ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
  6658. }
  6659. elseif ( ctype_digit( (string) $arg1 )) {
  6660. $argType = 'INDEX';
  6661. $index = (int) $arg1;
  6662. unset( $this->compix );
  6663. }
  6664. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  6665. unset( $this->compix['INDEX'] );
  6666. $argType = strtolower( $arg1 );
  6667. if( !$arg2 )
  6668. $index = $this->compix[$argType] =
  6669. ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
  6670. else
  6671. $index = (int) $arg2;
  6672. }
  6673. $index -= 1;
  6674. $ckeys = array_keys( $this->components );
  6675. if( !empty( $index) && ( $index > end( $ckeys )))
  6676. return FALSE;
  6677. $cix2gC = 0;
  6678. foreach( $this->components as $cix => $component ) {
  6679. if( empty( $component )) continue;
  6680. unset( $component->propix );
  6681. if(( 'INDEX' == $argType ) && ( $index == $cix ))
  6682. return $component->copy();
  6683. elseif( $argType == $component->objName ) {
  6684. if( $index == $cix2gC )
  6685. return $component->copy();
  6686. $cix2gC++;
  6687. }
  6688. elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' ))) {
  6689. unset( $component->propix );
  6690. return $component->copy();
  6691. }
  6692. }
  6693. /* not found.. . */
  6694. unset( $this->compix );
  6695. return false;
  6696. }
  6697. /**
  6698. * add calendar component as subcomponent to container for subcomponents
  6699. *
  6700. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6701. * @since 1.x.x - 2007-04-24
  6702. * @param object $component calendar component
  6703. * @return void
  6704. */
  6705. function addSubComponent ( $component ) {
  6706. $this->setComponent( $component );
  6707. }
  6708. /**
  6709. * add calendar component as subcomponent to container for subcomponents
  6710. *
  6711. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6712. * @since 2.4.13 - 2008-09-24
  6713. * @param object $component calendar component
  6714. * @param mixed $arg1 optional, ordno/component type/ component uid
  6715. * @param mixed $arg2 optional, ordno if arg1 = component type
  6716. * @return bool
  6717. */
  6718. function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
  6719. if( !isset( $this->components )) return FALSE;
  6720. if( '' >= $component->getConfig( 'language'))
  6721. $component->setConfig( 'language', $this->getConfig( 'language' ));
  6722. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  6723. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  6724. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  6725. $component->setConfig( 'format', $this->getConfig( 'format' ));
  6726. if( !in_array( $component->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
  6727. unset( $component->propix );
  6728. /* make sure dtstamp and uid is set */
  6729. $dummy = $component->getProperty( 'dtstamp' );
  6730. $dummy = $component->getProperty( 'uid' );
  6731. }
  6732. if( !$arg1 ) {
  6733. $this->components[] = $component->copy();
  6734. return TRUE;
  6735. }
  6736. $argType = $index = null;
  6737. if ( ctype_digit( (string) $arg1 )) {
  6738. $argType = 'INDEX';
  6739. $index = (int) $arg1 - 1;
  6740. }
  6741. elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
  6742. $argType = strtolower( $arg1 );
  6743. $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
  6744. }
  6745. $cix2sC = 0;
  6746. foreach ( $this->components as $cix => $component2 ) {
  6747. if( empty( $component2 )) continue;
  6748. unset( $component2->propix );
  6749. if(( 'INDEX' == $argType ) && ( $index == $cix )) {
  6750. $this->components[$cix] = $component->copy();
  6751. return TRUE;
  6752. }
  6753. elseif( $argType == $component2->objName ) {
  6754. if( $index == $cix2sC ) {
  6755. $this->components[$cix] = $component->copy();
  6756. return TRUE;
  6757. }
  6758. $cix2sC++;
  6759. }
  6760. elseif( !$argType && ($arg1 == $component2->getProperty( 'uid' ))) {
  6761. $this->components[$cix] = $component->copy();
  6762. return TRUE;
  6763. }
  6764. }
  6765. /* not found.. . insert anyway.. .*/
  6766. $this->components[] = $component->copy();
  6767. return TRUE;
  6768. }
  6769. /**
  6770. * creates formatted output for subcomponents
  6771. *
  6772. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6773. * @since 2.4.10 - 2008-08-06
  6774. * @return string
  6775. */
  6776. function createSubComponent() {
  6777. $output = null;
  6778. foreach( $this->components as $component ) {
  6779. if( empty( $component )) continue;
  6780. if( '' >= $component->getConfig( 'language'))
  6781. $component->setConfig( 'language', $this->getConfig( 'language' ));
  6782. $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
  6783. $component->setConfig( 'nl', $this->getConfig( 'nl' ));
  6784. $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
  6785. $component->setConfig( 'format', $this->getConfig( 'format' ));
  6786. $output .= $component->createComponent( $this->xcaldecl );
  6787. }
  6788. return $output;
  6789. }
  6790. /********************************************************************************/
  6791. /**
  6792. * break lines at pos 75
  6793. *
  6794. * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
  6795. * break. Long content lines SHOULD be split into a multiple line
  6796. * representations using a line "folding" technique. That is, a long
  6797. * line can be split between any two characters by inserting a CRLF
  6798. * immediately followed by a single linear white space character (i.e.,
  6799. * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
  6800. * of CRLF followed immediately by a single linear white space character
  6801. * is ignored (i.e., removed) when processing the content type.
  6802. *
  6803. * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
  6804. * the reserved expression "\n" in the arg $string could be broken up by the
  6805. * folding of lines, causing ambiguity in the return string.
  6806. * Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
  6807. *
  6808. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6809. * @since 2.2.8 - 2006-09-03
  6810. * @param string $value
  6811. * @return string
  6812. */
  6813. function _size75( $string ) {
  6814. $strlen = strlen( $string );
  6815. $tmp = $string;
  6816. $string = null;
  6817. while( $strlen > 75 ) {
  6818. $breakAtChar = 75;
  6819. if( substr( $tmp, ( $breakAtChar - 1 ), strlen( '\n' )) == '\n' )
  6820. $breakAtChar = $breakAtChar - 1;
  6821. $string .= substr( $tmp, 0, $breakAtChar );
  6822. $string .= $this->nl;
  6823. $tmp = ' '.substr( $tmp, $breakAtChar );
  6824. $strlen = strlen( $tmp );
  6825. } // while
  6826. $string .= rtrim( $tmp ); // the rest
  6827. if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
  6828. $string .= $this->nl;
  6829. return $string;
  6830. }
  6831. /**
  6832. * special characters management output
  6833. *
  6834. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6835. * @since 2.3.3 - 2007-12-20
  6836. * @param string $string
  6837. * @return string
  6838. */
  6839. function _strrep( $string ) {
  6840. switch( $this->format ) {
  6841. case 'xcal':
  6842. $string = str_replace( '\n', $this->nl, $string);
  6843. $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
  6844. break;
  6845. default:
  6846. $pos = 0;
  6847. while( $pos <= strlen( $string )) {
  6848. $pos = strpos( $string, "\\", $pos );
  6849. if( FALSE === $pos )
  6850. break;
  6851. if( !in_array( $string{($pos + 1)}, array( 'n', 'N', 'r', ',', ';' ))) {
  6852. $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
  6853. $pos += 1;
  6854. }
  6855. $pos += 1;
  6856. }
  6857. if( FALSE !== strpos( $string, '"' ))
  6858. $string = str_replace('"', "'", $string);
  6859. if( FALSE !== strpos( $string, ',' ))
  6860. $string = str_replace(',', '\,', $string);
  6861. if( FALSE !== strpos( $string, ';' ))
  6862. $string = str_replace(';', '\;', $string);
  6863. if( FALSE !== strpos( $string, "\r\n" ))
  6864. $string = str_replace( "\r\n", '\n', $string);
  6865. elseif( FALSE !== strpos( $string, "\r" ))
  6866. $string = str_replace( "\r", '\n', $string);
  6867. if( FALSE !== strpos( $string, '\N' ))
  6868. $string = str_replace( '\N', '\n', $string);
  6869. // if( FALSE !== strpos( $string, $this->nl ))
  6870. $string = str_replace( $this->nl, '\n', $string);
  6871. break;
  6872. }
  6873. return $string;
  6874. }
  6875. /**
  6876. * special characters management input (from iCal file)
  6877. *
  6878. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6879. * @since 2.3.3 - 2007-11-23
  6880. * @param string $string
  6881. * @return string
  6882. */
  6883. function _strunrep( $string ) {
  6884. $string = str_replace( '\\\\', '\\', $string);
  6885. $string = str_replace( '\,', ',', $string);
  6886. $string = str_replace( '\;', ';', $string);
  6887. // $string = str_replace( '\n', $this->nl, $string); // ??
  6888. return $string;
  6889. }
  6890. }
  6891. /*********************************************************************************/
  6892. /*********************************************************************************/
  6893. /**
  6894. * class for calendar component VEVENT
  6895. *
  6896. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6897. * @since 2.5.1 - 2008-10-12
  6898. */
  6899. class vevent extends calendarComponent {
  6900. var $attach;
  6901. var $attendee;
  6902. var $categories;
  6903. var $comment;
  6904. var $contact;
  6905. var $class;
  6906. var $created;
  6907. var $description;
  6908. var $dtend;
  6909. var $dtstart;
  6910. var $duration;
  6911. var $exdate;
  6912. var $exrule;
  6913. var $geo;
  6914. var $lastmodified;
  6915. var $location;
  6916. var $organizer;
  6917. var $priority;
  6918. var $rdate;
  6919. var $recurrenceid;
  6920. var $relatedto;
  6921. var $requeststatus;
  6922. var $resources;
  6923. var $rrule;
  6924. var $sequence;
  6925. var $status;
  6926. var $summary;
  6927. var $transp;
  6928. var $url;
  6929. var $xprop;
  6930. // component subcomponents container
  6931. var $components;
  6932. /**
  6933. * constructor for calendar component VEVENT object
  6934. *
  6935. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6936. * @since 2.5.1 - 2008-10-31
  6937. */
  6938. function __construct() {
  6939. $this->calendarComponent();
  6940. $this->attach = '';
  6941. $this->attendee = '';
  6942. $this->categories = '';
  6943. $this->class = '';
  6944. $this->comment = '';
  6945. $this->contact = '';
  6946. $this->created = '';
  6947. $this->description = '';
  6948. $this->dtstart = '';
  6949. $this->dtend = '';
  6950. $this->duration = '';
  6951. $this->exdate = '';
  6952. $this->exrule = '';
  6953. $this->geo = '';
  6954. $this->lastmodified = '';
  6955. $this->location = '';
  6956. $this->organizer = '';
  6957. $this->priority = '';
  6958. $this->rdate = '';
  6959. $this->recurrenceid = '';
  6960. $this->relatedto = '';
  6961. $this->requeststatus = '';
  6962. $this->resources = '';
  6963. $this->rrule = '';
  6964. $this->sequence = '';
  6965. $this->status = '';
  6966. $this->summary = '';
  6967. $this->transp = '';
  6968. $this->url = '';
  6969. $this->xprop = '';
  6970. $this->components = array();
  6971. }
  6972. /**
  6973. * create formatted output for calendar component VEVENT object instance
  6974. *
  6975. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  6976. * @since 2.5.1 - 2008-11-07
  6977. * @param array $xcaldecl
  6978. * @return string
  6979. */
  6980. function createComponent( &$xcaldecl ) {
  6981. $objectname = $this->_createFormat();
  6982. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  6983. $component .= $this->createUid();
  6984. $component .= $this->createDtstamp();
  6985. $component .= $this->createAttach();
  6986. $component .= $this->createAttendee();
  6987. $component .= $this->createCategories();
  6988. $component .= $this->createComment();
  6989. $component .= $this->createContact();
  6990. $component .= $this->createClass();
  6991. $component .= $this->createCreated();
  6992. $component .= $this->createDescription();
  6993. $component .= $this->createDtstart();
  6994. $component .= $this->createDtend();
  6995. $component .= $this->createDuration();
  6996. $component .= $this->createExdate();
  6997. $component .= $this->createExrule();
  6998. $component .= $this->createGeo();
  6999. $component .= $this->createLastModified();
  7000. $component .= $this->createLocation();
  7001. $component .= $this->createOrganizer();
  7002. $component .= $this->createPriority();
  7003. $component .= $this->createRdate();
  7004. $component .= $this->createRrule();
  7005. $component .= $this->createRelatedTo();
  7006. $component .= $this->createRequestStatus();
  7007. $component .= $this->createRecurrenceid();
  7008. $component .= $this->createResources();
  7009. $component .= $this->createSequence();
  7010. $component .= $this->createStatus();
  7011. $component .= $this->createSummary();
  7012. $component .= $this->createTransp();
  7013. $component .= $this->createUrl();
  7014. $component .= $this->createXprop();
  7015. $component .= $this->createSubComponent();
  7016. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7017. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7018. foreach( $this->xcaldecl as $localxcaldecl )
  7019. $xcaldecl[] = $localxcaldecl;
  7020. }
  7021. return $component;
  7022. }
  7023. }
  7024. /*********************************************************************************/
  7025. /*********************************************************************************/
  7026. /**
  7027. * class for calendar component VTODO
  7028. *
  7029. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7030. * @since 2.5.1 - 2008-10-12
  7031. */
  7032. class vtodo extends calendarComponent {
  7033. var $attach;
  7034. var $attendee;
  7035. var $categories;
  7036. var $comment;
  7037. var $completed;
  7038. var $contact;
  7039. var $class;
  7040. var $created;
  7041. var $description;
  7042. var $dtstart;
  7043. var $due;
  7044. var $duration;
  7045. var $exdate;
  7046. var $exrule;
  7047. var $geo;
  7048. var $lastmodified;
  7049. var $location;
  7050. var $organizer;
  7051. var $percentcomplete;
  7052. var $priority;
  7053. var $rdate;
  7054. var $recurrenceid;
  7055. var $relatedto;
  7056. var $requeststatus;
  7057. var $resources;
  7058. var $rrule;
  7059. var $sequence;
  7060. var $status;
  7061. var $summary;
  7062. var $url;
  7063. var $xprop;
  7064. // component subcomponents container
  7065. var $components;
  7066. /**
  7067. * constructor for calendar component VTODO object
  7068. *
  7069. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7070. * @since 2.5.1 - 2008-10-31
  7071. */
  7072. function __construct() {
  7073. $this->calendarComponent();
  7074. $this->attach = '';
  7075. $this->attendee = '';
  7076. $this->categories = '';
  7077. $this->class = '';
  7078. $this->comment = '';
  7079. $this->completed = '';
  7080. $this->contact = '';
  7081. $this->created = '';
  7082. $this->description = '';
  7083. $this->dtstart = '';
  7084. $this->due = '';
  7085. $this->duration = '';
  7086. $this->exdate = '';
  7087. $this->exrule = '';
  7088. $this->geo = '';
  7089. $this->lastmodified = '';
  7090. $this->location = '';
  7091. $this->organizer = '';
  7092. $this->percentcomplete = '';
  7093. $this->priority = '';
  7094. $this->rdate = '';
  7095. $this->recurrenceid = '';
  7096. $this->relatedto = '';
  7097. $this->requeststatus = '';
  7098. $this->resources = '';
  7099. $this->rrule = '';
  7100. $this->sequence = '';
  7101. $this->status = '';
  7102. $this->summary = '';
  7103. $this->url = '';
  7104. $this->xprop = '';
  7105. $this->components = array();
  7106. }
  7107. /**
  7108. * create formatted output for calendar component VTODO object instance
  7109. *
  7110. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7111. * @since 2.5.1 - 2008-11-07
  7112. * @param array $xcaldecl
  7113. * @return string
  7114. */
  7115. function createComponent( &$xcaldecl ) {
  7116. $objectname = $this->_createFormat();
  7117. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7118. $component .= $this->createUid();
  7119. $component .= $this->createDtstamp();
  7120. $component .= $this->createAttach();
  7121. $component .= $this->createAttendee();
  7122. $component .= $this->createCategories();
  7123. $component .= $this->createClass();
  7124. $component .= $this->createComment();
  7125. $component .= $this->createCompleted();
  7126. $component .= $this->createContact();
  7127. $component .= $this->createCreated();
  7128. $component .= $this->createDescription();
  7129. $component .= $this->createDtstart();
  7130. $component .= $this->createDue();
  7131. $component .= $this->createDuration();
  7132. $component .= $this->createExdate();
  7133. $component .= $this->createExrule();
  7134. $component .= $this->createGeo();
  7135. $component .= $this->createLastModified();
  7136. $component .= $this->createLocation();
  7137. $component .= $this->createOrganizer();
  7138. $component .= $this->createPercentComplete();
  7139. $component .= $this->createPriority();
  7140. $component .= $this->createRdate();
  7141. $component .= $this->createRelatedTo();
  7142. $component .= $this->createRequestStatus();
  7143. $component .= $this->createRecurrenceid();
  7144. $component .= $this->createResources();
  7145. $component .= $this->createRrule();
  7146. $component .= $this->createSequence();
  7147. $component .= $this->createStatus();
  7148. $component .= $this->createSummary();
  7149. $component .= $this->createUrl();
  7150. $component .= $this->createXprop();
  7151. $component .= $this->createSubComponent();
  7152. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7153. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7154. foreach( $this->xcaldecl as $localxcaldecl )
  7155. $xcaldecl[] = $localxcaldecl;
  7156. }
  7157. return $component;
  7158. }
  7159. }
  7160. /*********************************************************************************/
  7161. /*********************************************************************************/
  7162. /**
  7163. * class for calendar component VJOURNAL
  7164. *
  7165. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7166. * @since 2.5.1 - 2008-10-12
  7167. */
  7168. class vjournal extends calendarComponent {
  7169. var $attach;
  7170. var $attendee;
  7171. var $categories;
  7172. var $comment;
  7173. var $contact;
  7174. var $class;
  7175. var $created;
  7176. var $description;
  7177. var $dtstart;
  7178. var $exdate;
  7179. var $exrule;
  7180. var $lastmodified;
  7181. var $organizer;
  7182. var $rdate;
  7183. var $recurrenceid;
  7184. var $relatedto;
  7185. var $requeststatus;
  7186. var $rrule;
  7187. var $sequence;
  7188. var $status;
  7189. var $summary;
  7190. var $url;
  7191. var $xprop;
  7192. /**
  7193. * constructor for calendar component VJOURNAL object
  7194. *
  7195. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7196. * @since 2.5.1 - 2008-10-31
  7197. */
  7198. function __construct() {
  7199. $this->calendarComponent();
  7200. $this->attach = '';
  7201. $this->attendee = '';
  7202. $this->categories = '';
  7203. $this->class = '';
  7204. $this->comment = '';
  7205. $this->contact = '';
  7206. $this->created = '';
  7207. $this->description = '';
  7208. $this->dtstart = '';
  7209. $this->exdate = '';
  7210. $this->exrule = '';
  7211. $this->lastmodified = '';
  7212. $this->organizer = '';
  7213. $this->rdate = '';
  7214. $this->recurrenceid = '';
  7215. $this->relatedto = '';
  7216. $this->requeststatus = '';
  7217. $this->rrule = '';
  7218. $this->sequence = '';
  7219. $this->status = '';
  7220. $this->summary = '';
  7221. $this->url = '';
  7222. $this->xprop = '';
  7223. }
  7224. /**
  7225. * create formatted output for calendar component VJOURNAL object instance
  7226. *
  7227. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7228. * @since 2.5.1 - 2008-10-12
  7229. * @param array $xcaldecl
  7230. * @return string
  7231. */
  7232. function createComponent( &$xcaldecl ) {
  7233. $objectname = $this->_createFormat();
  7234. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7235. $component .= $this->createUid();
  7236. $component .= $this->createDtstamp();
  7237. $component .= $this->createAttach();
  7238. $component .= $this->createAttendee();
  7239. $component .= $this->createCategories();
  7240. $component .= $this->createClass();
  7241. $component .= $this->createComment();
  7242. $component .= $this->createContact();
  7243. $component .= $this->createCreated();
  7244. $component .= $this->createDescription();
  7245. $component .= $this->createDtstart();
  7246. $component .= $this->createExdate();
  7247. $component .= $this->createExrule();
  7248. $component .= $this->createLastModified();
  7249. $component .= $this->createOrganizer();
  7250. $component .= $this->createRdate();
  7251. $component .= $this->createRequestStatus();
  7252. $component .= $this->createRecurrenceid();
  7253. $component .= $this->createRelatedTo();
  7254. $component .= $this->createRrule();
  7255. $component .= $this->createSequence();
  7256. $component .= $this->createStatus();
  7257. $component .= $this->createSummary();
  7258. $component .= $this->createUrl();
  7259. $component .= $this->createXprop();
  7260. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7261. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7262. foreach( $this->xcaldecl as $localxcaldecl )
  7263. $xcaldecl[] = $localxcaldecl;
  7264. }
  7265. return $component;
  7266. }
  7267. }
  7268. /*********************************************************************************/
  7269. /*********************************************************************************/
  7270. /**
  7271. * class for calendar component VFREEBUSY
  7272. *
  7273. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7274. * @since 2.5.1 - 2008-10-12
  7275. */
  7276. class vfreebusy extends calendarComponent {
  7277. var $attendee;
  7278. var $comment;
  7279. var $contact;
  7280. var $dtend;
  7281. var $dtstart;
  7282. var $duration;
  7283. var $freebusy;
  7284. var $organizer;
  7285. var $requeststatus;
  7286. var $url;
  7287. var $xprop;
  7288. // component subcomponents container
  7289. var $components;
  7290. /**
  7291. * constructor for calendar component VFREEBUSY object
  7292. *
  7293. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7294. * @since 2.5.1 - 2008-10-31
  7295. */
  7296. function __construct() {
  7297. $this->calendarComponent();
  7298. $this->attendee = '';
  7299. $this->comment = '';
  7300. $this->contact = '';
  7301. $this->dtend = '';
  7302. $this->dtstart = '';
  7303. $this->duration = '';
  7304. $this->freebusy = '';
  7305. $this->organizer = '';
  7306. $this->requeststatus = '';
  7307. $this->url = '';
  7308. $this->xprop = '';
  7309. }
  7310. /**
  7311. * create formatted output for calendar component VFREEBUSY object instance
  7312. *
  7313. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7314. * @since 2.3.1 - 2007-11-19
  7315. * @param array $xcaldecl
  7316. * @return string
  7317. */
  7318. function createComponent( &$xcaldecl ) {
  7319. $objectname = $this->_createFormat();
  7320. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7321. $component .= $this->createUid();
  7322. $component .= $this->createDtstamp();
  7323. $component .= $this->createAttendee();
  7324. $component .= $this->createComment();
  7325. $component .= $this->createContact();
  7326. $component .= $this->createDtstart();
  7327. $component .= $this->createDtend();
  7328. $component .= $this->createDuration();
  7329. $component .= $this->createFreebusy();
  7330. $component .= $this->createOrganizer();
  7331. $component .= $this->createRequestStatus();
  7332. $component .= $this->createUrl();
  7333. $component .= $this->createXprop();
  7334. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7335. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7336. foreach( $this->xcaldecl as $localxcaldecl )
  7337. $xcaldecl[] = $localxcaldecl;
  7338. }
  7339. return $component;
  7340. }
  7341. }
  7342. /*********************************************************************************/
  7343. /*********************************************************************************/
  7344. /**
  7345. * class for calendar component VALARM
  7346. *
  7347. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7348. * @since 2.5.1 - 2008-10-12
  7349. */
  7350. class valarm extends calendarComponent {
  7351. var $action;
  7352. var $attach;
  7353. var $attendee;
  7354. var $description;
  7355. var $duration;
  7356. var $repeat;
  7357. var $summary;
  7358. var $trigger;
  7359. var $xprop;
  7360. /**
  7361. * constructor for calendar component VALARM object
  7362. *
  7363. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7364. * @since 2.5.1 - 2008-10-31
  7365. */
  7366. function __construct() {
  7367. $this->calendarComponent();
  7368. $this->action = '';
  7369. $this->attach = '';
  7370. $this->attendee = '';
  7371. $this->description = '';
  7372. $this->duration = '';
  7373. $this->repeat = '';
  7374. $this->summary = '';
  7375. $this->trigger = '';
  7376. $this->xprop = '';
  7377. }
  7378. /**
  7379. * create formatted output for calendar component VALARM object instance
  7380. *
  7381. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7382. * @since 2.5.1 - 2008-10-22
  7383. * @param array $xcaldecl
  7384. * @return string
  7385. */
  7386. function createComponent( &$xcaldecl ) {
  7387. $objectname = $this->_createFormat();
  7388. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7389. $component .= $this->createAction();
  7390. $component .= $this->createAttach();
  7391. $component .= $this->createAttendee();
  7392. $component .= $this->createDescription();
  7393. $component .= $this->createDuration();
  7394. $component .= $this->createRepeat();
  7395. $component .= $this->createSummary();
  7396. $component .= $this->createTrigger();
  7397. $component .= $this->createXprop();
  7398. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7399. return $component;
  7400. }
  7401. }
  7402. /**********************************************************************************
  7403. /*********************************************************************************/
  7404. /**
  7405. * class for calendar component VTIMEZONE
  7406. *
  7407. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7408. * @since 2.5.1 - 2008-10-12
  7409. */
  7410. class vtimezone extends calendarComponent {
  7411. var $timezonetype;
  7412. var $comment;
  7413. var $dtstart;
  7414. var $lastmodified;
  7415. var $rdate;
  7416. var $rrule;
  7417. var $tzid;
  7418. var $tzname;
  7419. var $tzoffsetfrom;
  7420. var $tzoffsetto;
  7421. var $tzurl;
  7422. var $xprop;
  7423. // component subcomponents container
  7424. var $components;
  7425. /**
  7426. * constructor for calendar component VTIMEZONE object
  7427. *
  7428. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7429. * @since 2.5.1 - 2008-10-31
  7430. * @param string $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
  7431. */
  7432. function __construct($timezonetype=false) {
  7433. if (!$timezonetype) {
  7434. $this->timezonetype = 'VTIMEZONE';
  7435. } else {
  7436. $this->timezonetype = strtoupper( $timezonetype );
  7437. }
  7438. $this->calendarComponent();
  7439. $this->comment = '';
  7440. $this->dtstart = '';
  7441. $this->lastmodified = '';
  7442. $this->rdate = '';
  7443. $this->rrule = '';
  7444. $this->tzid = '';
  7445. $this->tzname = '';
  7446. $this->tzoffsetfrom = '';
  7447. $this->tzoffsetto = '';
  7448. $this->tzurl = '';
  7449. $this->xprop = '';
  7450. $this->components = array();
  7451. }
  7452. /**
  7453. * create formatted output for calendar component VTIMEZONE object instance
  7454. *
  7455. * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
  7456. * @since 2.5.1 - 2008-10-25
  7457. * @param array $xcaldecl
  7458. * @return string
  7459. */
  7460. function createComponent( &$xcaldecl ) {
  7461. $objectname = $this->_createFormat();
  7462. $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
  7463. $component .= $this->createTzid();
  7464. $component .= $this->createLastModified();
  7465. $component .= $this->createTzurl();
  7466. $component .= $this->createDtstart();
  7467. $component .= $this->createTzoffsetfrom();
  7468. $component .= $this->createTzoffsetto();
  7469. $component .= $this->createComment();
  7470. $component .= $this->createRdate();
  7471. $component .= $this->createRrule();
  7472. $component .= $this->createTzname();
  7473. $component .= $this->createXprop();
  7474. $component .= $this->createSubComponent();
  7475. $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
  7476. if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
  7477. foreach( $this->xcaldecl as $localxcaldecl )
  7478. $xcaldecl[] = $localxcaldecl;
  7479. }
  7480. return $component;
  7481. }
  7482. }