PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/auth/cas/CAS
/srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/auth/cas/CAS/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/auth/cas/CAS/client.php
<?php





/**


 * @file CAS/client.php


 * Main class of the phpCAS library


 */





// include internationalization stuff


include_once(dirname(__FILE__).'/languages/languages.php');





// include PGT storage classes


include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');





/**


 * @class CASClient


 * The CASClient class is a client interface that provides CAS authentication


 * to PHP applications.


 *


 * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>


 */





class CASClient


{





  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


  // XX                                                                    XX


  // XX                          CONFIGURATION                             XX


  // XX                                                                    XX


  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX





  // ########################################################################


  //  HTML OUTPUT


  // ########################################################################


  /**


   * @addtogroup internalOutput


   * @{


   */  


  


  /**


   * This method filters a string by replacing special tokens by appropriate values


   * and prints it. The corresponding tokens are taken into account:


   * - __CAS_VERSION__


   * - __PHPCAS_VERSION__


   * - __SERVER_BASE_URL__


   *


   * Used by CASClient::PrintHTMLHeader() and CASClient::printHTMLFooter().


   *


   * @param $str the string to filter and output


   *


   * @private


   */


  function HTMLFilterOutput($str)


    {


      $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);


      $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);


      $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);


      echo $str;


    }





  /**


   * A string used to print the header of HTML pages. Written by CASClient::setHTMLHeader(),


   * read by CASClient::printHTMLHeader().


   *


   * @hideinitializer


   * @private


   * @see CASClient::setHTMLHeader, CASClient::printHTMLHeader()


   */


  var $_output_header = '';


  


  /**


   * This method prints the header of the HTML output (after filtering). If


   * CASClient::setHTMLHeader() was not used, a default header is output.


   *


   * @param $title the title of the page


   *


   * @see HTMLFilterOutput()


   * @private


   */


  function printHTMLHeader($title)


    {


      $this->HTMLFilterOutput(str_replace('__TITLE__',


					  $title,


					  (empty($this->_output_header)


					   ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'


					   : $this->_output_header)


					  )


			      );


    }





  /**


   * A string used to print the footer of HTML pages. Written by CASClient::setHTMLFooter(),


   * read by printHTMLFooter().


   *


   * @hideinitializer


   * @private


   * @see CASClient::setHTMLFooter, CASClient::printHTMLFooter()


   */


  var $_output_footer = '';


  


  /**


   * This method prints the footer of the HTML output (after filtering). If


   * CASClient::setHTMLFooter() was not used, a default footer is output.


   *


   * @see HTMLFilterOutput()


   * @private


   */


  function printHTMLFooter()


    {


      $this->HTMLFilterOutput(empty($this->_output_footer)


			      ?('<hr><address>phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>')


			      :$this->_output_footer);


    }





  /**


   * This method set the HTML header used for all outputs.


   *


   * @param $header the HTML header.


   *


   * @public


   */


  function setHTMLHeader($header)


    {


      $this->_output_header = $header;


    }





  /**


   * This method set the HTML footer used for all outputs.


   *


   * @param $footer the HTML footer.


   *


   * @public


   */


  function setHTMLFooter($footer)


    {


      $this->_output_footer = $footer;


    }





  /** @} */


  // ########################################################################


  //  INTERNATIONALIZATION


  // ########################################################################


  /**


   * @addtogroup internalLang


   * @{


   */  


  /**


   * A string corresponding to the language used by phpCAS. Written by 


   * CASClient::setLang(), read by CASClient::getLang().





   * @note debugging information is always in english (debug purposes only).


   *


   * @hideinitializer


   * @private


   * @sa CASClient::_strings, CASClient::getString()


   */


  var $_lang = '';


  


  /**


   * This method returns the language used by phpCAS.


   *


   * @return a string representing the language


   *


   * @private


   */


  function getLang()


    {


      if ( empty($this->_lang) )


	$this->setLang(PHPCAS_LANG_DEFAULT);


      return $this->_lang;


    }





  /**


   * array containing the strings used by phpCAS. Written by CASClient::setLang(), read by 


   * CASClient::getString() and used by CASClient::setLang().


   *


   * @note This array is filled by instructions in CAS/languages/<$this->_lang>.php


   *


   * @private


   * @see CASClient::_lang, CASClient::getString(), CASClient::setLang(), CASClient::getLang()


   */


  var $_strings;





  /**


   * This method returns a string depending on the language.


   *


   * @param $str the index of the string in $_string.


   *


   * @return the string corresponding to $index in $string.


   *


   * @private


   */


  function getString($str)


    {


      // call CASclient::getLang() to be sure the language is initialized


      $this->getLang();


      


      if ( !isset($this->_strings[$str]) ) {


	trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);


      }


      return $this->_strings[$str];


    }





  /**


   * This method is used to set the language used by phpCAS. 


   * @note Can be called only once.


   *


   * @param $lang a string representing the language.


   *


   * @public


   * @sa CAS_LANG_FRENCH, CAS_LANG_ENGLISH


   */


  function setLang($lang)


    {


      // include the corresponding language file


      include_once(dirname(__FILE__).'/languages/'.$lang.'.php');





      if ( !is_array($this->_strings) ) {


	trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);


      }


      $this->_lang = $lang;


    }





  /** @} */


  // ########################################################################


  //  CAS SERVER CONFIG


  // ########################################################################


  /**


   * @addtogroup internalConfig


   * @{


   */  


  


  /**


   * a record to store information about the CAS server.


   * - $_server["version"]: the version of the CAS server


   * - $_server["hostname"]: the hostname of the CAS server


   * - $_server["port"]: the port the CAS server is running on


   * - $_server["uri"]: the base URI the CAS server is responding on


   * - $_server["base_url"]: the base URL of the CAS server


   * - $_server["login_url"]: the login URL of the CAS server


   * - $_server["service_validate_url"]: the service validating URL of the CAS server


   * - $_server["proxy_url"]: the proxy URL of the CAS server


   * - $_server["proxy_validate_url"]: the proxy validating URL of the CAS server


   * - $_server["logout_url"]: the logout URL of the CAS server


   *


   * $_server["version"], $_server["hostname"], $_server["port"] and $_server["uri"]


   * are written by CASClient::CASClient(), read by CASClient::getServerVersion(), 


   * CASClient::getServerHostname(), CASClient::getServerPort() and CASClient::getServerURI().


   *


   * The other fields are written and read by CASClient::getServerBaseURL(), 


   * CASClient::getServerLoginURL(), CASClient::getServerServiceValidateURL(), 


   * CASClient::getServerProxyValidateURL() and CASClient::getServerLogoutURL().


   *


   * @hideinitializer


   * @private


   */


  var $_server = array(


		       'version' => -1,


		       'hostname' => 'none',


		       'port' => -1,


		       'uri' => 'none'


		       );


  


  /**


   * This method is used to retrieve the version of the CAS server.


   * @return the version of the CAS server.


   * @private


   */


  function getServerVersion()


    { 


      return $this->_server['version']; 


    }





  /**


   * This method is used to retrieve the hostname of the CAS server.


   * @return the hostname of the CAS server.


   * @private


   */


  function getServerHostname()


    { return $this->_server['hostname']; }





  /**


   * This method is used to retrieve the port of the CAS server.


   * @return the port of the CAS server.


   * @private


   */


  function getServerPort()


    { return $this->_server['port']; }





  /**


   * This method is used to retrieve the URI of the CAS server.


   * @return a URI.


   * @private


   */


  function getServerURI()


    { return $this->_server['uri']; }





  /**


   * This method is used to retrieve the base URL of the CAS server.


   * @return a URL.


   * @private


   */


  function getServerBaseURL()


    { 


      // the URL is build only when needed


      if ( empty($this->_server['base_url']) ) {


	$this->_server['base_url'] = 'https://'


	  .$this->getServerHostname()


	  .':'


	  .$this->getServerPort()


	  .$this->getServerURI();


      }


      return $this->_server['base_url']; 


    }





  /**


   * This method is used to retrieve the login URL of the CAS server.


   * @param $gateway true to check authentication, false to force it


   * @return a URL.


   * @private


   */


  function getServerLoginURL($gateway=false)


    { 


      phpCAS::traceBegin();


      // the URL is build only when needed


      if ( empty($this->_server['login_url']) ) {


        $this->_server['login_url'] = $this->getServerBaseURL();


        $this->_server['login_url'] .= 'login?service=';


//        $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL());


        $this->_server['login_url'] .= urlencode($this->getURL());


        if ($gateway) {


          $this->_server['login_url'] .= '&gateway=true';


        }


      }


      phpCAS::traceEnd($this->_server['login_url']);


      return $this->_server['login_url']; 


    }





  /**


   * This method sets the login URL of the CAS server.


   * @param $url the login URL


   * @private


   * @since 0.4.21 by Wyman Chan


   */


  function setServerLoginURL($url)


    {


      return $this->_server['login_url'] = $url;


    }





  /**


   * This method is used to retrieve the service validating URL of the CAS server.


   * @return a URL.


   * @private


   */


  function getServerServiceValidateURL()


    { 


      // the URL is build only when needed


      if ( empty($this->_server['service_validate_url']) ) {


	switch ($this->getServerVersion()) {


	case CAS_VERSION_1_0:


	  $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';


	  break;


	case CAS_VERSION_2_0:


	  $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';


	  break;


	}


      }


//      return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 


      return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); 


    }





  /**


   * This method is used to retrieve the proxy validating URL of the CAS server.


   * @return a URL.


   * @private


   */


  function getServerProxyValidateURL()


    { 


      // the URL is build only when needed


      if ( empty($this->_server['proxy_validate_url']) ) {


	switch ($this->getServerVersion()) {


	case CAS_VERSION_1_0:


	  $this->_server['proxy_validate_url'] = '';


	  break;


	case CAS_VERSION_2_0:


	  $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';


	  break;


	}


      }


//      return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 


      return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); 


    }





  /**


   * This method is used to retrieve the proxy URL of the CAS server.


   * @return a URL.


   * @private


   */


  function getServerProxyURL()


    { 


      // the URL is build only when needed


      if ( empty($this->_server['proxy_url']) ) {


	switch ($this->getServerVersion()) {


	case CAS_VERSION_1_0:


	  $this->_server['proxy_url'] = '';


	  break;


	case CAS_VERSION_2_0:


	  $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';


	  break;


	}


      }


      return $this->_server['proxy_url']; 


    }





  /**


   * This method is used to retrieve the logout URL of the CAS server.


   * @return a URL.


   * @private


   */


  function getServerLogoutURL()


    { 


      // the URL is build only when needed


      if ( empty($this->_server['logout_url']) ) {


	$this->_server['logout_url'] = $this->getServerBaseURL().'logout';


      }


      return $this->_server['logout_url']; 


    }





  /**


   * This method sets the logout URL of the CAS server.


   * @param $url the logout URL


   * @private


   * @since 0.4.21 by Wyman Chan


   */


  function setServerLogoutURL($url)


    {


      return $this->_server['logout_url'] = $url;


    }





  /**


   * This method checks to see if the request is secured via HTTPS


   * @return true if https, false otherwise


   * @private


   */


  function isHttps() {


    //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) {


    //0.4.24 by Hinnack


    if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {


      return true;


    } else {


      return false;


    }


  }





  // ########################################################################


  //  CONSTRUCTOR


  // ########################################################################


   /**


    * CASClient constructor.


    *


    * @param $server_version the version of the CAS server


    * @param $proxy TRUE if the CAS client is a CAS proxy, FALSE otherwise


    * @param $server_hostname the hostname of the CAS server


    * @param $server_port the port the CAS server is running on


    * @param $server_uri the URI the CAS server is responding on


    * @param $start_session Have phpCAS start PHP sessions (default true)


    *


    * @return a newly created CASClient object


    *


    * @public


    */


  function CASClient(


  	$server_version,


	$proxy,


	$server_hostname,


	$server_port,


	$server_uri,


	$start_session = true) {





    phpCAS::traceBegin();





    //activate session mechanism if desired


    if ($start_session) {


      session_start();


    }





    $this->_proxy = $proxy;





    //check version


    switch ($server_version) {


      case CAS_VERSION_1_0:


        if ( $this->isProxy() )


          phpCAS::error('CAS proxies are not supported in CAS '


              .$server_version);


        break;


      case CAS_VERSION_2_0:


        break;


      default:


        phpCAS::error('this version of CAS (`'


            .$server_version


            .'\') is not supported by phpCAS '


            .phpCAS::getVersion());


    }


    $this->_server['version'] = $server_version;





    //check hostname


    if ( empty($server_hostname) 


        || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {


      phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');


    }


    $this->_server['hostname'] = $server_hostname;





    //check port


    if ( $server_port == 0 


        || !is_int($server_port) ) {


      phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');


    }


    $this->_server['port'] = $server_port;





    //check URI


    if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {


      phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');


    }


    //add leading and trailing `/' and remove doubles      


    $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');


    $this->_server['uri'] = $server_uri;





    //set to callback mode if PgtIou and PgtId CGI GET parameters are provided 


    if ( $this->isProxy() ) {


      $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));


    }





    if ( $this->isCallbackMode() ) {


      //callback mode: check that phpCAS is secured


      if ( !$this->isHttps() ) {


        phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');


      }


    } else {


      //normal mode: get ticket and remove it from CGI parameters for developpers


      $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);


      switch ($this->getServerVersion()) {


        case CAS_VERSION_1_0: // check for a Service Ticket


          if( preg_match('/^ST-/',$ticket) ) {


            phpCAS::trace('ST \''.$ticket.'\' found');


            //ST present


            $this->setST($ticket);


            //ticket has been taken into account, unset it to hide it to applications


            unset($_GET['ticket']);


          } else if ( !empty($ticket) ) {


            //ill-formed ticket, halt


            phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');


          }


          break;


        case CAS_VERSION_2_0: // check for a Service or Proxy Ticket


          if( preg_match('/^[SP]T-/',$ticket) ) {


            phpCAS::trace('ST or PT \''.$ticket.'\' found');


            $this->setPT($ticket);


            unset($_GET['ticket']);


          } else if ( !empty($ticket) ) {


            //ill-formed ticket, halt


            phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');


          } 


          break;


        }


	}


    phpCAS::traceEnd();


  }





  /** @} */





  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


  // XX                                                                    XX


  // XX                           AUTHENTICATION                           XX


  // XX                                                                    XX


  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX





  /**


   * @addtogroup internalAuthentication


   * @{


   */  


  


  /**


   * The Authenticated user. Written by CASClient::setUser(), read by CASClient::getUser().


   * @attention client applications should use phpCAS::getUser().


   *


   * @hideinitializer


   * @private


   */


  var $_user = '';


  


  /**


   * This method sets the CAS user's login name.


   *


   * @param $user the login name of the authenticated user.


   *


   * @private


   */


  function setUser($user)


    {


      $this->_user = $user;


    }





  /**


   * This method returns the CAS user's login name.


   * @warning should be called only after CASClient::forceAuthentication() or 


   * CASClient::isAuthenticated(), otherwise halt with an error.


   *


   * @return the login name of the authenticated user


   */


  function getUser()


    {


      if ( empty($this->_user) ) {


	phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');


      }


      return $this->_user;


    }





  /**


   * This method is called to be sure that the user is authenticated. When not 


   * authenticated, halt by redirecting to the CAS server; otherwise return TRUE.


   * @return TRUE when the user is authenticated; otherwise halt.


   * @public


   */


  function forceAuthentication()


    {


      phpCAS::traceBegin();





      if ( $this->isAuthenticated() ) {


        // the user is authenticated, nothing to be done.


	    phpCAS::trace('no need to authenticate');


	    $res = TRUE;





      } else {


	    // the user is not authenticated, redirect to the CAS server


        unset($_SESSION['phpCAS']['auth_checked']);


	    $this->redirectToCas(FALSE/* no gateway */);	


	    // never reached


	    $res = FALSE;


      }


      phpCAS::traceEnd($res);


      return $res;


    }





  /**


   * An integer that gives the number of times authentication will be cached before rechecked.


   *


   * @hideinitializer


   * @private


   */


  var $_cache_times_for_auth_recheck = 0;


  


  /**


   * Set the number of times authentication will be cached before rechecked.


   *


   * @param $n an integer.


   *


   * @public


   */


  function setCacheTimesForAuthRequest($n)


    {


      $this->_cache_times_for_auth_recheck = n;


    }





  /**


   * This method is called to check whether the user is authenticated or not.


   * @return TRUE when the user is authenticated, FALSE otherwise.


   * @public


   */


  function checkAuthentication()


    {


      phpCAS::traceBegin();





      if ( $this->isAuthenticated() ) {


	    phpCAS::trace('user is authenticated');


	    $res = TRUE;


      } else if (isset($_SESSION['phpCAS']['auth_checked'])) {


        // the previous request has redirected the client to the CAS server with gateway=true


        unset($_SESSION['phpCAS']['auth_checked']);


        $res = FALSE;


      } else {


//        $_SESSION['phpCAS']['auth_checked'] = true;


//	    $this->redirectToCas(TRUE/* gateway */);	


//	    // never reached


//	    $res = FALSE;


        // avoid a check against CAS on every request


        if (! isset($_SESSION['phpCAS']['unauth_count']) )


           $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized


        


        if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) 


          || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))


        {


           $res = FALSE;


           


           if ($this->_cache_times_for_auth_recheck != -1)


           {


		   	  $_SESSION['phpCAS']['unauth_count']++;


           	  phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');


           }


           else


           {


           	  phpCAS::trace('user is not authenticated (cached for until login pressed)');


           }


        }


        else


        {


         	$_SESSION['phpCAS']['unauth_count'] = 0;


            $_SESSION['phpCAS']['auth_checked'] = true;


            phpCAS::trace('user is not authenticated (cache reset)');


    	    $this->redirectToCas(TRUE/* gateway */);	


    	    // never reached


    	    $res = FALSE;


        }


      }


      phpCAS::traceEnd($res);


      return $res;


    }


  


  /**


   * This method is called to check if the user is authenticated (previously or by


   * tickets given in the URL).


   *


   * @return TRUE when the user is authenticated.


   *


   * @public


   */


  function isAuthenticated()


  {


      phpCAS::traceBegin();


      $res = FALSE;


      $validate_url = '';





      if ( $this->wasPreviouslyAuthenticated() ) {


	  	 // the user has already (previously during the session) been 


		 // authenticated, nothing to be done.


    	phpCAS::trace('user was already authenticated, no need to look for tickets');


    	$res = TRUE;


      } 


	  elseif ( $this->hasST() ) {


    	// if a Service Ticket was given, validate it


    	phpCAS::trace('ST `'.$this->getST().'\' is present');


    	$this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts


    	phpCAS::trace('ST `'.$this->getST().'\' was validated');


    	if ( $this->isProxy() ) {


		   $this->validatePGT($validate_url,$text_response,$tree_response); // idem


		   phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');


		   $_SESSION['phpCAS']['pgt'] = $this->getPGT();


		}


		$_SESSION['phpCAS']['user'] = $this->getUser();


		$res = TRUE;


	}


	elseif ( $this->hasPT() ) {


		// if a Proxy Ticket was given, validate it


		phpCAS::trace('PT `'.$this->getPT().'\' is present');


		$this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts


		phpCAS::trace('PT `'.$this->getPT().'\' was validated');





		if ( $this->isProxy() ) {





		   $this->validatePGT($validate_url,$text_response,$tree_response); // idem


		   phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');


		   $_SESSION['phpCAS']['pgt'] = $this->getPGT();


		}


    	$_SESSION['phpCAS']['user'] = $this->getUser();


		$res = TRUE;


	} 


	else {


    	// no ticket given, not authenticated


    	phpCAS::trace('no ticket found');


	}





	phpCAS::traceEnd($res);


	return $res;


  }


  


  /**


   * This method tells if the current session is authenticated.


   * @return true if authenticated based soley on $_SESSION variable


   * @since 0.4.22 by Brendan Arnold


   */


  function isSessionAuthenticated ()


    {


      return !empty($_SESSION['phpCAS']['user']);


    }





  /**


   * This method tells if the user has already been (previously) authenticated


   * by looking into the session variables.


   *


   * @note This function switches to callback mode when needed.


   *


   * @return TRUE when the user has already been authenticated; FALSE otherwise.


   *


   * @private


   */


  function wasPreviouslyAuthenticated()


    {


      phpCAS::traceBegin();





      if ( $this->isCallbackMode() ) {





	$this->callback();


      }





      $auth = FALSE;





      if ( $this->isProxy() ) {


	// CAS proxy: username and PGT must be present


	if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {


	  // authentication already done


	  $this->setUser($_SESSION['phpCAS']['user']);


	  $this->setPGT($_SESSION['phpCAS']['pgt']);


	  phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); 


	  $auth = TRUE;


	} elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {


	  // these two variables should be empty or not empty at the same time


	  phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');


	  // unset all tickets to enforce authentication


	  unset($_SESSION['phpCAS']);


	  $this->setST('');


	  $this->setPT('');


	} elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {


	  // these two variables should be empty or not empty at the same time


	  phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); 


	  // unset all tickets to enforce authentication


	  unset($_SESSION['phpCAS']);


	  $this->setST('');


	  $this->setPT('');


	} else {


	  phpCAS::trace('neither user not PGT found'); 


	}


      } else {


	// `simple' CAS client (not a proxy): username must be present


	if ( $this->isSessionAuthenticated() ) {


	  // authentication already done


	  $this->setUser($_SESSION['phpCAS']['user']);


	  phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); 


	  $auth = TRUE;


	} else {


	  phpCAS::trace('no user found');


	}


      }


      


      phpCAS::traceEnd($auth);


      return $auth;


    }


  


  /**


   * This method is used to redirect the client to the CAS server.


   * It is used by CASClient::forceAuthentication() and CASClient::checkAuthentication().


   * @param $gateway true to check authentication, false to force it


   * @public


   */


  function redirectToCas($gateway=false)


    {


      phpCAS::traceBegin();


      $cas_url = $this->getServerLoginURL($gateway);


      header('Location: '.$cas_url);


      $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));


      printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);


      $this->printHTMLFooter();


      phpCAS::traceExit();


      exit();


    }


  


  /**


   * This method is used to logout from CAS.


   * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out)


   * @public


   */


  function logout($url = "")


    {


      phpCAS::traceBegin();


      $cas_url = $this->getServerLogoutURL();


      // v0.4.14 sebastien.gougeon at univ-rennes1.fr


      // header('Location: '.$cas_url);


      if ( $url != "" ) {


        $url = '?service=' . $url;


      }


      header('Location: '.$cas_url . $url);


      session_unset();


      session_destroy();


      $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));


      printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);


      $this->printHTMLFooter();


      phpCAS::traceExit();


      exit();


    }


  


  /** @} */





  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


  // XX                                                                    XX


  // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX


  // XX                                                                    XX


  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX





  // ########################################################################


  //  ST


  // ########################################################################


  /**


   * @addtogroup internalBasic


   * @{


   */  


  


  /**


   * the Service Ticket provided in the URL of the request if present


   * (empty otherwise). Written by CASClient::CASClient(), read by 


   * CASClient::getST() and CASClient::hasPGT().


   *


   * @hideinitializer


   * @private


   */


  var $_st = '';


  


  /**


   * This method returns the Service Ticket provided in the URL of the request.


   * @return The service ticket.


   * @private


   */


  function getST()


    { return $this->_st; }





  /**


   * This method stores the Service Ticket.


   * @param $st The Service Ticket.


   * @private


   */


  function setST($st)


    { $this->_st = $st; }





  /**


   * This method tells if a Service Ticket was stored.


   * @return TRUE if a Service Ticket has been stored.


   * @private


   */


  function hasST()


    { return !empty($this->_st); }





  /** @} */





  // ########################################################################


  //  ST VALIDATION


  // ########################################################################


  /**


   * @addtogroup internalBasic


   * @{


   */  





  /**


   * This method is used to validate a ST; halt on failure, and sets $validate_url,


   * $text_reponse and $tree_response on success. These parameters are used later


   * by CASClient::validatePGT() for CAS proxies.


   * 


   * @param $validate_url the URL of the request to the CAS server.


   * @param $text_response the response of the CAS server, as is (XML text).


   * @param $tree_response the response of the CAS server, as a DOM XML tree.


   *


   * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().


   *


   * @private


   */


  function validateST($validate_url,&$text_response,&$tree_response)


    {


      phpCAS::traceBegin();


      // build the URL to validate the ticket


      $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();


      if ( $this->isProxy() ) {


	  	 // pass the callback url for CAS proxies


		 $validate_url .= '&pgtUrl='.$this->getCallbackURL();


      }





      // open and read the URL


      if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {


	phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');


	$this->authError('ST not validated',


			 $validate_url,


			 TRUE/*$no_response*/);


      }





      // analyze the result depending on the version


      switch ($this->getServerVersion()) {


      case CAS_VERSION_1_0:


	if (preg_match('/^no\n/',$text_response)) {


	  phpCAS::trace('ST has not been validated');


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       FALSE/*$bad_response*/,


		       $text_response);


	}


	if (!preg_match('/^yes\n/',$text_response)) {


	  phpCAS::trace('ill-formed response');


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       TRUE/*$bad_response*/,


		       $text_response);


	}


	// ST has been validated, extract the user name


	$arr = preg_split('/\n/',$text_response);


	$this->setUser(trim($arr[1]));


	break;


      case CAS_VERSION_2_0:


	// read the response of the CAS server into a DOM object


	if ( !($dom = domxml_open_mem($text_response))) {


	  phpCAS::trace('domxml_open_mem() failed');


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       TRUE/*$bad_response*/,


		       $text_response);


	}


	// read the root node of the XML tree


	if ( !($tree_response = $dom->document_element()) ) {


	  phpCAS::trace('document_element() failed');


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       TRUE/*$bad_response*/,


		       $text_response);


	}


	// insure that tag name is 'serviceResponse'


	if ( $tree_response->node_name() != 'serviceResponse' ) {


	  phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       TRUE/*$bad_response*/,


		       $text_response);


	}


	if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {


	  // authentication succeded, extract the user name


	  if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {


	    phpCAS::trace('<authenticationSuccess> found, but no <user>');


	    $this->authError('ST not validated',


			 $validate_url,


			 FALSE/*$no_response*/,


			 TRUE/*$bad_response*/,


			 $text_response);


	  }


	  $user = trim($user_elements[0]->get_content());


	  phpCAS::trace('user = `'.$user);


	  $this->setUser($user);


	  


	} else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {


	  phpCAS::trace('<authenticationFailure> found');


	  // authentication failed, extract the error code and message


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       FALSE/*$bad_response*/,


		       $text_response,


		       $failure_elements[0]->get_attribute('code')/*$err_code*/,


		       trim($failure_elements[0]->get_content())/*$err_msg*/);


	} else {


	  phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');


	  $this->authError('ST not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       TRUE/*$bad_response*/,


		       $text_response);


	}


	break;


      }


      


      // at this step, ST has been validated and $this->_user has been set,


      phpCAS::traceEnd(TRUE);


      return TRUE;


    }





  /** @} */





  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


  // XX                                                                    XX


  // XX                     PROXY FEATURES (CAS 2.0)                       XX


  // XX                                                                    XX


  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX





  // ########################################################################


  //  PROXYING


  // ########################################################################


  /**


   * @addtogroup internalProxy


   * @{


   */





  /**


   * A boolean telling if the client is a CAS proxy or not. Written by CASClient::CASClient(), 


   * read by CASClient::isProxy().


   *


   * @private


   */


  var $_proxy;


  


  /**


   * Tells if a CAS client is a CAS proxy or not


   *


   * @return TRUE when the CAS client is a CAs proxy, FALSE otherwise


   *


   * @private


   */


  function isProxy()


    {


      return $this->_proxy;


    }





  /** @} */


  // ########################################################################


  //  PGT


  // ########################################################################


  /**


   * @addtogroup internalProxy


   * @{


   */  


  


  /**


   * the Proxy Grnting Ticket given by the CAS server (empty otherwise). 


   * Written by CASClient::setPGT(), read by CASClient::getPGT() and CASClient::hasPGT().


   *


   * @hideinitializer


   * @private


   */


  var $_pgt = '';


  


  /**


   * This method returns the Proxy Granting Ticket given by the CAS server.


   * @return The Proxy Granting Ticket.


   * @private


   */


  function getPGT()


    { return $this->_pgt; }





  /**


   * This method stores the Proxy Granting Ticket.


   * @param $pgt The Proxy Granting Ticket.


   * @private


   */


  function setPGT($pgt)


    { $this->_pgt = $pgt; }





  /**


   * This method tells if a Proxy Granting Ticket was stored.


   * @return TRUE if a Proxy Granting Ticket has been stored.


   * @private


   */


  function hasPGT()


    { return !empty($this->_pgt); }





  /** @} */





  // ########################################################################


  //  CALLBACK MODE


  // ########################################################################


  /**


   * @addtogroup internalCallback


   * @{


   */  


  /**


   * each PHP script using phpCAS in proxy mode is its own callback to get the


   * PGT back from the CAS server. callback_mode is detected by the constructor


   * thanks to the GET parameters.


   */





  /**


   * a boolean to know if the CAS client is running in callback mode. Written by


   * CASClient::setCallBackMode(), read by CASClient::isCallbackMode().


   *


   * @hideinitializer


   * @private


   */


  var $_callback_mode = FALSE;


  


  /**


   * This method sets/unsets callback mode.


   *


   * @param $callback_mode TRUE to set callback mode, FALSE otherwise.


   *


   * @private


   */


  function setCallbackMode($callback_mode)


    {


      $this->_callback_mode = $callback_mode;


    }





  /**


   * This method returns TRUE when the CAs client is running i callback mode, 


   * FALSE otherwise.


   *


   * @return A boolean.


   *


   * @private


   */


  function isCallbackMode()


    {


      return $this->_callback_mode;


    }





  /**


   * the URL that should be used for the PGT callback (in fact the URL of the 


   * current request without any CGI parameter). Written and read by 


   * CASClient::getCallbackURL().


   *


   * @hideinitializer


   * @private


   */


  var $_callback_url = '';





  /**


   * This method returns the URL that should be used for the PGT callback (in


   * fact the URL of the current request without any CGI parameter, except if


   * phpCAS::setFixedCallbackURL() was used).


   *


   * @return The callback URL


   *


   * @private


   */


  function getCallbackURL()


    {


      // the URL is built when needed only


      if ( empty($this->_callback_url) ) {


        $final_uri = '';


	    // remove the ticket if present in the URL


	    $final_uri = 'https://';


	    /* replaced by Julien Marchal - v0.4.6


	     * $this->uri .= $_SERVER['SERVER_NAME'];


	     */


        if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){


          /* replaced by teedog - v0.4.12


           * $final_uri .= $_SERVER['SERVER_NAME'];


           */


          if (empty($_SERVER['SERVER_NAME'])) {


            $final_uri .= $_SERVER['HTTP_HOST'];


          } else {


            $final_uri .= $_SERVER['SERVER_NAME'];


          }


        } else {


          $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];


        }


	    if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)


	       || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {


	      $final_uri .= ':';


	      $final_uri .= $_SERVER['SERVER_PORT'];


	    }


	    $request_uri = $_SERVER['REQUEST_URI'];


	    $request_uri = preg_replace('/\?.*$/','',$request_uri);


	    $final_uri .= $request_uri;


	    $this->setCallbackURL($final_uri);


      }


      return $this->_callback_url;


    }





  /**


   * This method sets the callback url.


   *


   * @param $callback_url url to set callback 


   *


   * @private


   */


  function setCallbackURL($url)


    {


      return $this->_callback_url = $url;


    }





  /**


   * This method is called by CASClient::CASClient() when running in callback


   * mode. It stores the PGT and its PGT Iou, prints its output and halts.


   *


   * @private


   */


  function callback()


    {


      phpCAS::traceBegin();


      $this->printHTMLHeader('phpCAS callback');


      $pgt_iou = $_GET['pgtIou'];


      $pgt = $_GET['pgtId'];


      phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');


      echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';


      $this->storePGT($pgt,$pgt_iou);


      $this->printHTMLFooter();


      phpCAS::traceExit();


    }





  /** @} */





  // ########################################################################


  //  PGT STORAGE


  // ########################################################################


  /**


   * @addtogroup internalPGTStorage


   * @{


   */  


    


  /**


   * an instance of a class inheriting of PGTStorage, used to deal with PGT


   * storage. Created by CASClient::setPGTStorageFile() or CASClient::setPGTStorageDB(), used 


   * by CASClient::setPGTStorageFile(), CASClient::setPGTStorageDB() and CASClient::initPGTStorage().


   *


   * @hideinitializer


   * @private


   */


  var $_pgt_storage = null;





  /**


   * This method is used to initialize the storage of PGT's.


   * Halts on error.


   *


   * @private


   */


  function initPGTStorage()


    {


      // if no SetPGTStorageXxx() has been used, default to file


      if ( !is_object($this->_pgt_storage) ) {


	$this->setPGTStorageFile();


      }





      // initializes the storage


      $this->_pgt_storage->init();


    }


  


  /**


   * This method stores a PGT. Halts on error.


   *


   * @param $pgt the PGT to store


   * @param $pgt_iou its corresponding Iou


   *


   * @private


   */


  function storePGT($pgt,$pgt_iou)


    {


      // ensure that storage is initialized


      $this->initPGTStorage();





      // writes the PGT


      $this->_pgt_storage->write($pgt,$pgt_iou);


    }


  


  /**


   * This method reads a PGT from its Iou and deletes the corresponding storage entry.


   *


   * @param $pgt_iou the PGT Iou


   *


   * @return The PGT corresponding to the Iou, FALSE when not found.


   *


   * @private


   */


  function loadPGT($pgt_iou)


    {


      // ensure that storage is initialized


      $this->initPGTStorage();





      // read the PGT


      return $this->_pgt_storage->read($pgt_iou);


    }


  


  /**


   * This method is used to tell phpCAS to store the response of the


   * CAS server to PGT requests onto the filesystem. 


   *


   * @param $format the format used to store the PGT's (`plain' and `xml' allowed)


   * @param $path the path where the PGT's should be stored


   *


   * @public


   */


  function setPGTStorageFile($format='',


			     $path='')


    {


      // check that the storage has not already been set


      if ( is_object($this->_pgt_storage) ) {


	phpCAS::error('PGT storage already defined');


      }





      // create the storage object


      $this->_pgt_storage = &new PGTStorageFile($this,$format,$path);


    }


  


  /**


   * This method is used to tell phpCAS to store the response of the


   * CAS server to PGT requests into a database. 


   * @note The connection to the database is done only when needed. 


   * As a consequence, bad parameters are detected only when 


   * initializing PGT storage.


   *


   * @param $user the user to access the data with


   * @param $password the user's password


   * @param $database_type the type of the database hosting the data


   * @param $hostname the server hosting the database


   * @param $port the port the server is listening on


   * @param $database the name of the database


   * @param $table the name of the table storing the data


   *


   * @public


   */


  function setPGTStorageDB($user,


			   $password,


			   $database_type,


			   $hostname,


			   $port,


			   $database,


			   $table)


    {


      // check that the storage has not already been set


      if ( is_object($this->_pgt_storage) ) {


	phpCAS::error('PGT storage already defined');


      }





      // warn the user that he should use file storage...


      trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);





      // create the storage object


      $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);


    }


  


  // ########################################################################


  //  PGT VALIDATION


  // ########################################################################


  /**


   * This method is used to validate a PGT; halt on failure.


   * 


   * @param $validate_url the URL of the request to the CAS server.


   * @param $text_response the response of the CAS server, as is (XML text); result


   * of CASClient::validateST() or CASClient::validatePT().


   * @param $tree_response the response of the CAS server, as a DOM XML tree; result


   * of CASClient::validateST() or CASClient::validatePT().


   *


   * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().


   *


   * @private


   */


  function validatePGT(&$validate_url,$text_response,$tree_response)


    {


      phpCAS::traceBegin();


      if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {


	phpCAS::trace('<proxyGrantingTicket> not found');


	// authentication succeded, but no PGT Iou was transmitted


	$this->authError('Ticket validated but no PGT Iou transmitted',


		     $validate_url,


		     FALSE/*$no_response*/,


		     FALSE/*$bad_response*/,


		     $text_response);


      } else {


	// PGT Iou transmitted, extract it


	$pgt_iou = trim($arr[0]->get_content());


	$pgt = $this->loadPGT($pgt_iou);


	if ( $pgt == FALSE ) {





	  phpCAS::trace('could not load PGT');





	  $this->authError('PGT Iou was transmitted but PGT could not be retrieved',


		       $validate_url,


		       FALSE/*$no_response*/,


		       FALSE/*$bad_response*/,


		       $text_response);








	}


	$this->setPGT($pgt);


      }


      phpCAS::traceEnd(TRUE);


      return TRUE;


    }





  // ########################################################################


  //  PGT VALIDATION


  // ########################################################################





  /**


   * This method is used to retrieve PT's from the CAS server thanks to a PGT.


   * 


   * @param $target_service the service to ask for with the PT.


   * @param $err_code an error code (PHPCAS_SERVICE_OK on success).


   * @param $err_msg an error message (empty on success).


   *


   * @return a Proxy Ticket, or FALSE on error.


   *


   * @private


   */


  function retrievePT($target_service,&$err_code,&$err_msg)


    {


      phpCAS::traceBegin();





      // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is


      // set to false and $err_msg to an error message. At the end, if $pt is FALSE 


      // and $error_msg is still empty, it is set to 'invalid response' (the most


      // commonly encountered error).


      $err_msg = '';





      // build the URL to retrieve the PT


//      $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT();


      $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();





      // open and read the URL


      if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) {


	phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');


	$err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;


	$err_msg = 'could not retrieve PT (no response from the CAS server)';


	phpCAS::traceEnd(FALSE);


	return FALSE;


      }





      $bad_response = FALSE;





      if ( !$bad_response ) {


	// read the response of the CAS server into a DOM object


	if ( !($dom = @domxml_open_mem($cas_response))) {


	  phpCAS::trace('domxml_open_mem() failed');


	  // read failed


	  $bad_response = TRUE;


	} 


      }





      if ( !$bad_response ) {


	// read the root node of the XML tree


	if ( !($root = $dom->document_element()) ) {


	  phpCAS::trace('document_element() failed');


	  // read failed


	  $bad_response = TRUE;


	} 


      }





      if ( !$bad_response ) {


	// insure that tag name is 'serviceResponse'


	if ( $root->node_name() != 'serviceResponse' ) {


	  phpCAS::trace('node_name() failed');


	  // bad root node


	  $bad_response = TRUE;


	} 


      }





      if ( !$bad_response ) {


	// look for a proxySuccess tag


	if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {


	  // authentication succeded, look for a proxyTicket tag


	  if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {


	    $err_code = PHPCAS_SERVICE_OK;


	    $err_msg = '';


        phpCAS::trace('original PT: '.trim($arr[0]->get_content()));


        $pt = trim($arr[0]->get_content());


	    phpCAS::traceEnd($pt);


	    return $pt;


	  } else {


	    phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');


	  }


	} 


	// look for a proxyFailure tag


	else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {


	  // authentication failed, extract the error


	  $err_code = PHPCAS_SERVICE_PT_FAILURE;


	  $err_msg = 'PT retrieving failed (code=`'


	    .$arr[0]->get_attribute('code')


	    .'\', message=`'


	    .trim($arr[0]->get_content())


	    .'\')';


	  phpCAS::traceEnd(FALSE);


	  return FALSE;


	} else {


	  phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');


	}


      }





      // at this step, we are sure that the response of the CAS server was ill-formed


      $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;


      $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';





      phpCAS::traceEnd(FALSE);


      return FALSE;


    }





  // ########################################################################


  // ACCESS TO EXTERNAL SERVICES


  // ########################################################################





  /**


   * This method is used to acces a remote URL.


   *


   * @param $url the URL to access.


   * @param $cookies an array containing cookies strings such as 'name=val'


   * @param $headers an array containing the HTTP header lines of the response


   * (an empty array on failure).


   * @param $body the body of the response, as a string (empty on failure).


   * @param $err_msg an error message, filled on failure.


   *


   * @return TRUE on success, FALSE otherwise (in this later case, $err_msg


   * contains an error message).


   *


   * @private


   */


  function readURL($url,$cookies,&$headers,&$body,&$err_msg)


    {


      phpCAS::traceBegin();


      $headers = '';


      $body = '';


      $err_msg = '';





      $res = TRUE;





      // initialize the CURL session


      $ch = curl_init($url);


	


	  // verify the the server's certificate corresponds to its name


	  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);


	  // but do not verify the certificate itself


	  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);





      // return the CURL output into a variable


      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);


      // include the HTTP header with the body


      curl_setopt($ch, CURLOPT_HEADER, 1);


      // add cookies headers


      if ( is_array($cookies) ) {


	curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));


      }


      // perform the query


      $buf = curl_exec ($ch);


      if ( $buf === FALSE ) {


	phpCAS::trace('cur_exec() failed');


	$err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);


	// close the CURL session


	curl_close ($ch);


	$res = FALSE;


      } else {


	// close the CURL session


	curl_close ($ch);


	


	// find the end of the headers


	// note: strpos($str,"\n\r\n\r") does not work (?)


	$pos = FALSE;


	for ($i=0; $i<strlen($buf); $i++) {


	  if ( $buf[$i] == chr(13) ) 


	    if ( $buf[$i+1] == chr(10) ) 


	      if ( $buf[$i+2] == chr(13) ) 


		if ( $buf[$i+3] == chr(10) ) {


		  // header found


		  $pos = $i;


		  break;


		}


	}


	


	if ( $pos === FALSE ) {


	  // end of header not found


	  $err_msg = 'no header found';


	  phpCAS::trace($err_msg);


	  $res = FALSE;


	} else { 


	  // extract headers into an array


	  $headers = preg_split ("/[\n\r]+/",substr($buf,0,$pos));	  


	  // extract body into a string


	  $body = substr($buf,$pos+4);


	}


      }





      phpCAS::traceEnd($res);


      return $res;


    }





  /**


   * This method is used to access an HTTP[S] service.


   * 


   * @param $url the service to access.


   * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on


   * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,


   * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.


   * @param $output the output of the service (also used to give an error


   * message on failure).


   *


   * @return TRUE on success, FALSE otherwise (in this later case, $err_code


   * gives the reason why it failed and $output contains an error message).


   *


   * @public


   */


  function serviceWeb($url,&$err_code,&$output)


    {


      phpCAS::traceBegin();


      // at first retrieve a PT


      $pt = $this->retrievePT($url,$err_code,$output);





      $res = TRUE;


      


      // test if PT was retrieved correctly


      if ( !$pt ) {


	// note: $err_code and $err_msg are filled by CASClient::retrievePT()


	phpCAS::trace('PT was not retrieved correctly');


	$res = FALSE;


      } else {


	// add cookies if necessary


	if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {


	  foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { 


	    $cookies[] = $name.'='.$val;


	  }


	}


	


	// build the URL including the PT


	if ( strstr($url,'?') === FALSE ) {


	  $service_url = $url.'?ticket='.$pt;


	} else {


	  $service_url = $url.'&ticket='.$pt;


	}


	


	phpCAS::trace('reading URL`'.$service_url.'\'');


	if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {


	  phpCAS::trace('could not read URL`'.$service_url.'\'');


	  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;


	  // give an error message


	  $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),


			    $service_url,


			    $err_msg);


	  $res = FALSE;


	} else {


	  // URL has been fetched, extract the cookies


	  phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');


	  foreach ( $headers as $header ) {


	    // test if the header is a cookie


	    if ( preg_match('/^Set-Cookie:/',$header) ) {


	      // the header is a cookie, remove the beginning


	      $header_val = preg_replace('/^Set-Cookie: */','',$header);


	      // extract interesting information


	      $name_val = strtok($header_val,'; ');


	      // extract the name and the value of the cookie


	      $cookie_name = strtok($name_val,'=');


	      $cookie_val = strtok('=');


	      // store the cookie 


	      $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;


	      phpCAS::trace($cookie_name.' -> '.$cookie_val);


	    }


	  }


	}


      }





      phpCAS::traceEnd($res);


      return $res;


  }





  /**


   * This method is used to access an IMAP/POP3/NNTP service.


   * 


   * @param $url a string giving the URL of the service, including the mailing box


   * for IMAP URLs, as accepted by imap_open().


   * @param $flags options given to imap_open().


   * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on


   * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,


   * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.


   * @param $err_msg an error message on failure


   * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL


   * on success, FALSE on error).


   *


   * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code


   * gives the reason why it failed and $err_msg contains an error message).


   *


   * @public


   */


  function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)


    {


      phpCAS::traceBegin();


      // at first retrieve a PT


      $pt = $this->retrievePT($target_service,$err_code,$output);





      $stream = FALSE;


      


      // test if PT was retrieved correctly


      if ( !$pt ) {


	// note: $err_code and $err_msg are filled by CASClient::retrievePT()


	phpCAS::trace('PT was not retrieved correctly');


      } else {


	phpCAS::trace('opening IMAP URL `'.$url.'\'...');


	$stream = @imap_open($url,$this->getUser(),$pt,$flags);


	if ( !$stream ) {


	  phpCAS::trace('could not open URL');


	  $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;


	  // give an error message


	  $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),


			     $service_url,


			     var_export(imap_errors(),TRUE));


	  $pt = FALSE;


	  $stream = FALSE;


	} else {


	  phpCAS::trace('ok');


	}


      }





      phpCAS::traceEnd($stream);


      return $stream;


  }





  /** @} */





  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


  // XX                                                                    XX


  // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX


  // XX                                                                    XX


  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX





  // ########################################################################


  //  PT


  // ########################################################################


  /**


   * @addtogroup internalProxied


   * @{


   */  


  


  /**


   * the Proxy Ticket provided in the URL of the request if present


   * (empty otherwise). Written by CASClient::CASClient(), read by 


   * CASClient::getPT() and CASClient::hasPGT().


   *


   * @hideinitializer


   * @private


   */


  var $_pt = '';


  


  /**


   * This method returns the Proxy Ticket provided in the URL of the request.


   * @return The proxy ticket.


   * @private


   */


  function getPT()


    {


      return 'ST'.substr($this->_pt, 2);


    }





  /**


   * This method stores the Proxy Ticket.


   * @param $pt The Proxy Ticket.


   * @private


   */


  function setPT($pt)


    { $this->_pt = $pt; }





  /**


   * This method tells if a Proxy Ticket was stored.


   * @return TRUE if a Proxy Ticket has been stored.


   * @private


   */


  function hasPT()


    { return !empty($this->_pt); }





  /** @} */


  // ########################################################################


  //  PT VALIDATION


  // ########################################################################


  /**


   * @addtogroup internalProxied


   * @{


   */  





  /**


   * This method is used to validate a PT; halt on failure


   * 


   * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().


   *


   * @private


   */


  function validatePT(&$validate_url,&$text_response,&$tree_response)


    {


      phpCAS::traceBegin();


      // build the URL to validate the ticket


      $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();





      if ( $this->isProxy() ) {


      // pass the callback url for CAS proxies


	$validate_url .= '&pgtUrl='.$this->getCallbackURL();


      }





      // open and read the URL


      if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {


	phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');


	$this->authError('PT not validated',


			 $validate_url,


			 TRUE/*$no_response*/);


      }





      // read the response of the CAS server into a DOM object


      if ( !($dom = domxml_open_mem($text_response))) {


	// read failed


	$this->authError('PT not validated',


		     $validate_url,


		     FALSE/*$no_response*/,


		     TRUE/*$bad_response*/,


		     $text_response);


      }


      // read the root node of the XML tree


      if ( !($tree_response = $dom->document_element()) ) {


	// read failed


	$this->authError('PT not validated',


		     $validate_url,


		     FALSE/*$no_response*/,


		     TRUE/*$bad_response*/,


		     $text_response);


      }


      // insure that tag name is 'serviceResponse'


      if ( $tree_response->node_name() != 'serviceResponse' ) {


	// bad root node


	$this->authError('PT not validated',


		     $validate_url,


		     FALSE/*$no_response*/,


		     TRUE/*$bad_response*/,


		     $text_response);


      }


      if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {


	// authentication succeded, extract the user name


	if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {


	  // no user specified => error


	  $this->authError('PT not validated',


		       $validate_url,


		       FALSE/*$no_response*/,


		       TRUE/*$bad_response*/,


		       $text_response);


	}


	$this->setUser(trim($arr[0]->get_content()));


	


      } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {


	// authentication succeded, extract the error code and message


	$this->authError('PT not validated',


		     $validate_url,


		     FALSE/*$no_response*/,


		     FALSE/*$bad_response*/,


		     $text_response,


		     $arr[0]->get_attribute('code')/*$err_code*/,


		     trim($arr[0]->get_content())/*$err_msg*/);


      } else {


	$this->authError('PT not validated',


		     $validate_url,	


		     FALSE/*$no_response*/,


		     TRUE/*$bad_response*/,


		     $text_response);


      }


      


      // at this step, PT has been validated and $this->_user has been set,





      phpCAS::traceEnd(TRUE);


      return TRUE;


    }





  /** @} */





  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


  // XX                                                                    XX


  // XX                               MISC                                 XX


  // XX                                                                    XX


  // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX





  /**


   * @addtogroup internalMisc


   * @{


   */  


  


  // ########################################################################


  //  URL


  // ########################################################################


  /**


   * the URL of the current request (without any ticket CGI parameter). Written 


   * and read by CASClient::getURL().


   *


   * @hideinitializer


   * @private


   */


  var $_url = '';





  /**


   * This method returns the URL of the current request (without any ticket


   * CGI parameter).


   *


   * @return The URL


   *


   * @private


   */


  function getURL()


    {


      phpCAS::traceBegin();


      // the URL is built when needed only


      if ( empty($this->_url) ) {


	    $final_uri = '';


	    // remove the ticket if present in the URL


	    $final_uri = ($this->isHttps()) ? 'https' : 'http';


	    $final_uri .= '://';


	    /* replaced by Julien Marchal - v0.4.6


	     * $this->_url .= $_SERVER['SERVER_NAME'];


	     */


        if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){


          /* replaced by teedog - v0.4.12


           * $this->_url .= $_SERVER['SERVER_NAME'];


           */


          if (empty($_SERVER['SERVER_NAME'])) {


            $server_name = $_SERVER['HTTP_HOST'];


          } else {


            $server_name = $_SERVER['SERVER_NAME'];


          }


        } else {


          $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];


        }


      $final_uri .= $server_name;


      if (!strpos($server_name, ':')) {


  	    if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)


	       || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {


	      $final_uri .= ':';


	      $final_uri .= $_SERVER['SERVER_PORT'];


	    }


      }





	  $final_uri .= strtok($_SERVER['REQUEST_URI'],"?");


	  $cgi_params = '?'.strtok("?");


	  // remove the ticket if present in the CGI parameters


	  $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params);


	  $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params);


	  $cgi_params = preg_replace('/\?%26/','?',$cgi_params);


	  $cgi_params = preg_replace('/\?&/','?',$cgi_params);


	  $cgi_params = preg_replace('/\?$/','',$cgi_params);


	  $final_uri .= $cgi_params;


	  $this->setURL($final_uri);


    }


    phpCAS::traceEnd($this->_url);


    return $this->_url;


  }





  /**


   * This method sets the URL of the current request 


   *


   * @param $url url to set for service


   *


   * @private


   */


  function setURL($url)


    {


      $this->_url = $url;


    }


  


  // ########################################################################


  //  AUTHENTICATION ERROR HANDLING


  // ########################################################################


  /**


   * This method is used to print the HTML output when the user was not authenticated.


   *


   * @param $failure the failure that occured


   * @param $cas_url the URL the CAS server was asked for


   * @param $no_response the response from the CAS server (other 


   * parameters are ignored if TRUE)


   * @param $bad_response bad response from the CAS server ($err_code


   * and $err_msg ignored if TRUE)


   * @param $cas_response the response of the CAS server


   * @param $err_code the error code given by the CAS server


   * @param $err_msg the error message given by the CAS server


   *


   * @private


   */


  function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')


    {


      phpCAS::traceBegin();





      $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));


      printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']);


      phpCAS::trace('CAS URL: '.$cas_url);


      phpCAS::trace('Authentication failure: '.$failure);


      if ( $no_response ) {


	phpCAS::trace('Reason: no response from the CAS server');


      } else {


	if ( $bad_response ) {


	    phpCAS::trace('Reason: bad response from the CAS server');


	} else {


	  switch ($this->getServerVersion()) {


	  case CAS_VERSION_1_0:


	    phpCAS::trace('Reason: CAS error');


	    break;


	  case CAS_VERSION_2_0:


	    if ( empty($err_code) )


	      phpCAS::trace('Reason: no CAS error');


	    else


	      phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);


	    break;


	  }


	}


	phpCAS::trace('CAS response: '.$cas_response);


      }


      $this->printHTMLFooter();


      phpCAS::traceExit();


      exit();


    }





  /** @} */


}





?>