document.lib.php 262 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use ChamiloSession as Session;
  4. /**
  5. * Class DocumentManager
  6. * This is the document library for Chamilo.
  7. * It is / will be used to provide a service layer to all document-using tools.
  8. * and eliminate code duplication fro group documents, scorm documents, main documents.
  9. * Include/require it in your code to use its functionality.
  10. *
  11. * @package chamilo.library
  12. */
  13. class DocumentManager
  14. {
  15. /**
  16. * Construct.
  17. */
  18. private function __construct()
  19. {
  20. }
  21. /**
  22. * @param string $course_code
  23. *
  24. * @return int the document folder quota for the current course in bytes
  25. * or the default quota
  26. */
  27. public static function get_course_quota($course_code = null)
  28. {
  29. if (empty($course_code)) {
  30. $course_info = api_get_course_info();
  31. } else {
  32. $course_info = api_get_course_info($course_code);
  33. }
  34. $course_quota = null;
  35. if (empty($course_info)) {
  36. return DEFAULT_DOCUMENT_QUOTA;
  37. } else {
  38. $course_quota = $course_info['disk_quota'];
  39. }
  40. if (is_null($course_quota) || empty($course_quota)) {
  41. // Course table entry for quota was null, then use default value
  42. $course_quota = DEFAULT_DOCUMENT_QUOTA;
  43. }
  44. return $course_quota;
  45. }
  46. /**
  47. * Get the content type of a file by checking the extension
  48. * We could use mime_content_type() with php-versions > 4.3,
  49. * but this doesn't work as it should on Windows installations.
  50. *
  51. * @param string $filename or boolean TRUE to return complete array
  52. *
  53. * @author ? first version
  54. * @author Bert Vanderkimpen
  55. *
  56. * @return string
  57. */
  58. public static function file_get_mime_type($filename)
  59. {
  60. // All MIME types in an array (from 1.6, this is the authorative source)
  61. // Please, keep this alphabetical if you add something to this list!
  62. $mimeTypes = [
  63. 'ai' => 'application/postscript',
  64. 'aif' => 'audio/x-aiff',
  65. 'aifc' => 'audio/x-aiff',
  66. 'aiff' => 'audio/x-aiff',
  67. 'asf' => 'video/x-ms-asf',
  68. 'asc' => 'text/plain',
  69. 'au' => 'audio/basic',
  70. 'avi' => 'video/x-msvideo',
  71. 'bcpio' => 'application/x-bcpio',
  72. 'bin' => 'application/octet-stream',
  73. 'bmp' => 'image/bmp',
  74. 'cdf' => 'application/x-netcdf',
  75. 'class' => 'application/octet-stream',
  76. 'cpio' => 'application/x-cpio',
  77. 'cpt' => 'application/mac-compactpro',
  78. 'csh' => 'application/x-csh',
  79. 'css' => 'text/css',
  80. 'dcr' => 'application/x-director',
  81. 'dir' => 'application/x-director',
  82. 'djv' => 'image/vnd.djvu',
  83. 'djvu' => 'image/vnd.djvu',
  84. 'dll' => 'application/octet-stream',
  85. 'dmg' => 'application/x-diskcopy',
  86. 'dms' => 'application/octet-stream',
  87. 'doc' => 'application/msword',
  88. 'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
  89. 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  90. 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  91. 'dvi' => 'application/x-dvi',
  92. 'dwg' => 'application/vnd.dwg',
  93. 'dwf' => 'application/vnd.dwf',
  94. 'dxf' => 'application/vnd.dxf',
  95. 'dxr' => 'application/x-director',
  96. 'eps' => 'application/postscript',
  97. 'epub' => 'application/epub+zip',
  98. 'etx' => 'text/x-setext',
  99. 'exe' => 'application/octet-stream',
  100. 'ez' => 'application/andrew-inset',
  101. 'flv' => 'video/flv',
  102. 'gif' => 'image/gif',
  103. 'gtar' => 'application/x-gtar',
  104. 'gz' => 'application/x-gzip',
  105. 'hdf' => 'application/x-hdf',
  106. 'hqx' => 'application/mac-binhex40',
  107. 'htm' => 'text/html',
  108. 'html' => 'text/html',
  109. 'ice' => 'x-conference-xcooltalk',
  110. 'ief' => 'image/ief',
  111. 'iges' => 'model/iges',
  112. 'igs' => 'model/iges',
  113. 'jar' => 'application/java-archiver',
  114. 'jpe' => 'image/jpeg',
  115. 'jpeg' => 'image/jpeg',
  116. 'jpg' => 'image/jpeg',
  117. 'js' => 'application/x-javascript',
  118. 'kar' => 'audio/midi',
  119. 'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
  120. 'latex' => 'application/x-latex',
  121. 'lha' => 'application/octet-stream',
  122. 'log' => 'text/plain',
  123. 'lzh' => 'application/octet-stream',
  124. 'm1a' => 'audio/mpeg',
  125. 'm2a' => 'audio/mpeg',
  126. 'm3u' => 'audio/x-mpegurl',
  127. 'man' => 'application/x-troff-man',
  128. 'me' => 'application/x-troff-me',
  129. 'mesh' => 'model/mesh',
  130. 'mid' => 'audio/midi',
  131. 'midi' => 'audio/midi',
  132. 'mov' => 'video/quicktime',
  133. 'movie' => 'video/x-sgi-movie',
  134. 'mp2' => 'audio/mpeg',
  135. 'mp3' => 'audio/mpeg',
  136. 'mp4' => 'video/mp4',
  137. 'mpa' => 'audio/mpeg',
  138. 'mpe' => 'video/mpeg',
  139. 'mpeg' => 'video/mpeg',
  140. 'mpg' => 'video/mpeg',
  141. 'mpga' => 'audio/mpeg',
  142. 'ms' => 'application/x-troff-ms',
  143. 'msh' => 'model/mesh',
  144. 'mxu' => 'video/vnd.mpegurl',
  145. 'nc' => 'application/x-netcdf',
  146. 'oda' => 'application/oda',
  147. 'oga' => 'audio/ogg',
  148. 'ogg' => 'application/ogg',
  149. 'ogx' => 'application/ogg',
  150. 'ogv' => 'video/ogg',
  151. 'pbm' => 'image/x-portable-bitmap',
  152. 'pct' => 'image/pict',
  153. 'pdb' => 'chemical/x-pdb',
  154. 'pdf' => 'application/pdf',
  155. 'pgm' => 'image/x-portable-graymap',
  156. 'pgn' => 'application/x-chess-pgn',
  157. 'pict' => 'image/pict',
  158. 'png' => 'image/png',
  159. 'pnm' => 'image/x-portable-anymap',
  160. 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
  161. 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
  162. 'pps' => 'application/vnd.ms-powerpoint',
  163. 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
  164. 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
  165. 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
  166. 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
  167. 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  168. 'ppm' => 'image/x-portable-pixmap',
  169. 'ppt' => 'application/vnd.ms-powerpoint',
  170. 'ps' => 'application/postscript',
  171. 'qt' => 'video/quicktime',
  172. 'ra' => 'audio/x-realaudio',
  173. 'ram' => 'audio/x-pn-realaudio',
  174. 'rar' => 'image/x-rar-compressed',
  175. 'ras' => 'image/x-cmu-raster',
  176. 'rgb' => 'image/x-rgb',
  177. 'rm' => 'audio/x-pn-realaudio',
  178. 'roff' => 'application/x-troff',
  179. 'rpm' => 'audio/x-pn-realaudio-plugin',
  180. 'rtf' => 'text/rtf',
  181. 'rtx' => 'text/richtext',
  182. 'sgm' => 'text/sgml',
  183. 'sgml' => 'text/sgml',
  184. 'sh' => 'application/x-sh',
  185. 'shar' => 'application/x-shar',
  186. 'silo' => 'model/mesh',
  187. 'sib' => 'application/X-Sibelius-Score',
  188. 'sit' => 'application/x-stuffit',
  189. 'skd' => 'application/x-koan',
  190. 'skm' => 'application/x-koan',
  191. 'skp' => 'application/x-koan',
  192. 'skt' => 'application/x-koan',
  193. 'smi' => 'application/smil',
  194. 'smil' => 'application/smil',
  195. 'snd' => 'audio/basic',
  196. 'so' => 'application/octet-stream',
  197. 'spl' => 'application/x-futuresplash',
  198. 'src' => 'application/x-wais-source',
  199. 'sv4cpio' => 'application/x-sv4cpio',
  200. 'sv4crc' => 'application/x-sv4crc',
  201. 'svf' => 'application/vnd.svf',
  202. 'svg' => 'image/svg+xml',
  203. //'svgz' => 'image/svg+xml',
  204. 'swf' => 'application/x-shockwave-flash',
  205. 'sxc' => 'application/vnd.sun.xml.calc',
  206. 'sxi' => 'application/vnd.sun.xml.impress',
  207. 'sxw' => 'application/vnd.sun.xml.writer',
  208. 't' => 'application/x-troff',
  209. 'tar' => 'application/x-tar',
  210. 'tcl' => 'application/x-tcl',
  211. 'tex' => 'application/x-tex',
  212. 'texi' => 'application/x-texinfo',
  213. 'texinfo' => 'application/x-texinfo',
  214. 'tga' => 'image/x-targa',
  215. 'tif' => 'image/tif',
  216. 'tiff' => 'image/tiff',
  217. 'tr' => 'application/x-troff',
  218. 'tsv' => 'text/tab-seperated-values',
  219. 'txt' => 'text/plain',
  220. 'ustar' => 'application/x-ustar',
  221. 'vcd' => 'application/x-cdlink',
  222. 'vrml' => 'model/vrml',
  223. 'wav' => 'audio/x-wav',
  224. 'wbmp' => 'image/vnd.wap.wbmp',
  225. 'wbxml' => 'application/vnd.wap.wbxml',
  226. 'webp' => 'image/webp',
  227. 'wml' => 'text/vnd.wap.wml',
  228. 'wmlc' => 'application/vnd.wap.wmlc',
  229. 'wmls' => 'text/vnd.wap.wmlscript',
  230. 'wmlsc' => 'application/vnd.wap.wmlscriptc',
  231. 'wma' => 'audio/x-ms-wma',
  232. 'wmv' => 'video/x-ms-wmv',
  233. 'wrl' => 'model/vrml',
  234. 'xbm' => 'image/x-xbitmap',
  235. 'xht' => 'application/xhtml+xml',
  236. 'xhtml' => 'application/xhtml+xml',
  237. 'xls' => 'application/vnd.ms-excel',
  238. 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
  239. 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
  240. 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  241. 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
  242. 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
  243. 'xml' => 'text/xml',
  244. 'xpm' => 'image/x-xpixmap',
  245. 'xsl' => 'text/xml',
  246. 'xwd' => 'image/x-windowdump',
  247. 'xyz' => 'chemical/x-xyz',
  248. 'zip' => 'application/zip',
  249. ];
  250. if ($filename === true) {
  251. return $mimeTypes;
  252. }
  253. // Get the extension of the file
  254. $extension = explode('.', $filename);
  255. // $filename will be an array if a . was found
  256. if (is_array($extension)) {
  257. $extension = strtolower($extension[count($extension) - 1]);
  258. } else {
  259. //file without extension
  260. $extension = 'empty';
  261. }
  262. //if the extension is found, return the content type
  263. if (isset($mimeTypes[$extension])) {
  264. return $mimeTypes[$extension];
  265. }
  266. return 'application/octet-stream';
  267. }
  268. /**
  269. * This function smart streams a file to the client using HTTP headers.
  270. *
  271. * @param string $fullFilename The full path of the file to be sent
  272. * @param string $filename The name of the file as shown to the client
  273. * @param string $contentType The MIME type of the file
  274. *
  275. * @return bool false if file doesn't exist, true if stream succeeded
  276. */
  277. public static function smartReadFile($fullFilename, $filename, $contentType = 'application/octet-stream')
  278. {
  279. if (!file_exists($fullFilename)) {
  280. header("HTTP/1.1 404 Not Found");
  281. return false;
  282. }
  283. $size = filesize($fullFilename);
  284. $time = date('r', filemtime($fullFilename));
  285. $fm = @fopen($fullFilename, 'rb');
  286. if (!$fm) {
  287. header("HTTP/1.1 505 Internal server error");
  288. return false;
  289. }
  290. $begin = 0;
  291. $end = $size - 1;
  292. if (isset($_SERVER['HTTP_RANGE'])) {
  293. if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
  294. $begin = intval($matches[1]);
  295. if (!empty($matches[2])) {
  296. $end = intval($matches[2]);
  297. }
  298. }
  299. }
  300. if (isset($_SERVER['HTTP_RANGE'])) {
  301. header('HTTP/1.1 206 Partial Content');
  302. } else {
  303. header('HTTP/1.1 200 OK');
  304. }
  305. header("Content-Type: $contentType");
  306. header('Cache-Control: public, must-revalidate, max-age=0');
  307. header('Pragma: no-cache');
  308. header('Accept-Ranges: bytes');
  309. header('Content-Length:'.(($end - $begin) + 1));
  310. if (isset($_SERVER['HTTP_RANGE'])) {
  311. header("Content-Range: bytes $begin-$end/$size");
  312. }
  313. header("Content-Disposition: inline; filename=$filename");
  314. header("Content-Transfer-Encoding: binary");
  315. header("Last-Modified: $time");
  316. $cur = $begin;
  317. fseek($fm, $begin, 0);
  318. while (!feof($fm) && $cur <= $end && (connection_status() == 0)) {
  319. echo fread($fm, min(1024 * 16, ($end - $cur) + 1));
  320. $cur += 1024 * 16;
  321. }
  322. }
  323. /**
  324. * This function streams a file to the client.
  325. *
  326. * @param string $full_file_name
  327. * @param bool $forced
  328. * @param string $name
  329. * @param bool $fixLinksHttpToHttps change file content from http to https
  330. *
  331. * @return false if file doesn't exist, true if stream succeeded
  332. */
  333. public static function file_send_for_download(
  334. $full_file_name,
  335. $forced = false,
  336. $name = '',
  337. $fixLinksHttpToHttps = false
  338. ) {
  339. session_write_close(); //we do not need write access to session anymore
  340. if (!is_file($full_file_name)) {
  341. return false;
  342. }
  343. $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
  344. $len = filesize($full_file_name);
  345. // Fixing error when file name contains a ","
  346. $filename = str_replace(',', '', $filename);
  347. $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
  348. // Allows chrome to make videos and audios seekable
  349. header('Accept-Ranges: bytes');
  350. if ($forced) {
  351. // Force the browser to save the file instead of opening it
  352. if (isset($sendFileHeaders) &&
  353. !empty($sendFileHeaders)) {
  354. header("X-Sendfile: $filename");
  355. }
  356. header('Content-type: application/octet-stream');
  357. header('Content-length: '.$len);
  358. if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
  359. header('Content-Disposition: filename= '.$filename);
  360. } else {
  361. header('Content-Disposition: attachment; filename= '.$filename);
  362. }
  363. if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
  364. header('Pragma: ');
  365. header('Cache-Control: ');
  366. header('Cache-Control: public'); // IE cannot download from sessions without a cache
  367. }
  368. header('Content-Description: '.$filename);
  369. header('Content-Transfer-Encoding: binary');
  370. if (function_exists('ob_end_clean') && ob_get_length()) {
  371. // Use ob_end_clean() to avoid weird buffering situations
  372. // where file is sent broken/incomplete for download
  373. ob_end_clean();
  374. }
  375. $res = fopen($full_file_name, 'r');
  376. fpassthru($res);
  377. return true;
  378. } else {
  379. // no forced download, just let the browser decide what to do according to the mimetype
  380. $lpFixedEncoding = api_get_configuration_value('lp_fixed_encoding');
  381. // Commented to let courses content to be cached in order to improve performance:
  382. //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
  383. //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  384. // Commented to avoid double caching declaration when playing with IE and HTTPS
  385. //header('Cache-Control: no-cache, must-revalidate');
  386. //header('Pragma: no-cache');
  387. $contentType = self::file_get_mime_type($filename);
  388. switch ($contentType) {
  389. case 'text/html':
  390. if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
  391. $contentType .= '; charset=UTF-8';
  392. } else {
  393. $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
  394. if (!empty($encoding)) {
  395. $contentType .= '; charset='.$encoding;
  396. }
  397. }
  398. break;
  399. case 'text/plain':
  400. if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
  401. $contentType .= '; charset=UTF-8';
  402. } else {
  403. $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
  404. if (!empty($encoding)) {
  405. $contentType .= '; charset='.$encoding;
  406. }
  407. }
  408. break;
  409. case 'video/mp4':
  410. case 'audio/mpeg':
  411. case 'audio/mp4':
  412. case 'audio/ogg':
  413. case 'audio/webm':
  414. case 'audio/wav':
  415. case 'video/ogg':
  416. case 'video/webm':
  417. self::smartReadFile($full_file_name, $filename, $contentType);
  418. exit;
  419. case 'application/vnd.dwg':
  420. case 'application/vnd.dwf':
  421. header('Content-type: application/octet-stream');
  422. break;
  423. }
  424. header('Content-type: '.$contentType);
  425. header('Content-Length: '.$len);
  426. $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
  427. if (strpos($userAgent, 'msie')) {
  428. header('Content-Disposition: ; filename= '.$filename);
  429. } else {
  430. //header('Content-Disposition: inline');
  431. header('Content-Disposition: inline;');
  432. }
  433. if ($fixLinksHttpToHttps) {
  434. $content = file_get_contents($full_file_name);
  435. $content = str_replace(
  436. ['http%3A%2F%2F', 'http://'],
  437. ['https%3A%2F%2F', 'https://'],
  438. $content
  439. );
  440. echo $content;
  441. } else {
  442. if (function_exists('ob_end_clean') && ob_get_length()) {
  443. // Use ob_end_clean() to avoid weird buffering situations
  444. // where file is sent broken/incomplete for download
  445. ob_end_clean();
  446. }
  447. readfile($full_file_name);
  448. }
  449. return true;
  450. }
  451. }
  452. /**
  453. * Session folder filters.
  454. *
  455. * @param string $path
  456. * @param int $sessionId
  457. *
  458. * @return string|null
  459. */
  460. public static function getSessionFolderFilters($path, $sessionId)
  461. {
  462. $sessionId = (int) $sessionId;
  463. $condition = null;
  464. if (!empty($sessionId)) {
  465. // Chat folder filter
  466. if ($path == '/chat_files') {
  467. $condition .= " AND (docs.session_id = '$sessionId') ";
  468. }
  469. // share_folder filter
  470. $condition .= " AND docs.path != '/shared_folder' ";
  471. }
  472. return $condition;
  473. }
  474. /**
  475. * Fetches all document data for the given user/group.
  476. *
  477. * @param array $courseInfo
  478. * @param string $path
  479. * @param int $toGroupId iid
  480. * @param int $toUserId
  481. * @param bool $canSeeInvisible
  482. * @param bool $search
  483. * @param int $sessionId
  484. *
  485. * @return array with all document data
  486. */
  487. public static function getAllDocumentData(
  488. $courseInfo,
  489. $path = '/',
  490. $toGroupId = 0,
  491. $toUserId = null,
  492. $canSeeInvisible = false,
  493. $search = false,
  494. $sessionId = 0
  495. ) {
  496. if (empty($courseInfo)) {
  497. return [];
  498. }
  499. $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  500. $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
  501. if (!is_null($toUserId)) {
  502. $toUserId = (int) $toUserId;
  503. $userGroupFilter = "last.to_user_id = $toUserId";
  504. if (empty($toUserId)) {
  505. $userGroupFilter = ' (last.to_user_id = 0 OR last.to_user_id IS NULL) ';
  506. }
  507. } else {
  508. $toGroupId = (int) $toGroupId;
  509. $userGroupFilter = "last.to_group_id = $toGroupId";
  510. if (empty($toGroupId)) {
  511. $userGroupFilter = '( last.to_group_id = 0 OR last.to_group_id IS NULL) ';
  512. }
  513. }
  514. // Escape underscores in the path so they don't act as a wildcard
  515. $originalPath = $path;
  516. $path = str_replace('_', '\_', $path);
  517. $visibilityBit = ' <> 2';
  518. // The given path will not end with a slash, unless it's the root '/'
  519. // so no root -> add slash
  520. $addedSlash = $path == '/' ? '' : '/';
  521. // Condition for the session
  522. $sessionId = $sessionId ?: api_get_session_id();
  523. $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
  524. $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
  525. $sharedCondition = null;
  526. if ($originalPath == '/shared_folder') {
  527. $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
  528. if (!empty($students)) {
  529. $conditionList = [];
  530. foreach ($students as $studentInfo) {
  531. $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
  532. }
  533. $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
  534. }
  535. }
  536. $sql = "SELECT
  537. docs.id,
  538. docs.filetype,
  539. docs.path,
  540. docs.title,
  541. docs.comment,
  542. docs.size,
  543. docs.readonly,
  544. docs.session_id,
  545. last.session_id item_property_session_id,
  546. last.lastedit_date,
  547. last.visibility,
  548. last.insert_user_id
  549. FROM $tblItemProperty AS last
  550. INNER JOIN $tblDocument AS docs
  551. ON (
  552. docs.id = last.ref AND
  553. docs.c_id = last.c_id
  554. )
  555. WHERE
  556. last.tool = '".TOOL_DOCUMENT."' AND
  557. docs.c_id = {$courseInfo['real_id']} AND
  558. last.c_id = {$courseInfo['real_id']} AND
  559. docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
  560. docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
  561. docs.path NOT LIKE '%_DELETED_%' AND
  562. $userGroupFilter AND
  563. last.visibility $visibilityBit
  564. $conditionSession
  565. $sharedCondition
  566. ORDER BY last.iid DESC, last.session_id DESC
  567. ";
  568. $result = Database::query($sql);
  569. $documentData = [];
  570. $isAllowedToEdit = api_is_allowed_to_edit(null, true);
  571. $isCoach = api_is_coach();
  572. if ($result !== false && Database::num_rows($result) != 0) {
  573. $rows = [];
  574. $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
  575. while ($row = Database::fetch_array($result, 'ASSOC')) {
  576. if (isset($rows[$row['id']])) {
  577. continue;
  578. }
  579. // If we are in session and hide_invisible_course_documents_in_sessions is enabled
  580. // Then we avoid the documents that have visibility in session but that they come from a base course
  581. if ($hideInvisibleDocuments && $sessionId) {
  582. if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
  583. continue;
  584. }
  585. }
  586. if (self::isBasicCourseFolder($row['path'], $sessionId)) {
  587. $basicCourseDocumentsContent = self::getAllDocumentData(
  588. $courseInfo,
  589. $row['path']
  590. );
  591. if (empty($basicCourseDocumentsContent)) {
  592. continue;
  593. }
  594. }
  595. $rows[$row['id']] = $row;
  596. }
  597. // If we are in session and hide_invisible_course_documents_in_sessions is enabled
  598. // Or if we are students
  599. // Then don't list the invisible or deleted documents
  600. if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
  601. $rows = array_filter($rows, function ($row) {
  602. if (in_array($row['visibility'], ['0', '2'])) {
  603. return false;
  604. }
  605. return true;
  606. });
  607. }
  608. foreach ($rows as $row) {
  609. if ($row['filetype'] == 'file' &&
  610. pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
  611. ) {
  612. // Templates management
  613. $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
  614. $sql = "SELECT id FROM $tblTemplate
  615. WHERE
  616. course_code = '".$courseInfo['code']."' AND
  617. user_id = '".api_get_user_id()."' AND
  618. ref_doc = '".$row['id']."'";
  619. $templateResult = Database::query($sql);
  620. $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
  621. }
  622. $row['basename'] = basename($row['path']);
  623. // Just filling $document_data.
  624. $documentData[$row['id']] = $row;
  625. }
  626. // Only for the student we filter the results see BT#1652
  627. if (!$isCoach && !$isAllowedToEdit) {
  628. // Checking parents visibility.
  629. $finalDocumentData = [];
  630. foreach ($documentData as $row) {
  631. $isVisible = self::check_visibility_tree(
  632. $row['id'],
  633. $courseInfo,
  634. $sessionId,
  635. api_get_user_id(),
  636. $toGroupId
  637. );
  638. if ($isVisible) {
  639. $finalDocumentData[$row['id']] = $row;
  640. }
  641. }
  642. } else {
  643. $finalDocumentData = $documentData;
  644. }
  645. return $finalDocumentData;
  646. } else {
  647. return [];
  648. }
  649. }
  650. /**
  651. * Gets the paths of all folders in a course
  652. * can show all folders (except for the deleted ones) or only visible ones.
  653. *
  654. * @param array $_course
  655. * @param int $groupIid iid
  656. * @param bool $can_see_invisible
  657. * @param bool $getInvisibleList
  658. * @param string $path current path
  659. *
  660. * @return array with paths
  661. */
  662. public static function get_all_document_folders(
  663. $_course,
  664. $groupIid = 0,
  665. $can_see_invisible = false,
  666. $getInvisibleList = false,
  667. $path = ''
  668. ) {
  669. if (empty($_course)) {
  670. return [];
  671. }
  672. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  673. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  674. $groupIid = (int) $groupIid;
  675. $document_folders = [];
  676. $students = CourseManager::get_user_list_from_course_code(
  677. $_course['code'],
  678. api_get_session_id()
  679. );
  680. $conditionList = [];
  681. if (!empty($students)) {
  682. foreach ($students as $studentId => $studentInfo) {
  683. $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
  684. }
  685. }
  686. $groupCondition = " last.to_group_id = $groupIid";
  687. if (empty($groupIid)) {
  688. $groupCondition = ' (last.to_group_id = 0 OR last.to_group_id IS NULL)';
  689. }
  690. $show_users_condition = '';
  691. if (api_get_setting('show_users_folders') === 'false') {
  692. $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
  693. }
  694. if ($can_see_invisible) {
  695. // condition for the session
  696. $session_id = api_get_session_id();
  697. //$condition_session = api_get_session_condition($session_id, true, false, 'docs.session_id');
  698. $session_id = $session_id ?: api_get_session_id();
  699. $condition_session = " AND (last.session_id = '$session_id' OR (last.session_id = '0' OR last.session_id IS NULL) )";
  700. $condition_session .= self::getSessionFolderFilters($path, $session_id);
  701. if ($groupIid != 0) {
  702. $sql = "SELECT DISTINCT docs.id, path
  703. FROM $TABLE_ITEMPROPERTY AS last
  704. INNER JOIN $TABLE_DOCUMENT AS docs
  705. ON (
  706. docs.id = last.ref AND
  707. docs.c_id = last.c_id
  708. )
  709. WHERE
  710. last.tool = '".TOOL_DOCUMENT."' AND
  711. last.c_id = {$_course['real_id']} AND
  712. docs.c_id = {$_course['real_id']} AND
  713. docs.filetype = 'folder' AND
  714. $groupCondition AND
  715. docs.path NOT LIKE '%shared_folder%' AND
  716. docs.path NOT LIKE '%_DELETED_%' AND
  717. last.visibility <> 2
  718. $condition_session ";
  719. } else {
  720. $sql = "SELECT DISTINCT docs.id, path
  721. FROM $TABLE_ITEMPROPERTY AS last
  722. INNER JOIN $TABLE_DOCUMENT AS docs
  723. ON (
  724. docs.id = last.ref AND
  725. docs.c_id = last.c_id
  726. )
  727. WHERE
  728. last.tool = '".TOOL_DOCUMENT."' AND
  729. last.c_id = {$_course['real_id']} AND
  730. docs.c_id = {$_course['real_id']} AND
  731. docs.filetype = 'folder' AND
  732. docs.path NOT LIKE '%_DELETED_%' AND
  733. $groupCondition AND
  734. last.visibility <> 2
  735. $show_users_condition
  736. $condition_session
  737. ";
  738. }
  739. $result = Database::query($sql);
  740. if ($result && Database::num_rows($result) != 0) {
  741. while ($row = Database::fetch_array($result, 'ASSOC')) {
  742. if (self::is_folder_to_avoid($row['path'])) {
  743. continue;
  744. }
  745. if (strpos($row['path'], '/shared_folder/') !== false) {
  746. if (!in_array($row['path'], $conditionList)) {
  747. continue;
  748. }
  749. }
  750. $document_folders[$row['id']] = $row['path'];
  751. }
  752. if (!empty($document_folders)) {
  753. natsort($document_folders);
  754. }
  755. return $document_folders;
  756. } else {
  757. return false;
  758. }
  759. } else {
  760. // No invisible folders
  761. // Condition for the session
  762. $session_id = api_get_session_id();
  763. $condition_session = api_get_session_condition(
  764. $session_id,
  765. true,
  766. true, // needed to don't show files in elfinder browser
  767. 'docs.session_id'
  768. );
  769. $visibilityCondition = 'last.visibility = 1';
  770. $fileType = "docs.filetype = 'folder' AND";
  771. if ($getInvisibleList) {
  772. $visibilityCondition = 'last.visibility = 0';
  773. $fileType = '';
  774. }
  775. //get visible folders
  776. $sql = "SELECT DISTINCT docs.id, path
  777. FROM
  778. $TABLE_ITEMPROPERTY AS last
  779. INNER JOIN $TABLE_DOCUMENT AS docs
  780. ON (docs.id = last.ref AND last.c_id = docs.c_id)
  781. WHERE
  782. $fileType
  783. last.tool = '".TOOL_DOCUMENT."' AND
  784. $groupCondition AND
  785. $visibilityCondition
  786. $show_users_condition
  787. $condition_session AND
  788. last.c_id = {$_course['real_id']} AND
  789. docs.c_id = {$_course['real_id']} ";
  790. $result = Database::query($sql);
  791. $visibleFolders = [];
  792. while ($row = Database::fetch_array($result, 'ASSOC')) {
  793. $visibleFolders[$row['id']] = $row['path'];
  794. }
  795. if ($getInvisibleList) {
  796. return $visibleFolders;
  797. }
  798. //get invisible folders
  799. $sql = "SELECT DISTINCT docs.id, path
  800. FROM $TABLE_ITEMPROPERTY AS last
  801. INNER JOIN $TABLE_DOCUMENT AS docs
  802. ON (docs.id = last.ref AND last.c_id = docs.c_id)
  803. WHERE
  804. docs.filetype = 'folder' AND
  805. last.tool = '".TOOL_DOCUMENT."' AND
  806. $groupCondition AND
  807. last.visibility = 0 $condition_session AND
  808. last.c_id = {$_course['real_id']} AND
  809. docs.c_id = {$_course['real_id']} ";
  810. $result = Database::query($sql);
  811. $invisibleFolders = [];
  812. while ($row = Database::fetch_array($result, 'ASSOC')) {
  813. //get visible folders in the invisible ones -> they are invisible too
  814. $sql = "SELECT DISTINCT docs.id, path
  815. FROM $TABLE_ITEMPROPERTY AS last
  816. INNER JOIN $TABLE_DOCUMENT AS docs
  817. ON (docs.id = last.ref AND docs.c_id = last.c_id)
  818. WHERE
  819. docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
  820. docs.filetype = 'folder' AND
  821. last.tool = '".TOOL_DOCUMENT."' AND
  822. $groupCondition AND
  823. last.visibility = 1 $condition_session AND
  824. last.c_id = {$_course['real_id']} AND
  825. docs.c_id = {$_course['real_id']} ";
  826. $folder_in_invisible_result = Database::query($sql);
  827. while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
  828. $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
  829. }
  830. }
  831. // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
  832. if (is_array($visibleFolders) && is_array($invisibleFolders)) {
  833. $document_folders = array_diff($visibleFolders, $invisibleFolders);
  834. natsort($document_folders);
  835. return $document_folders;
  836. } elseif (is_array($visibleFolders)) {
  837. natsort($visibleFolders);
  838. return $visibleFolders;
  839. } else {
  840. //no visible folders found
  841. return false;
  842. }
  843. }
  844. }
  845. /**
  846. * This check if a document has the readonly property checked, then see if the user
  847. * is the owner of this file, if all this is true then return true.
  848. *
  849. * @param array $_course
  850. * @param int $user_id id of the current user
  851. * @param string $file path stored in the database (if not defined, $documentId must be used)
  852. * @param int $document_id in case you dont have the file path ,
  853. * insert the id of the file here and leave $file in blank ''
  854. * @param bool $to_delete
  855. * @param int $sessionId
  856. *
  857. * @return bool true/false
  858. * */
  859. public static function check_readonly(
  860. $_course,
  861. $user_id,
  862. $file = null,
  863. $document_id = 0,
  864. $to_delete = false,
  865. $sessionId = null,
  866. $documentId = null
  867. ) {
  868. if (empty($sessionId)) {
  869. $sessionId = api_get_session_id();
  870. } else {
  871. $sessionId = intval($sessionId);
  872. }
  873. if (empty($document_id) || !is_numeric($document_id)) {
  874. $document_id = self::get_document_id($_course, $file, $sessionId);
  875. } else {
  876. $document_id = intval($document_id);
  877. }
  878. $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  879. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  880. $course_id = $_course['real_id'];
  881. if ($to_delete) {
  882. if (self::is_folder($_course, $document_id)) {
  883. if (!empty($file)) {
  884. $path = Database::escape_string($file);
  885. // Check
  886. $sql = "SELECT td.id, readonly, tp.insert_user_id
  887. FROM $TABLE_DOCUMENT td
  888. INNER JOIN $TABLE_PROPERTY tp
  889. ON (td.c_id = tp.c_id AND tp.ref= td.id)
  890. WHERE
  891. td.c_id = $course_id AND
  892. tp.c_id = $course_id AND
  893. td.session_id = $sessionId AND
  894. (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
  895. // Get all id's of documents that are deleted
  896. $what_to_check_result = Database::query($sql);
  897. if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
  898. // file with readonly set to 1 exist?
  899. $readonly_set = false;
  900. while ($row = Database::fetch_array($what_to_check_result)) {
  901. //query to delete from item_property table
  902. if ($row['readonly'] == 1) {
  903. if (!($row['insert_user_id'] == $user_id)) {
  904. $readonly_set = true;
  905. break;
  906. }
  907. }
  908. }
  909. if ($readonly_set) {
  910. return true;
  911. }
  912. }
  913. }
  914. return false;
  915. }
  916. }
  917. if (!empty($document_id)) {
  918. $sql = "SELECT a.insert_user_id, b.readonly
  919. FROM $TABLE_PROPERTY a
  920. INNER JOIN $TABLE_DOCUMENT b
  921. ON (a.c_id = b.c_id AND a.ref= b.id)
  922. WHERE
  923. a.c_id = $course_id AND
  924. b.c_id = $course_id AND
  925. a.ref = $document_id
  926. LIMIT 1";
  927. $result = Database::query($sql);
  928. $doc_details = Database::fetch_array($result, 'ASSOC');
  929. if ($doc_details['readonly'] == 1) {
  930. return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
  931. }
  932. }
  933. return false;
  934. }
  935. /**
  936. * This check if a document is a folder or not.
  937. *
  938. * @param array $_course
  939. * @param int $id document id
  940. *
  941. * @return bool true/false
  942. * */
  943. public static function is_folder($_course, $id)
  944. {
  945. $table = Database::get_course_table(TABLE_DOCUMENT);
  946. if (empty($_course)) {
  947. return false;
  948. }
  949. $course_id = $_course['real_id'];
  950. $id = (int) $id;
  951. $sql = "SELECT filetype FROM $table
  952. WHERE c_id = $course_id AND id= $id";
  953. $result = Database::fetch_array(Database::query($sql), 'ASSOC');
  954. return $result['filetype'] == 'folder';
  955. }
  956. /**
  957. * @param int $document_id
  958. * @param array $course_info
  959. * @param int $session_id
  960. * @param bool $remove_content_from_db
  961. */
  962. public static function deleteDocumentFromDb(
  963. $document_id,
  964. $course_info = [],
  965. $session_id = 0,
  966. $remove_content_from_db = false
  967. ) {
  968. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  969. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  970. // Deleting from the DB
  971. $user_id = api_get_user_id();
  972. $document_id = (int) $document_id;
  973. if (empty($course_info)) {
  974. $course_info = api_get_course_info();
  975. }
  976. if (empty($session_id)) {
  977. $session_id = api_get_session_id();
  978. }
  979. // Soft DB delete
  980. api_item_property_update(
  981. $course_info,
  982. TOOL_DOCUMENT,
  983. $document_id,
  984. 'delete',
  985. $user_id,
  986. null,
  987. null,
  988. null,
  989. null,
  990. $session_id
  991. );
  992. self::delete_document_from_search_engine($course_info['code'], $document_id);
  993. self::unset_document_as_template($document_id, $course_info['code'], $user_id);
  994. //Hard DB delete
  995. if ($remove_content_from_db) {
  996. $sql = "DELETE FROM $TABLE_ITEMPROPERTY
  997. WHERE
  998. c_id = {$course_info['real_id']} AND
  999. ref = ".$document_id." AND
  1000. tool='".TOOL_DOCUMENT."'";
  1001. Database::query($sql);
  1002. $sql = "DELETE FROM $TABLE_DOCUMENT
  1003. WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
  1004. Database::query($sql);
  1005. }
  1006. }
  1007. /**
  1008. * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
  1009. * Files/folders that are inside a deleted folder get visibility 2.
  1010. *
  1011. * @param array $_course
  1012. * @param string $path Path stored in the database
  1013. * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
  1014. * @param int $sessionId The ID of the session, if any
  1015. * @param int $documentId The document id, if available
  1016. * @param int $groupId iid
  1017. *
  1018. * @return bool true/false
  1019. *
  1020. * @todo now only files/folders in a folder get visibility 2, we should rename them too.
  1021. * @todo We should be able to get rid of this later when using only documentId (check further usage)
  1022. */
  1023. public static function delete_document(
  1024. $_course,
  1025. $path = null,
  1026. $base_work_dir = null,
  1027. $sessionId = null,
  1028. $documentId = null,
  1029. $groupId = 0
  1030. ) {
  1031. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  1032. $documentId = (int) $documentId;
  1033. $groupId = (int) $groupId;
  1034. if (empty($groupId)) {
  1035. $groupId = api_get_group_id();
  1036. }
  1037. $sessionId = (int) $sessionId;
  1038. if (empty($sessionId)) {
  1039. $sessionId = api_get_session_id();
  1040. }
  1041. $course_id = $_course['real_id'];
  1042. if (empty($course_id)) {
  1043. return false;
  1044. }
  1045. if (empty($base_work_dir)) {
  1046. return false;
  1047. }
  1048. if (empty($documentId)) {
  1049. $documentId = self::get_document_id($_course, $path, $sessionId);
  1050. $docInfo = self::get_document_data_by_id(
  1051. $documentId,
  1052. $_course['code'],
  1053. false,
  1054. $sessionId
  1055. );
  1056. $path = $docInfo['path'];
  1057. } else {
  1058. $docInfo = self::get_document_data_by_id(
  1059. $documentId,
  1060. $_course['code'],
  1061. false,
  1062. $sessionId
  1063. );
  1064. if (empty($docInfo)) {
  1065. return false;
  1066. }
  1067. $path = $docInfo['path'];
  1068. }
  1069. if (empty($path) || empty($docInfo) || empty($documentId)) {
  1070. return false;
  1071. }
  1072. $itemInfo = api_get_item_property_info(
  1073. $_course['real_id'],
  1074. TOOL_DOCUMENT,
  1075. $documentId,
  1076. $sessionId,
  1077. $groupId
  1078. );
  1079. if (empty($itemInfo)) {
  1080. return false;
  1081. }
  1082. // File was already deleted.
  1083. if ($itemInfo['lastedit_type'] == 'DocumentDeleted' ||
  1084. $itemInfo['lastedit_type'] == 'delete' ||
  1085. $itemInfo['visibility'] == 2
  1086. ) {
  1087. return false;
  1088. }
  1089. // Filtering by group.
  1090. if ($itemInfo['to_group_id'] != $groupId) {
  1091. return false;
  1092. }
  1093. $document_exists_in_disk = file_exists($base_work_dir.$path);
  1094. $new_path = $path.'_DELETED_'.$documentId;
  1095. $file_deleted_from_db = false;
  1096. $file_deleted_from_disk = false;
  1097. $file_renamed_from_disk = false;
  1098. if ($documentId) {
  1099. // Deleting doc from the DB.
  1100. self::deleteDocumentFromDb($documentId, $_course, $sessionId);
  1101. // Checking
  1102. // $file_exists_in_db = self::get_document_data_by_id($documentId, $_course['code']);
  1103. $file_deleted_from_db = true;
  1104. }
  1105. // Looking for children.
  1106. if ($docInfo['filetype'] == 'folder') {
  1107. $cleanPath = Database::escape_string($path);
  1108. // Deleted files inside this folder.
  1109. $sql = "SELECT id FROM $TABLE_DOCUMENT
  1110. WHERE
  1111. c_id = $course_id AND
  1112. session_id = $sessionId AND
  1113. path LIKE BINARY '".$cleanPath."/%'";
  1114. // Get all id's of documents that are deleted.
  1115. $result = Database::query($sql);
  1116. if ($result && Database::num_rows($result) != 0) {
  1117. // Recursive delete.
  1118. while ($row = Database::fetch_array($result)) {
  1119. self::delete_document(
  1120. $_course,
  1121. null,
  1122. $base_work_dir,
  1123. $sessionId,
  1124. $row['id'],
  1125. $groupId
  1126. );
  1127. }
  1128. }
  1129. }
  1130. if ($document_exists_in_disk) {
  1131. if (api_get_setting('permanently_remove_deleted_files') === 'true') {
  1132. // Delete documents, do it like this so metadata gets deleted too
  1133. my_delete($base_work_dir.$path);
  1134. // Hard delete.
  1135. self::deleteDocumentFromDb($documentId, $_course, $sessionId, true);
  1136. $file_deleted_from_disk = true;
  1137. } else {
  1138. // Set visibility to 2 and rename file/folder to xxx_DELETED_#id (soft delete)
  1139. if (is_file($base_work_dir.$path) || is_dir($base_work_dir.$path)) {
  1140. if (rename($base_work_dir.$path, $base_work_dir.$new_path)) {
  1141. $new_path = Database::escape_string($new_path);
  1142. $sql = "UPDATE $TABLE_DOCUMENT
  1143. SET path = '".$new_path."'
  1144. WHERE
  1145. c_id = $course_id AND
  1146. session_id = $sessionId AND
  1147. id = ".$documentId;
  1148. Database::query($sql);
  1149. // Soft delete.
  1150. self::deleteDocumentFromDb($documentId, $_course, $sessionId);
  1151. // Change path of sub folders and documents in database.
  1152. $old_item_path = $docInfo['path'];
  1153. $new_item_path = $new_path.substr($old_item_path, strlen($path));
  1154. $new_item_path = Database::escape_string($new_item_path);
  1155. $sql = "UPDATE $TABLE_DOCUMENT
  1156. SET path = '".$new_item_path."'
  1157. WHERE
  1158. c_id = $course_id AND
  1159. session_id = $sessionId AND
  1160. id = ".$documentId;
  1161. Database::query($sql);
  1162. $file_renamed_from_disk = true;
  1163. } else {
  1164. // Couldn't rename - file permissions problem?
  1165. error_log(
  1166. __FILE__.' '.__LINE__.': Error renaming '.$base_work_dir.$path.' to '.$base_work_dir.$new_path.'. This is probably due to file permissions',
  1167. 0
  1168. );
  1169. }
  1170. }
  1171. }
  1172. }
  1173. // Checking inconsistency
  1174. //error_log('Doc status: (1 del db :'.($file_deleted_from_db?'yes':'no').') - (2 del disk: '.($file_deleted_from_disk?'yes':'no').') - (3 ren disk: '.($file_renamed_from_disk?'yes':'no').')');
  1175. if ($file_deleted_from_db && $file_deleted_from_disk ||
  1176. $file_deleted_from_db && $file_renamed_from_disk
  1177. ) {
  1178. return true;
  1179. } else {
  1180. //Something went wrong
  1181. //The file or directory isn't there anymore (on the filesystem)
  1182. // This means it has been removed externally. To prevent a
  1183. // blocking error from happening, we drop the related items from the
  1184. // item_property and the document table.
  1185. error_log(
  1186. __FILE__.' '.__LINE__.': System inconsistency detected. The file or directory '.$base_work_dir.$path.' seems to have been removed from the filesystem independently from the web platform. To restore consistency, the elements using the same path will be removed from the database',
  1187. 0
  1188. );
  1189. return false;
  1190. }
  1191. }
  1192. /**
  1193. * Removes documents from search engine database.
  1194. *
  1195. * @param string $course_id Course code
  1196. * @param int $document_id Document id to delete
  1197. */
  1198. public static function delete_document_from_search_engine($course_id, $document_id)
  1199. {
  1200. // remove from search engine if enabled
  1201. if (api_get_setting('search_enabled') === 'true') {
  1202. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1203. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  1204. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
  1205. $res = Database::query($sql);
  1206. if (Database::num_rows($res) > 0) {
  1207. $row2 = Database::fetch_array($res);
  1208. $di = new ChamiloIndexer();
  1209. $di->remove_document($row2['search_did']);
  1210. }
  1211. $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  1212. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
  1213. Database::query($sql);
  1214. // remove terms from db
  1215. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  1216. delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
  1217. }
  1218. }
  1219. /**
  1220. * Gets the id of a document with a given path.
  1221. *
  1222. * @param array $courseInfo
  1223. * @param string $path
  1224. * @param int $sessionId
  1225. *
  1226. * @return int id of document / false if no doc found
  1227. */
  1228. public static function get_document_id($courseInfo, $path, $sessionId = null)
  1229. {
  1230. $table = Database::get_course_table(TABLE_DOCUMENT);
  1231. $courseId = $courseInfo['real_id'];
  1232. if (!isset($sessionId)) {
  1233. $sessionId = api_get_session_id();
  1234. } else {
  1235. $sessionId = intval($sessionId);
  1236. }
  1237. $path = Database::escape_string($path);
  1238. if (!empty($courseId) && !empty($path)) {
  1239. $sql = "SELECT id FROM $table
  1240. WHERE
  1241. c_id = $courseId AND
  1242. path LIKE BINARY '$path' AND
  1243. session_id = $sessionId
  1244. LIMIT 1";
  1245. $result = Database::query($sql);
  1246. if (Database::num_rows($result)) {
  1247. $row = Database::fetch_array($result);
  1248. return intval($row['id']);
  1249. }
  1250. }
  1251. return false;
  1252. }
  1253. /**
  1254. * Gets the document data with a given id.
  1255. *
  1256. * @param int $id Document Id (id field in c_document table)
  1257. * @param string $course_code Course code
  1258. * @param bool $load_parents load folder parents
  1259. * @param int $session_id The session ID,
  1260. * 0 if requires context *out of* session, and null to use global context
  1261. * @param bool $ignoreDeleted
  1262. *
  1263. * @return array document content
  1264. */
  1265. public static function get_document_data_by_id(
  1266. $id,
  1267. $course_code,
  1268. $load_parents = false,
  1269. $session_id = null,
  1270. $ignoreDeleted = false
  1271. ) {
  1272. $course_info = api_get_course_info($course_code);
  1273. $course_id = $course_info['real_id'];
  1274. if (empty($course_info)) {
  1275. return false;
  1276. }
  1277. $session_id = empty($session_id) ? api_get_session_id() : (int) $session_id;
  1278. $groupId = api_get_group_id();
  1279. $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
  1280. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  1281. $id = (int) $id;
  1282. $sessionCondition = api_get_session_condition($session_id, true, true);
  1283. $sql = "SELECT * FROM $TABLE_DOCUMENT
  1284. WHERE c_id = $course_id $sessionCondition AND id = $id";
  1285. if ($ignoreDeleted) {
  1286. $sql .= " AND path NOT LIKE '%_DELETED_%' ";
  1287. }
  1288. $result = Database::query($sql);
  1289. $courseParam = '&cidReq='.$course_code.'&id='.$id.'&id_session='.$session_id.'&gidReq='.$groupId;
  1290. if ($result && Database::num_rows($result) == 1) {
  1291. $row = Database::fetch_array($result, 'ASSOC');
  1292. //@todo need to clarify the name of the URLs not nice right now
  1293. $url_path = urlencode($row['path']);
  1294. $path = str_replace('%2F', '/', $url_path);
  1295. $pathinfo = pathinfo($row['path']);
  1296. $row['url'] = api_get_path(WEB_CODE_PATH).'document/showinframes.php?id='.$id.$courseParam;
  1297. $row['document_url'] = api_get_path(WEB_CODE_PATH).'document/document.php?id='.$id.$courseParam;
  1298. $row['absolute_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
  1299. $row['absolute_path_from_document'] = '/document'.$row['path'];
  1300. $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'].'/';
  1301. $row['direct_url'] = $www.$path;
  1302. $row['basename'] = basename($row['path']);
  1303. if (dirname($row['path']) == '.') {
  1304. $row['parent_id'] = '0';
  1305. } else {
  1306. $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
  1307. if (empty($row['parent_id'])) {
  1308. // Try one more with session id = 0
  1309. $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), 0);
  1310. }
  1311. }
  1312. $parents = [];
  1313. //Use to generate parents (needed for the breadcrumb)
  1314. //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
  1315. if ($load_parents) {
  1316. $dir_array = explode('/', $row['path']);
  1317. $dir_array = array_filter($dir_array);
  1318. $array_len = count($dir_array) + 1;
  1319. $real_dir = '';
  1320. for ($i = 1; $i < $array_len; $i++) {
  1321. $real_dir .= '/'.(isset($dir_array[$i]) ? $dir_array[$i] : '');
  1322. $parent_id = self::get_document_id($course_info, $real_dir);
  1323. if ($session_id != 0 && empty($parent_id)) {
  1324. $parent_id = self::get_document_id($course_info, $real_dir, 0);
  1325. }
  1326. if (!empty($parent_id)) {
  1327. $sub_document_data = self::get_document_data_by_id(
  1328. $parent_id,
  1329. $course_code,
  1330. false,
  1331. $session_id
  1332. );
  1333. if ($session_id != 0 and !$sub_document_data) {
  1334. $sub_document_data = self::get_document_data_by_id(
  1335. $parent_id,
  1336. $course_code,
  1337. false,
  1338. 0
  1339. );
  1340. }
  1341. //@todo add visibility here
  1342. $parents[] = $sub_document_data;
  1343. }
  1344. }
  1345. }
  1346. $row['parents'] = $parents;
  1347. return $row;
  1348. }
  1349. return false;
  1350. }
  1351. /**
  1352. * Allow to set a specific document as a new template for CKeditor
  1353. * for a particular user in a particular course.
  1354. *
  1355. * @param string $title
  1356. * @param string $description
  1357. * @param int $document_id_for_template the document id
  1358. * @param string $course_code
  1359. * @param int $user_id
  1360. * @param string $image
  1361. *
  1362. * @return bool
  1363. */
  1364. public static function set_document_as_template(
  1365. $title,
  1366. $description,
  1367. $document_id_for_template,
  1368. $course_code,
  1369. $user_id,
  1370. $image
  1371. ) {
  1372. // Database table definition
  1373. $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
  1374. $params = [
  1375. 'title' => $title,
  1376. 'description' => $description,
  1377. 'course_code' => $course_code,
  1378. 'user_id' => $user_id,
  1379. 'ref_doc' => $document_id_for_template,
  1380. 'image' => $image,
  1381. ];
  1382. Database::insert($table_template, $params);
  1383. return true;
  1384. }
  1385. /**
  1386. * Unset a document as template.
  1387. *
  1388. * @param int $document_id
  1389. * @param string $course_code
  1390. * @param int $user_id
  1391. */
  1392. public static function unset_document_as_template(
  1393. $document_id,
  1394. $course_code,
  1395. $user_id
  1396. ) {
  1397. $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
  1398. $course_code = Database::escape_string($course_code);
  1399. $user_id = intval($user_id);
  1400. $document_id = intval($document_id);
  1401. $sql = 'SELECT id FROM '.$table_template.'
  1402. WHERE
  1403. course_code="'.$course_code.'" AND
  1404. user_id="'.$user_id.'" AND
  1405. ref_doc="'.$document_id.'"';
  1406. $result = Database::query($sql);
  1407. $template_id = Database::result($result, 0, 0);
  1408. my_delete(api_get_path(SYS_CODE_PATH).'upload/template_thumbnails/'.$template_id.'.jpg');
  1409. $sql = 'DELETE FROM '.$table_template.'
  1410. WHERE
  1411. course_code="'.$course_code.'" AND
  1412. user_id="'.$user_id.'" AND
  1413. ref_doc="'.$document_id.'"';
  1414. Database::query($sql);
  1415. }
  1416. /**
  1417. * Return true if the documentpath have visibility=1 as
  1418. * item_property (you should use the is_visible_by_id).
  1419. *
  1420. * @param string $doc_path the relative complete path of the document
  1421. * @param array $course the _course array info of the document's course
  1422. * @param int
  1423. * @param string
  1424. *
  1425. * @return bool
  1426. */
  1427. public static function is_visible(
  1428. $doc_path,
  1429. $course,
  1430. $session_id = 0,
  1431. $file_type = 'file'
  1432. ) {
  1433. $docTable = Database::get_course_table(TABLE_DOCUMENT);
  1434. $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1435. $course_id = $course['real_id'];
  1436. // note the extra / at the end of doc_path to match every path in
  1437. // the document table that is part of the document path
  1438. $session_id = intval($session_id);
  1439. $condition = "AND d.session_id IN ('$session_id', '0') ";
  1440. // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
  1441. /*
  1442. When using hotpotatoes files, a new html files are generated
  1443. in the hotpotatoes folder to display the test.
  1444. The genuine html file is copied to math4.htm(user_id).t.html
  1445. Images files are not copied, and keep same name.
  1446. To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
  1447. In this case, we have to remove (user_id).t.html to check the visibility of the file
  1448. For images, we just check the path of the image file.
  1449. Exemple of hotpotatoes folder :
  1450. A.jpg
  1451. maths4-consigne.jpg
  1452. maths4.htm
  1453. maths4.htm1.t.html
  1454. maths4.htm52.t.html
  1455. maths4.htm654.t.html
  1456. omega.jpg
  1457. theta.jpg
  1458. */
  1459. if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
  1460. $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
  1461. }
  1462. if (!in_array($file_type, ['file', 'folder'])) {
  1463. $file_type = 'file';
  1464. }
  1465. $doc_path = Database::escape_string($doc_path).'/';
  1466. $sql = "SELECT visibility
  1467. FROM $docTable d
  1468. INNER JOIN $propTable ip
  1469. ON (d.id = ip.ref AND d.c_id = ip.c_id)
  1470. WHERE
  1471. d.c_id = $course_id AND
  1472. ip.c_id = $course_id AND
  1473. ip.tool = '".TOOL_DOCUMENT."' $condition AND
  1474. filetype = '$file_type' AND
  1475. locate(concat(path,'/'), '$doc_path')=1
  1476. ";
  1477. $result = Database::query($sql);
  1478. $is_visible = false;
  1479. if (Database::num_rows($result) > 0) {
  1480. $row = Database::fetch_array($result, 'ASSOC');
  1481. if ($row['visibility'] == 1) {
  1482. $is_visible = api_is_allowed_in_course() || api_is_platform_admin();
  1483. }
  1484. }
  1485. /* improved protection of documents viewable directly through the url:
  1486. incorporates the same protections of the course at the url of
  1487. documents:
  1488. access allowed for the whole world Open, access allowed for
  1489. users registered on the platform Private access, document accessible
  1490. only to course members (see the Users list), Completely closed;
  1491. the document is only accessible to the course admin and
  1492. teaching assistants.*/
  1493. //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
  1494. return $is_visible;
  1495. }
  1496. /**
  1497. * Return true if user can see a file.
  1498. *
  1499. * @param int document id
  1500. * @param array course info
  1501. * @param int
  1502. * @param int
  1503. * @param bool
  1504. *
  1505. * @return bool
  1506. */
  1507. public static function is_visible_by_id(
  1508. $doc_id,
  1509. $course_info,
  1510. $session_id,
  1511. $user_id,
  1512. $admins_can_see_everything = true,
  1513. $userIsSubscribed = null
  1514. ) {
  1515. $user_in_course = false;
  1516. //1. Checking the course array
  1517. if (empty($course_info)) {
  1518. $course_info = api_get_course_info();
  1519. if (empty($course_info)) {
  1520. return false;
  1521. }
  1522. }
  1523. $doc_id = (int) $doc_id;
  1524. $session_id = (int) $session_id;
  1525. // 2. Course and Session visibility are handle in local.inc.php/global.inc.php
  1526. // 3. Checking if user exist in course/session
  1527. if ($session_id == 0) {
  1528. if (is_null($userIsSubscribed)) {
  1529. $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
  1530. $user_id,
  1531. $course_info['code']
  1532. );
  1533. }
  1534. if ($userIsSubscribed === true || api_is_platform_admin()) {
  1535. $user_in_course = true;
  1536. }
  1537. // Check if course is open then we can consider that the student is registered to the course
  1538. if (isset($course_info) &&
  1539. in_array(
  1540. $course_info['visibility'],
  1541. [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
  1542. )
  1543. ) {
  1544. $user_in_course = true;
  1545. }
  1546. } else {
  1547. $user_status = SessionManager::get_user_status_in_course_session(
  1548. $user_id,
  1549. $course_info['real_id'],
  1550. $session_id
  1551. );
  1552. if (in_array($user_status, ['0', '2', '6'])) {
  1553. //is true if is an student, course session teacher or coach
  1554. $user_in_course = true;
  1555. }
  1556. if (api_is_platform_admin()) {
  1557. $user_in_course = true;
  1558. }
  1559. }
  1560. // 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
  1561. if ($user_in_course) {
  1562. // 4.1 Checking document visibility for a Course
  1563. if ($session_id == 0) {
  1564. $item_info = api_get_item_property_info(
  1565. $course_info['real_id'],
  1566. 'document',
  1567. $doc_id,
  1568. 0
  1569. );
  1570. if (isset($item_info['visibility'])) {
  1571. // True for admins if document exists
  1572. if ($admins_can_see_everything && api_is_platform_admin()) {
  1573. return true;
  1574. }
  1575. if ($item_info['visibility'] == 1) {
  1576. return true;
  1577. }
  1578. }
  1579. } else {
  1580. // 4.2 Checking document visibility for a Course in a Session
  1581. $item_info = api_get_item_property_info(
  1582. $course_info['real_id'],
  1583. 'document',
  1584. $doc_id,
  1585. 0
  1586. );
  1587. $item_info_in_session = api_get_item_property_info(
  1588. $course_info['real_id'],
  1589. 'document',
  1590. $doc_id,
  1591. $session_id
  1592. );
  1593. // True for admins if document exists
  1594. if (isset($item_info['visibility'])) {
  1595. if ($admins_can_see_everything && api_is_platform_admin()) {
  1596. return true;
  1597. }
  1598. }
  1599. if (isset($item_info_in_session['visibility'])) {
  1600. if ($item_info_in_session['visibility'] == 1) {
  1601. return true;
  1602. }
  1603. } else {
  1604. if ($item_info['visibility'] == 1) {
  1605. return true;
  1606. }
  1607. }
  1608. }
  1609. } elseif ($admins_can_see_everything && api_is_platform_admin()) {
  1610. return true;
  1611. }
  1612. return false;
  1613. }
  1614. /**
  1615. * Allow attach a certificate to a course.
  1616. *
  1617. * @todo move to certificate.lib.php
  1618. *
  1619. * @param string $course_id
  1620. * @param int $document_id
  1621. * @param int $session_id
  1622. */
  1623. public static function attach_gradebook_certificate($course_id, $document_id, $session_id = 0)
  1624. {
  1625. $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1626. $session_id = intval($session_id);
  1627. if (empty($session_id)) {
  1628. $session_id = api_get_session_id();
  1629. }
  1630. if (empty($session_id)) {
  1631. $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
  1632. } elseif ($session_id > 0) {
  1633. $sql_session = 'AND session_id='.intval($session_id);
  1634. } else {
  1635. $sql_session = '';
  1636. }
  1637. $sql = 'UPDATE '.$tbl_category.' SET document_id="'.intval($document_id).'"
  1638. WHERE course_code="'.Database::escape_string($course_id).'" '.$sql_session;
  1639. Database::query($sql);
  1640. }
  1641. /**
  1642. * get the document id of default certificate.
  1643. *
  1644. * @todo move to certificate.lib.php
  1645. *
  1646. * @param string $course_id
  1647. * @param int $session_id
  1648. *
  1649. * @return int The default certificate id
  1650. */
  1651. public static function get_default_certificate_id($course_id, $session_id = 0)
  1652. {
  1653. $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1654. $session_id = (int) $session_id;
  1655. if (empty($session_id)) {
  1656. $session_id = api_get_session_id();
  1657. }
  1658. if (empty($session_id)) {
  1659. $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
  1660. } elseif ($session_id > 0) {
  1661. $sql_session = 'AND session_id='.$session_id;
  1662. } else {
  1663. $sql_session = '';
  1664. }
  1665. $sql = 'SELECT document_id FROM '.$tbl_category.'
  1666. WHERE course_code="'.Database::escape_string($course_id).'" '.$sql_session;
  1667. $rs = Database::query($sql);
  1668. $num = Database::num_rows($rs);
  1669. if ($num == 0) {
  1670. return null;
  1671. }
  1672. $row = Database::fetch_array($rs);
  1673. return $row['document_id'];
  1674. }
  1675. /**
  1676. * Allow replace user info in file html.
  1677. *
  1678. * @param int $user_id
  1679. * @param string $course_code
  1680. * @param int $sessionId
  1681. * @param bool $is_preview
  1682. *
  1683. * @return array
  1684. */
  1685. public static function replace_user_info_into_html(
  1686. $user_id,
  1687. $course_code,
  1688. $sessionId,
  1689. $is_preview = false
  1690. ) {
  1691. $user_id = intval($user_id);
  1692. $course_info = api_get_course_info($course_code);
  1693. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1694. $course_id = $course_info['real_id'];
  1695. $document_id = self::get_default_certificate_id(
  1696. $course_code,
  1697. $sessionId
  1698. );
  1699. $my_content_html = null;
  1700. if ($document_id) {
  1701. $sql = "SELECT path FROM $tbl_document
  1702. WHERE c_id = $course_id AND id = $document_id";
  1703. $rs = Database::query($sql);
  1704. $new_content = '';
  1705. $all_user_info = [];
  1706. if (Database::num_rows($rs)) {
  1707. $row = Database::fetch_array($rs);
  1708. $filepath = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
  1709. if (is_file($filepath)) {
  1710. $my_content_html = file_get_contents($filepath);
  1711. }
  1712. $all_user_info = self::get_all_info_to_certificate(
  1713. $user_id,
  1714. $course_code,
  1715. $is_preview
  1716. );
  1717. $info_to_be_replaced_in_content_html = $all_user_info[0];
  1718. $info_to_replace_in_content_html = $all_user_info[1];
  1719. $new_content = str_replace(
  1720. $info_to_be_replaced_in_content_html,
  1721. $info_to_replace_in_content_html,
  1722. $my_content_html
  1723. );
  1724. }
  1725. return [
  1726. 'content' => $new_content,
  1727. 'variables' => $all_user_info,
  1728. ];
  1729. }
  1730. return [];
  1731. }
  1732. /**
  1733. * Return all content to replace and all content to be replace.
  1734. *
  1735. * @param int $user_id
  1736. * @param string $courseCode
  1737. * @param bool $is_preview
  1738. *
  1739. * @return array
  1740. */
  1741. public static function get_all_info_to_certificate($user_id, $courseCode, $is_preview = false)
  1742. {
  1743. $info_list = [];
  1744. $user_id = (int) $user_id;
  1745. $course_info = api_get_course_info($courseCode);
  1746. // Portal info
  1747. $organization_name = api_get_setting('Institution');
  1748. $portal_name = api_get_setting('siteName');
  1749. // Extra user data information
  1750. $extra_user_info_data = UserManager::get_extra_user_data(
  1751. $user_id,
  1752. false,
  1753. false,
  1754. false,
  1755. true
  1756. );
  1757. // get extra fields
  1758. $extraField = new ExtraField('user');
  1759. $extraFields = $extraField->get_all(['filter = ? AND visible_to_self = ?' => [1, 1]]);
  1760. // Student information
  1761. $user_info = api_get_user_info($user_id);
  1762. $first_name = $user_info['firstname'];
  1763. $last_name = $user_info['lastname'];
  1764. $username = $user_info['username'];
  1765. $official_code = $user_info['official_code'];
  1766. // Teacher information
  1767. $info_teacher_id = UserManager::get_user_id_of_course_admin_or_session_admin($course_info);
  1768. $teacher_info = api_get_user_info($info_teacher_id);
  1769. $teacher_first_name = $teacher_info['firstname'];
  1770. $teacher_last_name = $teacher_info['lastname'];
  1771. // info gradebook certificate
  1772. $info_grade_certificate = UserManager::get_info_gradebook_certificate($courseCode, $user_id);
  1773. $date_certificate = $info_grade_certificate['created_at'];
  1774. $date_long_certificate = '';
  1775. $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
  1776. if (!empty($date_certificate)) {
  1777. $date_long_certificate = api_convert_and_format_date($date_certificate);
  1778. $date_no_time = api_convert_and_format_date($date_certificate, DATE_FORMAT_LONG_NO_DAY);
  1779. }
  1780. if ($is_preview) {
  1781. $date_long_certificate = api_convert_and_format_date(api_get_utc_datetime());
  1782. $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
  1783. }
  1784. $url = api_get_path(WEB_PATH).'certificates/index.php?id='.$info_grade_certificate['id'];
  1785. $externalStyleFile = api_get_path(SYS_CSS_PATH).'themes/'.api_get_visual_theme().'/certificate.css';
  1786. $externalStyle = '';
  1787. if (is_file($externalStyleFile)) {
  1788. $externalStyle = file_get_contents($externalStyleFile);
  1789. }
  1790. $sessionId = api_get_session_id();
  1791. $timeInCourse = Tracking::get_time_spent_on_the_course($user_id, $course_info['real_id'], $sessionId);
  1792. $timeInCourse = api_time_to_hms($timeInCourse, ':', false, true);
  1793. $first = Tracking::get_first_connection_date_on_the_course($user_id, $course_info['real_id'], $sessionId, false);
  1794. $first = substr($first, 0, 10);
  1795. $last = Tracking::get_last_connection_date_on_the_course($user_id, $course_info, $sessionId, false);
  1796. $last = substr($last, 0, 10);
  1797. if ($first === $last) {
  1798. $startDateAndEndDate = get_lang('From').' '.$first;
  1799. } else {
  1800. $startDateAndEndDate = sprintf(
  1801. get_lang('FromDateXToDateY'),
  1802. $first,
  1803. $last
  1804. );
  1805. }
  1806. $courseDescription = new CourseDescription();
  1807. $description = $courseDescription->get_data_by_description_type(1, $course_info['real_id'], $sessionId);
  1808. $courseObjectives = '';
  1809. if ($description) {
  1810. $courseObjectives = $description['description_content'];
  1811. }
  1812. // Replace content
  1813. $info_to_replace_in_content_html = [
  1814. $first_name,
  1815. $last_name,
  1816. $username,
  1817. $organization_name,
  1818. $portal_name,
  1819. $teacher_first_name,
  1820. $teacher_last_name,
  1821. $official_code,
  1822. $date_long_certificate,
  1823. $date_no_time,
  1824. $courseCode,
  1825. $course_info['name'],
  1826. $info_grade_certificate['grade'],
  1827. $url,
  1828. '<a href="'.$url.'" target="_blank">'.get_lang('CertificateOnlineLink').'</a>',
  1829. '((certificate_barcode))',
  1830. $externalStyle,
  1831. $timeInCourse,
  1832. $startDateAndEndDate,
  1833. $courseObjectives,
  1834. ];
  1835. $tags = [
  1836. '((user_firstname))',
  1837. '((user_lastname))',
  1838. '((user_username))',
  1839. '((gradebook_institution))',
  1840. '((gradebook_sitename))',
  1841. '((teacher_firstname))',
  1842. '((teacher_lastname))',
  1843. '((official_code))',
  1844. '((date_certificate))',
  1845. '((date_certificate_no_time))',
  1846. '((course_code))',
  1847. '((course_title))',
  1848. '((gradebook_grade))',
  1849. '((certificate_link))',
  1850. '((certificate_link_html))',
  1851. '((certificate_barcode))',
  1852. '((external_style))',
  1853. '((time_in_course))',
  1854. '((start_date_and_end_date))',
  1855. '((course_objectives))',
  1856. ];
  1857. if (!empty($extraFields)) {
  1858. foreach ($extraFields as $extraField) {
  1859. $valueExtra = isset($extra_user_info_data[$extraField['variable']]) ? $extra_user_info_data[$extraField['variable']] : '';
  1860. $tags[] = '(('.strtolower($extraField['variable']).'))';
  1861. $info_to_replace_in_content_html[] = $valueExtra;
  1862. }
  1863. }
  1864. $info_list[] = $tags;
  1865. $info_list[] = $info_to_replace_in_content_html;
  1866. return $info_list;
  1867. }
  1868. /**
  1869. * Remove default certificate.
  1870. *
  1871. * @param string $course_id The course code
  1872. * @param int $default_certificate_id The document id of the default certificate
  1873. */
  1874. public static function remove_attach_certificate($course_id, $default_certificate_id)
  1875. {
  1876. if (empty($default_certificate_id)) {
  1877. return false;
  1878. }
  1879. $default_certificate = self::get_default_certificate_id($course_id);
  1880. if ((int) $default_certificate == (int) $default_certificate_id) {
  1881. $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1882. $session_id = api_get_session_id();
  1883. if ($session_id == 0 || is_null($session_id)) {
  1884. $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
  1885. } elseif ($session_id > 0) {
  1886. $sql_session = 'AND session_id='.intval($session_id);
  1887. } else {
  1888. $sql_session = '';
  1889. }
  1890. $sql = 'UPDATE '.$tbl_category.' SET document_id = null
  1891. WHERE
  1892. course_code = "'.Database::escape_string($course_id).'" AND
  1893. document_id="'.$default_certificate_id.'" '.$sql_session;
  1894. Database::query($sql);
  1895. }
  1896. }
  1897. /**
  1898. * Create directory certificate.
  1899. *
  1900. * @param array $courseInfo
  1901. */
  1902. public static function create_directory_certificate_in_course($courseInfo)
  1903. {
  1904. if (!empty($courseInfo)) {
  1905. $to_group_id = 0;
  1906. $to_user_id = null;
  1907. $course_dir = $courseInfo['path']."/document/";
  1908. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  1909. $base_work_dir = $sys_course_path.$course_dir;
  1910. $dir_name = '/certificates';
  1911. $post_dir_name = get_lang('CertificatesFiles');
  1912. $visibility_command = 'invisible';
  1913. $id = self::get_document_id_of_directory_certificate();
  1914. if (empty($id)) {
  1915. create_unexisting_directory(
  1916. $courseInfo,
  1917. api_get_user_id(),
  1918. api_get_session_id(),
  1919. $to_group_id,
  1920. $to_user_id,
  1921. $base_work_dir,
  1922. $dir_name,
  1923. $post_dir_name,
  1924. null,
  1925. false,
  1926. false
  1927. );
  1928. $id = self::get_document_id_of_directory_certificate();
  1929. if (empty($id)) {
  1930. $id = add_document(
  1931. $courseInfo,
  1932. $dir_name,
  1933. 'folder',
  1934. 0,
  1935. $post_dir_name,
  1936. null,
  1937. 0,
  1938. true,
  1939. $to_group_id,
  1940. 0,
  1941. 0,
  1942. false
  1943. );
  1944. }
  1945. if (!empty($id)) {
  1946. api_item_property_update(
  1947. $courseInfo,
  1948. TOOL_DOCUMENT,
  1949. $id,
  1950. $visibility_command,
  1951. api_get_user_id()
  1952. );
  1953. }
  1954. }
  1955. }
  1956. }
  1957. /**
  1958. * Get the document id of the directory certificate.
  1959. *
  1960. * @return int The document id of the directory certificate
  1961. *
  1962. * @todo move to certificate.lib.php
  1963. */
  1964. public static function get_document_id_of_directory_certificate()
  1965. {
  1966. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1967. $course_id = api_get_course_int_id();
  1968. $sql = "SELECT id FROM $tbl_document
  1969. WHERE c_id = $course_id AND path='/certificates' ";
  1970. $rs = Database::query($sql);
  1971. $row = Database::fetch_array($rs);
  1972. return $row['id'];
  1973. }
  1974. /**
  1975. * Check if a directory given is for certificate.
  1976. *
  1977. * @todo move to certificate.lib.php
  1978. *
  1979. * @param string $dir path of directory
  1980. *
  1981. * @return bool true if is a certificate or false otherwise
  1982. */
  1983. public static function is_certificate_mode($dir)
  1984. {
  1985. // I'm in the certification module?
  1986. $is_certificate_mode = false;
  1987. $is_certificate_array = explode('/', $dir);
  1988. array_shift($is_certificate_array);
  1989. if (isset($is_certificate_array[0]) && $is_certificate_array[0] == 'certificates') {
  1990. $is_certificate_mode = true;
  1991. }
  1992. return $is_certificate_mode || (isset($_GET['certificate']) && $_GET['certificate'] === 'true');
  1993. }
  1994. /**
  1995. * Gets the list of included resources as a list of absolute or relative paths from a html file or string html
  1996. * This allows for a better SCORM export or replace urls inside content html from copy course
  1997. * The list will generally include pictures, flash objects, java applets, or any other
  1998. * stuff included in the source of the current item. The current item is expected
  1999. * to be an HTML file or string html. If it is not, then the function will return and empty list.
  2000. *
  2001. * @param string source html (content or path)
  2002. * @param bool is file or string html
  2003. * @param string type (one of the app tools) - optional (otherwise takes the current item's type)
  2004. * @param int level of recursivity we're in
  2005. *
  2006. * @return array List of file paths. An additional field containing 'local' or 'remote' helps determine
  2007. * if the file should be copied into the zip or just linked
  2008. */
  2009. public static function get_resources_from_source_html(
  2010. $source_html,
  2011. $is_file = false,
  2012. $type = null,
  2013. $recursivity = 1
  2014. ) {
  2015. $max = 5;
  2016. $attributes = [];
  2017. $wanted_attributes = [
  2018. 'src',
  2019. 'url',
  2020. '@import',
  2021. 'href',
  2022. 'value',
  2023. 'flashvars',
  2024. 'poster',
  2025. ];
  2026. $explode_attributes = ['flashvars' => 'file'];
  2027. $abs_path = '';
  2028. if ($recursivity > $max) {
  2029. return [];
  2030. }
  2031. if (!isset($type)) {
  2032. $type = TOOL_DOCUMENT;
  2033. }
  2034. if (!$is_file) {
  2035. $attributes = self::parse_HTML_attributes(
  2036. $source_html,
  2037. $wanted_attributes,
  2038. $explode_attributes
  2039. );
  2040. } else {
  2041. if (is_file($source_html)) {
  2042. $abs_path = $source_html;
  2043. //for now, read the whole file in one go (that's gonna be a problem when the file is too big)
  2044. $info = pathinfo($abs_path);
  2045. $ext = $info['extension'];
  2046. switch (strtolower($ext)) {
  2047. case 'html':
  2048. case 'htm':
  2049. case 'shtml':
  2050. case 'css':
  2051. $file_content = file_get_contents($abs_path);
  2052. // get an array of attributes from the HTML source
  2053. $attributes = self::parse_HTML_attributes(
  2054. $file_content,
  2055. $wanted_attributes,
  2056. $explode_attributes
  2057. );
  2058. break;
  2059. default:
  2060. break;
  2061. }
  2062. } else {
  2063. return false;
  2064. }
  2065. }
  2066. $files_list = [];
  2067. switch ($type) {
  2068. case TOOL_DOCUMENT:
  2069. case TOOL_QUIZ:
  2070. case 'sco':
  2071. foreach ($wanted_attributes as $attr) {
  2072. if (isset($attributes[$attr])) {
  2073. //find which kind of path these are (local or remote)
  2074. $sources = $attributes[$attr];
  2075. foreach ($sources as $source) {
  2076. //skip what is obviously not a resource
  2077. if (strpos($source, '+this.')) {
  2078. continue; //javascript code - will still work unaltered
  2079. }
  2080. if (strpos($source, '.') === false) {
  2081. continue; //no dot, should not be an external file anyway
  2082. }
  2083. if (strpos($source, 'mailto:')) {
  2084. continue; //mailto link
  2085. }
  2086. if (strpos($source, ';') && !strpos($source, '&amp;')) {
  2087. continue; //avoid code - that should help
  2088. }
  2089. if ($attr == 'value') {
  2090. if (strpos($source, 'mp3file')) {
  2091. $files_list[] = [
  2092. substr($source, 0, strpos($source, '.swf') + 4),
  2093. 'local',
  2094. 'abs',
  2095. ];
  2096. $mp3file = substr($source, strpos($source, 'mp3file=') + 8);
  2097. if (substr($mp3file, 0, 1) == '/') {
  2098. $files_list[] = [$mp3file, 'local', 'abs'];
  2099. } else {
  2100. $files_list[] = [$mp3file, 'local', 'rel'];
  2101. }
  2102. } elseif (strpos($source, 'flv=') === 0) {
  2103. $source = substr($source, 4);
  2104. if (strpos($source, '&') > 0) {
  2105. $source = substr($source, 0, strpos($source, '&'));
  2106. }
  2107. if (strpos($source, '://') > 0) {
  2108. if (strpos($source, api_get_path(WEB_PATH)) !== false) {
  2109. //we found the current portal url
  2110. $files_list[] = [$source, 'local', 'url'];
  2111. } else {
  2112. //we didn't find any trace of current portal
  2113. $files_list[] = [$source, 'remote', 'url'];
  2114. }
  2115. } else {
  2116. $files_list[] = [$source, 'local', 'abs'];
  2117. }
  2118. /* skipping anything else to avoid two entries
  2119. (while the others can have sub-files in their url, flv's can't)*/
  2120. continue;
  2121. }
  2122. }
  2123. if (strpos($source, '://') > 0) {
  2124. //cut at '?' in a URL with params
  2125. if (strpos($source, '?') > 0) {
  2126. $second_part = substr($source, strpos($source, '?'));
  2127. if (strpos($second_part, '://') > 0) {
  2128. //if the second part of the url contains a url too, treat the second one before cutting
  2129. $pos1 = strpos($second_part, '=');
  2130. $pos2 = strpos($second_part, '&');
  2131. $second_part = substr($second_part, $pos1 + 1, $pos2 - ($pos1 + 1));
  2132. if (strpos($second_part, api_get_path(WEB_PATH)) !== false) {
  2133. //we found the current portal url
  2134. $files_list[] = [$second_part, 'local', 'url'];
  2135. $in_files_list[] = self::get_resources_from_source_html(
  2136. $second_part,
  2137. true,
  2138. TOOL_DOCUMENT,
  2139. $recursivity + 1
  2140. );
  2141. if (count($in_files_list) > 0) {
  2142. $files_list = array_merge($files_list, $in_files_list);
  2143. }
  2144. } else {
  2145. //we didn't find any trace of current portal
  2146. $files_list[] = [$second_part, 'remote', 'url'];
  2147. }
  2148. } elseif (strpos($second_part, '=') > 0) {
  2149. if (substr($second_part, 0, 1) === '/') {
  2150. //link starts with a /, making it absolute (relative to DocumentRoot)
  2151. $files_list[] = [$second_part, 'local', 'abs'];
  2152. $in_files_list[] = self::get_resources_from_source_html(
  2153. $second_part,
  2154. true,
  2155. TOOL_DOCUMENT,
  2156. $recursivity + 1
  2157. );
  2158. if (count($in_files_list) > 0) {
  2159. $files_list = array_merge($files_list, $in_files_list);
  2160. }
  2161. } elseif (strstr($second_part, '..') === 0) {
  2162. //link is relative but going back in the hierarchy
  2163. $files_list[] = [$second_part, 'local', 'rel'];
  2164. //$dir = api_get_path(SYS_CODE_PATH);//dirname($abs_path);
  2165. //$new_abs_path = realpath($dir.'/'.$second_part);
  2166. $dir = '';
  2167. if (!empty($abs_path)) {
  2168. $dir = dirname($abs_path).'/';
  2169. }
  2170. $new_abs_path = realpath($dir.$second_part);
  2171. $in_files_list[] = self::get_resources_from_source_html(
  2172. $new_abs_path,
  2173. true,
  2174. TOOL_DOCUMENT,
  2175. $recursivity + 1
  2176. );
  2177. if (count($in_files_list) > 0) {
  2178. $files_list = array_merge($files_list, $in_files_list);
  2179. }
  2180. } else {
  2181. //no starting '/', making it relative to current document's path
  2182. if (substr($second_part, 0, 2) == './') {
  2183. $second_part = substr($second_part, 2);
  2184. }
  2185. $files_list[] = [$second_part, 'local', 'rel'];
  2186. $dir = '';
  2187. if (!empty($abs_path)) {
  2188. $dir = dirname($abs_path).'/';
  2189. }
  2190. $new_abs_path = realpath($dir.$second_part);
  2191. $in_files_list[] = self::get_resources_from_source_html(
  2192. $new_abs_path,
  2193. true,
  2194. TOOL_DOCUMENT,
  2195. $recursivity + 1
  2196. );
  2197. if (count($in_files_list) > 0) {
  2198. $files_list = array_merge($files_list, $in_files_list);
  2199. }
  2200. }
  2201. }
  2202. //leave that second part behind now
  2203. $source = substr($source, 0, strpos($source, '?'));
  2204. if (strpos($source, '://') > 0) {
  2205. if (strpos($source, api_get_path(WEB_PATH)) !== false) {
  2206. //we found the current portal url
  2207. $files_list[] = [$source, 'local', 'url'];
  2208. $in_files_list[] = self::get_resources_from_source_html(
  2209. $source,
  2210. true,
  2211. TOOL_DOCUMENT,
  2212. $recursivity + 1
  2213. );
  2214. if (count($in_files_list) > 0) {
  2215. $files_list = array_merge($files_list, $in_files_list);
  2216. }
  2217. } else {
  2218. //we didn't find any trace of current portal
  2219. $files_list[] = [$source, 'remote', 'url'];
  2220. }
  2221. } else {
  2222. //no protocol found, make link local
  2223. if (substr($source, 0, 1) === '/') {
  2224. //link starts with a /, making it absolute (relative to DocumentRoot)
  2225. $files_list[] = [$source, 'local', 'abs'];
  2226. $in_files_list[] = self::get_resources_from_source_html(
  2227. $source,
  2228. true,
  2229. TOOL_DOCUMENT,
  2230. $recursivity + 1
  2231. );
  2232. if (count($in_files_list) > 0) {
  2233. $files_list = array_merge($files_list, $in_files_list);
  2234. }
  2235. } elseif (strstr($source, '..') === 0) {
  2236. //link is relative but going back in the hierarchy
  2237. $files_list[] = [$source, 'local', 'rel'];
  2238. $dir = '';
  2239. if (!empty($abs_path)) {
  2240. $dir = dirname($abs_path).'/';
  2241. }
  2242. $new_abs_path = realpath($dir.$source);
  2243. $in_files_list[] = self::get_resources_from_source_html(
  2244. $new_abs_path,
  2245. true,
  2246. TOOL_DOCUMENT,
  2247. $recursivity + 1
  2248. );
  2249. if (count($in_files_list) > 0) {
  2250. $files_list = array_merge($files_list, $in_files_list);
  2251. }
  2252. } else {
  2253. //no starting '/', making it relative to current document's path
  2254. if (substr($source, 0, 2) == './') {
  2255. $source = substr($source, 2);
  2256. }
  2257. $files_list[] = [$source, 'local', 'rel'];
  2258. $dir = '';
  2259. if (!empty($abs_path)) {
  2260. $dir = dirname($abs_path).'/';
  2261. }
  2262. $new_abs_path = realpath($dir.$source);
  2263. $in_files_list[] = self::get_resources_from_source_html(
  2264. $new_abs_path,
  2265. true,
  2266. TOOL_DOCUMENT,
  2267. $recursivity + 1
  2268. );
  2269. if (count($in_files_list) > 0) {
  2270. $files_list = array_merge($files_list, $in_files_list);
  2271. }
  2272. }
  2273. }
  2274. }
  2275. //found some protocol there
  2276. if (strpos($source, api_get_path(WEB_PATH)) !== false) {
  2277. //we found the current portal url
  2278. $files_list[] = [$source, 'local', 'url'];
  2279. $in_files_list[] = self::get_resources_from_source_html(
  2280. $source,
  2281. true,
  2282. TOOL_DOCUMENT,
  2283. $recursivity + 1
  2284. );
  2285. if (count($in_files_list) > 0) {
  2286. $files_list = array_merge($files_list, $in_files_list);
  2287. }
  2288. } else {
  2289. //we didn't find any trace of current portal
  2290. $files_list[] = [$source, 'remote', 'url'];
  2291. }
  2292. } else {
  2293. //no protocol found, make link local
  2294. if (substr($source, 0, 1) === '/') {
  2295. //link starts with a /, making it absolute (relative to DocumentRoot)
  2296. $files_list[] = [$source, 'local', 'abs'];
  2297. $in_files_list[] = self::get_resources_from_source_html(
  2298. $source,
  2299. true,
  2300. TOOL_DOCUMENT,
  2301. $recursivity + 1
  2302. );
  2303. if (count($in_files_list) > 0) {
  2304. $files_list = array_merge($files_list, $in_files_list);
  2305. }
  2306. } elseif (strpos($source, '..') === 0) {
  2307. //link is relative but going back in the hierarchy
  2308. $files_list[] = [$source, 'local', 'rel'];
  2309. $dir = '';
  2310. if (!empty($abs_path)) {
  2311. $dir = dirname($abs_path).'/';
  2312. }
  2313. $new_abs_path = realpath($dir.$source);
  2314. $in_files_list[] = self::get_resources_from_source_html(
  2315. $new_abs_path,
  2316. true,
  2317. TOOL_DOCUMENT,
  2318. $recursivity + 1
  2319. );
  2320. if (count($in_files_list) > 0) {
  2321. $files_list = array_merge($files_list, $in_files_list);
  2322. }
  2323. } else {
  2324. //no starting '/', making it relative to current document's path
  2325. if (substr($source, 0, 2) == './') {
  2326. $source = substr($source, 2);
  2327. }
  2328. $files_list[] = [$source, 'local', 'rel'];
  2329. $dir = '';
  2330. if (!empty($abs_path)) {
  2331. $dir = dirname($abs_path).'/';
  2332. }
  2333. $new_abs_path = realpath($dir.$source);
  2334. $in_files_list[] = self::get_resources_from_source_html(
  2335. $new_abs_path,
  2336. true,
  2337. TOOL_DOCUMENT,
  2338. $recursivity + 1
  2339. );
  2340. if (count($in_files_list) > 0) {
  2341. $files_list = array_merge($files_list, $in_files_list);
  2342. }
  2343. }
  2344. }
  2345. }
  2346. }
  2347. }
  2348. break;
  2349. default: //ignore
  2350. break;
  2351. }
  2352. $checked_files_list = [];
  2353. $checked_array_list = [];
  2354. if (count($files_list) > 0) {
  2355. foreach ($files_list as $idx => $file) {
  2356. if (!empty($file[0])) {
  2357. if (!in_array($file[0], $checked_files_list)) {
  2358. $checked_files_list[] = $files_list[$idx][0];
  2359. $checked_array_list[] = $files_list[$idx];
  2360. }
  2361. }
  2362. }
  2363. }
  2364. return $checked_array_list;
  2365. }
  2366. /**
  2367. * Parses the HTML attributes given as string.
  2368. *
  2369. * @param string HTML attribute string
  2370. * @param array List of attributes that we want to get back
  2371. * @param array
  2372. *
  2373. * @return array An associative array of attributes
  2374. *
  2375. * @author Based on a function from the HTML_Common2 PEAR module *
  2376. */
  2377. public static function parse_HTML_attributes($attrString, $wanted = [], $explode_variables = [])
  2378. {
  2379. $attributes = [];
  2380. $regs = [];
  2381. $reduced = false;
  2382. if (count($wanted) > 0) {
  2383. $reduced = true;
  2384. }
  2385. try {
  2386. //Find all occurences of something that looks like a URL
  2387. // The structure of this regexp is:
  2388. // (find protocol) then
  2389. // (optionally find some kind of space 1 or more times) then
  2390. // find (either an equal sign or a bracket) followed by an optional space
  2391. // followed by some text without quotes (between quotes itself or not)
  2392. // then possible closing brackets if we were in the opening bracket case
  2393. // OR something like @import()
  2394. $res = preg_match_all(
  2395. '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]*))'.
  2396. // '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]|[^\x00-\x7F])*)' . -> seems to be taking too much
  2397. // '/(((([A-Za-z_:])([^\x00-\x7F])*)' . -> takes only last letter of parameter name
  2398. '([ \n\t\r]+)?('.
  2399. // '(=([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+))' . -> doesn't restrict close enough to the url itself
  2400. '(=([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+))'.
  2401. '|'.
  2402. // '(\(([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)\))' . -> doesn't restrict close enough to the url itself
  2403. '(\(([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+)\))'.
  2404. '))'.
  2405. '|'.
  2406. // '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))?/', -> takes a lot (like 100's of thousands of empty possibilities)
  2407. '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))/',
  2408. $attrString,
  2409. $regs
  2410. );
  2411. } catch (Exception $e) {
  2412. error_log('Caught exception: '.$e->getMessage(), 0);
  2413. }
  2414. if ($res) {
  2415. for ($i = 0; $i < count($regs[1]); $i++) {
  2416. $name = trim($regs[3][$i]);
  2417. $check = trim($regs[0][$i]);
  2418. $value = trim($regs[10][$i]);
  2419. if (empty($value) and !empty($regs[13][$i])) {
  2420. $value = $regs[13][$i];
  2421. }
  2422. if (empty($name) && !empty($regs[16][$i])) {
  2423. $name = '@import';
  2424. $value = trim($regs[16][$i]);
  2425. }
  2426. if (!empty($name)) {
  2427. if (!$reduced || in_array(strtolower($name), $wanted)) {
  2428. if ($name == $check) {
  2429. $attributes[strtolower($name)][] = strtolower($name);
  2430. } else {
  2431. if (!empty($value) && ($value[0] == '\'' || $value[0] == '"')) {
  2432. $value = substr($value, 1, -1);
  2433. }
  2434. if ($value == 'API.LMSGetValue(name') {
  2435. $value = 'API.LMSGetValue(name)';
  2436. }
  2437. //Gets the xx.flv value from the string flashvars="width=320&height=240&autostart=false&file=xxx.flv&repeat=false"
  2438. if (isset($explode_variables[$name])) {
  2439. $value_modified = str_replace('&amp;', '&', $value);
  2440. $value_array = explode('&', $value_modified);
  2441. foreach ($value_array as $item) {
  2442. $itemParts = explode('=', $item);
  2443. $key = $itemParts[0];
  2444. $item_value = !empty($itemParts[1]) ? $itemParts[1] : '';
  2445. if ($key == $explode_variables[$name]) {
  2446. $attributes[strtolower($name)][] = $item_value;
  2447. }
  2448. }
  2449. }
  2450. $attributes[strtolower($name)][] = $value;
  2451. }
  2452. }
  2453. }
  2454. }
  2455. }
  2456. return $attributes;
  2457. }
  2458. /**
  2459. * Replace urls inside content html from a copy course.
  2460. *
  2461. * @param string $content_html
  2462. * @param string $origin_course_code
  2463. * @param string $destination_course_directory
  2464. * @param string $origin_course_path_from_zip
  2465. * @param string $origin_course_info_path
  2466. *
  2467. * @return string new content html with replaced urls or return false if content is not a string
  2468. */
  2469. public static function replaceUrlWithNewCourseCode(
  2470. $content_html,
  2471. $origin_course_code,
  2472. $destination_course_directory,
  2473. $origin_course_path_from_zip = null,
  2474. $origin_course_info_path = null
  2475. ) {
  2476. if (empty($content_html)) {
  2477. return false;
  2478. }
  2479. $orig_source_html = self::get_resources_from_source_html($content_html);
  2480. $orig_course_info = api_get_course_info($origin_course_code);
  2481. // Course does not exist in the current DB probably this came from a zip file?
  2482. if (empty($orig_course_info)) {
  2483. if (!empty($origin_course_path_from_zip)) {
  2484. $orig_course_path = $origin_course_path_from_zip.'/';
  2485. $orig_course_info_path = $origin_course_info_path;
  2486. }
  2487. } else {
  2488. $orig_course_path = api_get_path(SYS_COURSE_PATH).$orig_course_info['path'].'/';
  2489. $orig_course_info_path = $orig_course_info['path'];
  2490. }
  2491. $destination_course_code = CourseManager::getCourseCodeFromDirectory($destination_course_directory);
  2492. $destination_course_info = api_get_course_info($destination_course_code);
  2493. $dest_course_path = api_get_path(SYS_COURSE_PATH).$destination_course_directory.'/';
  2494. $dest_course_path_rel = api_get_path(REL_COURSE_PATH).$destination_course_directory.'/';
  2495. $user_id = api_get_user_id();
  2496. if (!empty($orig_source_html)) {
  2497. foreach ($orig_source_html as $source) {
  2498. // Get information about source url
  2499. $real_orig_url = $source[0]; // url
  2500. $scope_url = $source[1]; // scope (local, remote)
  2501. $type_url = $source[2]; // type (rel, abs, url)
  2502. // Get path and query from origin url
  2503. $orig_parse_url = parse_url($real_orig_url);
  2504. $real_orig_path = isset($orig_parse_url['path']) ? $orig_parse_url['path'] : null;
  2505. $real_orig_query = isset($orig_parse_url['query']) ? $orig_parse_url['query'] : null;
  2506. // Replace origin course code by destination course code from origin url query
  2507. $dest_url_query = '';
  2508. if (!empty($real_orig_query)) {
  2509. $dest_url_query = '?'.$real_orig_query;
  2510. if (strpos($dest_url_query, $origin_course_code) !== false) {
  2511. $dest_url_query = str_replace($origin_course_code, $destination_course_code, $dest_url_query);
  2512. }
  2513. }
  2514. if ($scope_url == 'local') {
  2515. if ($type_url == 'abs' || $type_url == 'rel') {
  2516. $document_file = strstr($real_orig_path, 'document');
  2517. if (strpos($real_orig_path, $document_file) !== false) {
  2518. $origin_filepath = $orig_course_path.$document_file;
  2519. $destination_filepath = $dest_course_path.$document_file;
  2520. // copy origin file inside destination course
  2521. if (file_exists($origin_filepath)) {
  2522. $filepath_dir = dirname($destination_filepath);
  2523. if (!is_dir($filepath_dir)) {
  2524. $perm = api_get_permissions_for_new_directories();
  2525. $result = @mkdir($filepath_dir, $perm, true);
  2526. if ($result) {
  2527. $filepath_to_add = str_replace(
  2528. [$dest_course_path, 'document'],
  2529. '',
  2530. $filepath_dir
  2531. );
  2532. //Add to item properties to the new folder
  2533. $doc_id = add_document(
  2534. $destination_course_info,
  2535. $filepath_to_add,
  2536. 'folder',
  2537. 0,
  2538. basename($filepath_to_add)
  2539. );
  2540. api_item_property_update(
  2541. $destination_course_info,
  2542. TOOL_DOCUMENT,
  2543. $doc_id,
  2544. 'FolderCreated',
  2545. $user_id,
  2546. null,
  2547. null,
  2548. null,
  2549. null
  2550. );
  2551. }
  2552. }
  2553. if (!file_exists($destination_filepath)) {
  2554. $result = @copy($origin_filepath, $destination_filepath);
  2555. if ($result) {
  2556. $filepath_to_add = str_replace(
  2557. [$dest_course_path, 'document'],
  2558. '',
  2559. $destination_filepath
  2560. );
  2561. $size = filesize($destination_filepath);
  2562. // Add to item properties to the file
  2563. $doc_id = add_document(
  2564. $destination_course_info,
  2565. $filepath_to_add,
  2566. 'file',
  2567. $size,
  2568. basename($filepath_to_add)
  2569. );
  2570. api_item_property_update(
  2571. $destination_course_info,
  2572. TOOL_DOCUMENT,
  2573. $doc_id,
  2574. 'FolderCreated',
  2575. $user_id,
  2576. null,
  2577. null,
  2578. null,
  2579. null
  2580. );
  2581. }
  2582. }
  2583. }
  2584. // Replace origin course path by destination course path.
  2585. if (strpos($content_html, $real_orig_url) !== false) {
  2586. $url_course_path = str_replace(
  2587. $orig_course_info_path.'/'.$document_file,
  2588. '',
  2589. $real_orig_path
  2590. );
  2591. // See BT#7780
  2592. $destination_url = $dest_course_path_rel.$document_file.$dest_url_query;
  2593. // If the course code doesn't exist in the path? what we do? Nothing! see BT#1985
  2594. if (strpos($real_orig_path, $origin_course_code) === false) {
  2595. $url_course_path = $real_orig_path;
  2596. $destination_url = $real_orig_path;
  2597. }
  2598. $content_html = str_replace($real_orig_url, $destination_url, $content_html);
  2599. }
  2600. }
  2601. // replace origin course code by destination course code from origin url
  2602. if (strpos($real_orig_url, '?') === 0) {
  2603. $dest_url = str_replace($origin_course_code, $destination_course_code, $real_orig_url);
  2604. $content_html = str_replace($real_orig_url, $dest_url, $content_html);
  2605. }
  2606. }
  2607. }
  2608. }
  2609. }
  2610. return $content_html;
  2611. }
  2612. /**
  2613. * Export document to PDF.
  2614. *
  2615. * @param int $document_id
  2616. * @param string $courseCode
  2617. * @param string $orientation
  2618. * @param bool $showHeaderAndFooter
  2619. */
  2620. public static function export_to_pdf(
  2621. $document_id,
  2622. $courseCode,
  2623. $orientation = 'landscape',
  2624. $showHeaderAndFooter = true
  2625. ) {
  2626. $course_data = api_get_course_info($courseCode);
  2627. $document_data = self::get_document_data_by_id($document_id, $courseCode);
  2628. $file_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/document'.$document_data['path'];
  2629. if ($orientation == 'landscape') {
  2630. $pageFormat = 'A4-L';
  2631. $pdfOrientation = 'L';
  2632. } else {
  2633. $pageFormat = 'A4';
  2634. $pdfOrientation = 'P';
  2635. }
  2636. $pdf = new PDF(
  2637. $pageFormat,
  2638. $pdfOrientation,
  2639. $showHeaderAndFooter ? [] : ['top' => 0, 'left' => 0, 'bottom' => 0, 'right' => 0]
  2640. );
  2641. if (api_get_configuration_value('use_alternative_document_pdf_footer')) {
  2642. $view = new Template('', false, false, false, true, false, false);
  2643. $template = $view->get_template('export/alt_pdf_footer.tpl');
  2644. $pdf->set_custom_footer([
  2645. 'html' => $view->fetch($template),
  2646. ]);
  2647. }
  2648. $pdf->html_to_pdf(
  2649. $file_path,
  2650. $document_data['title'],
  2651. $courseCode,
  2652. false,
  2653. $showHeaderAndFooter
  2654. );
  2655. }
  2656. /**
  2657. * Uploads a document.
  2658. *
  2659. * @param array $files the $_FILES variable
  2660. * @param string $path
  2661. * @param string $title
  2662. * @param string $comment
  2663. * @param int $unzip unzip or not the file
  2664. * @param string $ifExists overwrite, rename or warn (default)
  2665. * @param bool $index_document index document (search xapian module)
  2666. * @param bool $show_output print html messages
  2667. * @param string $fileKey
  2668. * @param bool $treat_spaces_as_hyphens
  2669. *
  2670. * @return array|bool
  2671. */
  2672. public static function upload_document(
  2673. $files,
  2674. $path,
  2675. $title = '',
  2676. $comment = '',
  2677. $unzip = 0,
  2678. $ifExists = '',
  2679. $index_document = false,
  2680. $show_output = false,
  2681. $fileKey = 'file',
  2682. $treat_spaces_as_hyphens = true
  2683. ) {
  2684. $course_info = api_get_course_info();
  2685. $sessionId = api_get_session_id();
  2686. $course_dir = $course_info['path'].'/document';
  2687. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  2688. $base_work_dir = $sys_course_path.$course_dir;
  2689. if (isset($files[$fileKey])) {
  2690. $uploadOk = process_uploaded_file($files[$fileKey], $show_output);
  2691. if ($uploadOk) {
  2692. $new_path = handle_uploaded_document(
  2693. $course_info,
  2694. $files[$fileKey],
  2695. $base_work_dir,
  2696. $path,
  2697. api_get_user_id(),
  2698. api_get_group_id(),
  2699. null,
  2700. $unzip,
  2701. $ifExists,
  2702. $show_output,
  2703. false,
  2704. null,
  2705. $sessionId,
  2706. $treat_spaces_as_hyphens
  2707. );
  2708. // When sending zip files
  2709. if ($new_path === true && $unzip == 1) {
  2710. return [
  2711. 'title' => $files[$fileKey]['name'],
  2712. 'url' => '#',
  2713. ];
  2714. }
  2715. if ($new_path) {
  2716. $documentId = self::get_document_id(
  2717. $course_info,
  2718. $new_path,
  2719. $sessionId
  2720. );
  2721. if (!empty($documentId)) {
  2722. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  2723. $params = [];
  2724. if (!empty($title)) {
  2725. $params['title'] = $title;
  2726. }
  2727. if (!empty($comment)) {
  2728. $params['comment'] = trim($comment);
  2729. }
  2730. Database::update(
  2731. $table_document,
  2732. $params,
  2733. [
  2734. 'id = ? AND c_id = ? ' => [
  2735. $documentId,
  2736. $course_info['real_id'],
  2737. ],
  2738. ]
  2739. );
  2740. }
  2741. if ($index_document) {
  2742. self::index_document(
  2743. $documentId,
  2744. $course_info['code'],
  2745. null,
  2746. $_POST['language'],
  2747. $_REQUEST,
  2748. $ifExists
  2749. );
  2750. }
  2751. if (!empty($documentId) && is_numeric($documentId)) {
  2752. $documentData = self::get_document_data_by_id(
  2753. $documentId,
  2754. $course_info['code'],
  2755. false,
  2756. $sessionId
  2757. );
  2758. return $documentData;
  2759. }
  2760. }
  2761. }
  2762. }
  2763. return false;
  2764. }
  2765. /**
  2766. * Obtains the text inside the file with the right parser.
  2767. */
  2768. public static function get_text_content($doc_path, $doc_mime)
  2769. {
  2770. // TODO: review w$ compatibility
  2771. // Use usual exec output lines array to store stdout instead of a temp file
  2772. // because we need to store it at RAM anyway before index on ChamiloIndexer object
  2773. $ret_val = null;
  2774. switch ($doc_mime) {
  2775. case 'text/plain':
  2776. $handle = fopen($doc_path, 'r');
  2777. $output = [fread($handle, filesize($doc_path))];
  2778. fclose($handle);
  2779. break;
  2780. case 'application/pdf':
  2781. exec("pdftotext $doc_path -", $output, $ret_val);
  2782. break;
  2783. case 'application/postscript':
  2784. $temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
  2785. exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
  2786. if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
  2787. return false;
  2788. }
  2789. exec("pdftotext $temp_file -", $output, $ret_val);
  2790. unlink($temp_file);
  2791. break;
  2792. case 'application/msword':
  2793. exec("catdoc $doc_path", $output, $ret_val);
  2794. break;
  2795. case 'text/html':
  2796. exec("html2text $doc_path", $output, $ret_val);
  2797. break;
  2798. case 'text/rtf':
  2799. // Note: correct handling of code pages in unrtf
  2800. // on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
  2801. exec("unrtf --text $doc_path", $output, $ret_val);
  2802. if ($ret_val == 127) { // command not found
  2803. return false;
  2804. }
  2805. // Avoid index unrtf comments
  2806. if (is_array($output) && count($output) > 1) {
  2807. $parsed_output = [];
  2808. foreach ($output as &$line) {
  2809. if (!preg_match('/^###/', $line, $matches)) {
  2810. if (!empty($line)) {
  2811. $parsed_output[] = $line;
  2812. }
  2813. }
  2814. }
  2815. $output = $parsed_output;
  2816. }
  2817. break;
  2818. case 'application/vnd.ms-powerpoint':
  2819. exec("catppt $doc_path", $output, $ret_val);
  2820. break;
  2821. case 'application/vnd.ms-excel':
  2822. exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
  2823. break;
  2824. }
  2825. $content = '';
  2826. if (!is_null($ret_val)) {
  2827. if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
  2828. return false;
  2829. }
  2830. }
  2831. if (isset($output)) {
  2832. foreach ($output as &$line) {
  2833. $content .= $line."\n";
  2834. }
  2835. return $content;
  2836. } else {
  2837. return false;
  2838. }
  2839. }
  2840. /**
  2841. * Calculates the total size of all documents in a course.
  2842. *
  2843. * @author Bert vanderkimpen
  2844. *
  2845. * @param int $course_id
  2846. * @param int $group_id (to calculate group document space)
  2847. * @param int $session_id
  2848. *
  2849. * @return int total size
  2850. */
  2851. public static function documents_total_space($course_id = null, $group_id = null, $session_id = null)
  2852. {
  2853. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2854. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  2855. $session_id = (int) $session_id;
  2856. $group_id = (int) $group_id;
  2857. $course_id = (int) $course_id;
  2858. if (!$course_id) {
  2859. $course_id = api_get_course_int_id();
  2860. }
  2861. $group_condition = '';
  2862. if ($group_id) {
  2863. $group_condition = " AND props.to_group_id='".$group_id."' ";
  2864. }
  2865. $session_condition = '';
  2866. if ($session_id) {
  2867. $session_condition = " AND props.session_id='".$session_id."' ";
  2868. }
  2869. $sql = "SELECT SUM(size)
  2870. FROM $TABLE_ITEMPROPERTY AS props
  2871. INNER JOIN $TABLE_DOCUMENT AS docs
  2872. ON (docs.id = props.ref AND props.c_id = docs.c_id)
  2873. WHERE
  2874. props.c_id = $course_id AND
  2875. docs.c_id = $course_id AND
  2876. props.tool = '".TOOL_DOCUMENT."' AND
  2877. props.visibility <> 2
  2878. $group_condition
  2879. $session_condition
  2880. ";
  2881. $result = Database::query($sql);
  2882. if ($result && Database::num_rows($result) != 0) {
  2883. $row = Database::fetch_row($result);
  2884. return (int) $row[0];
  2885. } else {
  2886. return 0;
  2887. }
  2888. }
  2889. /**
  2890. * Display the document quota in a simple way.
  2891. *
  2892. * Here we count 1 Kilobyte = 1024 Bytes, 1 Megabyte = 1048576 Bytes
  2893. */
  2894. public static function displaySimpleQuota($course_quota, $already_consumed_space)
  2895. {
  2896. $course_quota_m = round($course_quota / 1048576);
  2897. $already_consumed_space_m = round($already_consumed_space / 1048576, 2);
  2898. $percentage = $already_consumed_space / $course_quota * 100;
  2899. $percentage = round($percentage, 1);
  2900. $message = get_lang('YouAreCurrentlyUsingXOfYourX');
  2901. $message = sprintf($message, $already_consumed_space_m, $percentage.'%', $course_quota_m.' ');
  2902. return Display::div($message, ['id' => 'document_quota']);
  2903. }
  2904. /**
  2905. * Checks if there is enough place to add a file on a directory
  2906. * on the base of a maximum directory size allowed.
  2907. *
  2908. * @author Bert Vanderkimpen
  2909. *
  2910. * @param int $file_size size of the file in byte
  2911. * @param int $max_dir_space maximum size
  2912. *
  2913. * @return bool true if there is enough space, false otherwise
  2914. *
  2915. * @see enough_space() uses documents_total_space() function
  2916. */
  2917. public static function enough_space($file_size, $max_dir_space)
  2918. {
  2919. if ($max_dir_space) {
  2920. $already_filled_space = self::documents_total_space();
  2921. if (($file_size + $already_filled_space) > $max_dir_space) {
  2922. return false;
  2923. }
  2924. }
  2925. return true;
  2926. }
  2927. /**
  2928. * @param array $params count, url, extension
  2929. *
  2930. * @return string
  2931. */
  2932. public static function generateAudioJavascript($params = [])
  2933. {
  2934. $js = '
  2935. $(\'audio.audio_preview\').mediaelementplayer({
  2936. features: [\'playpause\'],
  2937. audioWidth: 30,
  2938. audioHeight: 30,
  2939. success: function(mediaElement, originalNode, instance) {
  2940. }
  2941. });';
  2942. return $js;
  2943. }
  2944. /**
  2945. * Shows a play icon next to the document title in the document list.
  2946. *
  2947. * @param string $documentWebPath
  2948. * @param array $documentInfo
  2949. *
  2950. * @return string
  2951. */
  2952. public static function generateAudioPreview($documentWebPath, $documentInfo)
  2953. {
  2954. $filePath = $documentWebPath.$documentInfo['path'];
  2955. $extension = $documentInfo['file_extension'];
  2956. $html = '<span class="preview"> <audio class="audio_preview skip" src="'.$filePath.'" type="audio/'.$extension.'" > </audio></span>';
  2957. return $html;
  2958. }
  2959. /**
  2960. * @param string $file
  2961. * @param string $extension
  2962. *
  2963. * @return string
  2964. */
  2965. public static function generateMediaPreview($file, $extension)
  2966. {
  2967. $id = api_get_unique_id();
  2968. switch ($extension) {
  2969. case 'mp3':
  2970. $document_data['file_extension'] = $extension;
  2971. $html = '<div style="margin: 0; position: absolute; top: 50%; left: 35%;">';
  2972. $html .= '<audio id="'.$id.'" controls="controls" src="'.$file.'" type="audio/mp3" ></audio></div>';
  2973. break;
  2974. default:
  2975. $html = '<video id="'.$id.'" controls>';
  2976. $html .= '<source src="'.$file.'" >';
  2977. $html .= '</video>';
  2978. break;
  2979. }
  2980. return $html;
  2981. }
  2982. /**
  2983. * @param array $course_info
  2984. * @param bool $lp_id
  2985. * @param string $target
  2986. * @param int $session_id
  2987. * @param bool $add_move_button
  2988. * @param string $filter_by_folder
  2989. * @param string $overwrite_url
  2990. * @param bool $showInvisibleFiles
  2991. * @param bool $showOnlyFolders
  2992. * @param int $folderId
  2993. * @param bool $addCloseButton
  2994. *
  2995. * @return string
  2996. */
  2997. public static function get_document_preview(
  2998. $course_info,
  2999. $lp_id = false,
  3000. $target = '',
  3001. $session_id = 0,
  3002. $add_move_button = false,
  3003. $filter_by_folder = null,
  3004. $overwrite_url = '',
  3005. $showInvisibleFiles = false,
  3006. $showOnlyFolders = false,
  3007. $folderId = false,
  3008. $addCloseButton = true
  3009. ) {
  3010. if (empty($course_info['real_id']) || empty($course_info['code']) || !is_array($course_info)) {
  3011. return '';
  3012. }
  3013. $user_id = api_get_user_id();
  3014. $userInfo = api_get_user_info();
  3015. $user_in_course = api_is_platform_admin();
  3016. if (!$user_in_course) {
  3017. if (CourseManager::is_course_teacher($user_id, $course_info['code'])) {
  3018. $user_in_course = true;
  3019. }
  3020. }
  3021. // Condition for the session
  3022. $session_id = (int) $session_id;
  3023. if (!$user_in_course) {
  3024. if (empty($session_id)) {
  3025. if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
  3026. $user_in_course = true;
  3027. }
  3028. // Check if course is open then we can consider that the student is registered to the course
  3029. if (isset($course_info) && in_array($course_info['visibility'], [2, 3])) {
  3030. $user_in_course = true;
  3031. }
  3032. } else {
  3033. $user_status = SessionManager::get_user_status_in_course_session(
  3034. $user_id,
  3035. $course_info['real_id'],
  3036. $session_id
  3037. );
  3038. //is true if is an student, course session teacher or coach
  3039. if (in_array($user_status, ['0', '2', '6'])) {
  3040. $user_in_course = true;
  3041. }
  3042. }
  3043. }
  3044. $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
  3045. $tbl_item_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
  3046. $condition_session = " AND (last.session_id = '$session_id' OR last.session_id = '0' OR last.session_id IS NULL)";
  3047. $add_folder_filter = null;
  3048. if (!empty($filter_by_folder)) {
  3049. $add_folder_filter = " AND docs.path LIKE '".Database::escape_string($filter_by_folder)."%'";
  3050. }
  3051. // If we are in LP display hidden folder https://support.chamilo.org/issues/6679
  3052. $lp_visibility_condition = null;
  3053. if ($lp_id) {
  3054. if ($showInvisibleFiles) {
  3055. $lp_visibility_condition .= ' OR last.visibility = 0';
  3056. }
  3057. }
  3058. $folderCondition = " AND docs.path LIKE '/%' ";
  3059. if (!api_is_allowed_to_edit()) {
  3060. $protectedFolders = self::getProtectedFolderFromStudent();
  3061. foreach ($protectedFolders as $folder) {
  3062. $folderCondition .= " AND docs.path NOT LIKE '$folder' ";
  3063. }
  3064. }
  3065. $parentData = [];
  3066. if ($folderId !== false) {
  3067. $parentData = self::get_document_data_by_id(
  3068. $folderId,
  3069. $course_info['code'],
  3070. false,
  3071. $session_id
  3072. );
  3073. if (!empty($parentData)) {
  3074. $cleanedPath = $parentData['path'];
  3075. $num = substr_count($cleanedPath, '/');
  3076. $notLikeCondition = '';
  3077. for ($i = 1; $i <= $num; $i++) {
  3078. $repeat = str_repeat('/%', $i + 1);
  3079. $notLikeCondition .= " AND docs.path NOT LIKE '".Database::escape_string($cleanedPath.$repeat)."' ";
  3080. }
  3081. $folderId = (int) $folderId;
  3082. $folderCondition = " AND
  3083. docs.id <> $folderId AND
  3084. docs.path LIKE '".$cleanedPath."/%'
  3085. $notLikeCondition
  3086. ";
  3087. } else {
  3088. $folderCondition = " AND docs.filetype = 'file' ";
  3089. }
  3090. }
  3091. $levelCondition = '';
  3092. if ($folderId === false) {
  3093. $levelCondition = " AND docs.path NOT LIKE'/%/%'";
  3094. }
  3095. $sql = "SELECT DISTINCT last.visibility, docs.*
  3096. FROM $tbl_item_prop AS last
  3097. INNER JOIN $tbl_doc AS docs
  3098. ON (docs.id = last.ref AND docs.c_id = last.c_id)
  3099. WHERE
  3100. docs.path NOT LIKE '%_DELETED_%' AND
  3101. last.tool = '".TOOL_DOCUMENT."' $condition_session AND
  3102. (last.visibility = '1' $lp_visibility_condition) AND
  3103. last.visibility <> 2 AND
  3104. docs.c_id = {$course_info['real_id']} AND
  3105. last.c_id = {$course_info['real_id']}
  3106. $folderCondition
  3107. $levelCondition
  3108. $add_folder_filter
  3109. ORDER BY docs.filetype DESC, docs.title ASC";
  3110. $res_doc = Database::query($sql);
  3111. $resources = Database::store_result($res_doc, 'ASSOC');
  3112. $return = '';
  3113. if ($lp_id == false && $addCloseButton) {
  3114. if ($folderId === false) {
  3115. $return .= Display::div(
  3116. Display::url(
  3117. Display::return_icon('close.png', get_lang('Close'), [], ICON_SIZE_SMALL),
  3118. ' javascript:void(0);',
  3119. ['id' => 'close_div_'.$course_info['real_id'].'_'.$session_id, 'class' => 'close_div']
  3120. ),
  3121. ['style' => 'position:absolute;right:10px']
  3122. );
  3123. }
  3124. }
  3125. // If you want to debug it, I advise you to do "echo" on the eval statements.
  3126. $newResources = [];
  3127. if (!empty($resources) && $user_in_course) {
  3128. foreach ($resources as $resource) {
  3129. $is_visible = self::is_visible_by_id(
  3130. $resource['id'],
  3131. $course_info,
  3132. $session_id,
  3133. api_get_user_id()
  3134. );
  3135. if ($showInvisibleFiles === false) {
  3136. if (!$is_visible) {
  3137. continue;
  3138. }
  3139. }
  3140. $newResources[] = $resource;
  3141. }
  3142. }
  3143. $label = get_lang('Documents');
  3144. $documents = [];
  3145. if ($folderId === false) {
  3146. $documents[$label] = [
  3147. 'id' => 0,
  3148. 'files' => $newResources,
  3149. ];
  3150. } else {
  3151. if (is_array($parentData)) {
  3152. $documents[$parentData['title']] = [
  3153. 'id' => (int) $folderId,
  3154. 'files' => $newResources,
  3155. ];
  3156. }
  3157. }
  3158. $writeResult = self::write_resources_tree(
  3159. $userInfo,
  3160. $course_info,
  3161. $session_id,
  3162. $documents,
  3163. $lp_id,
  3164. $target,
  3165. $add_move_button,
  3166. $overwrite_url,
  3167. $folderId
  3168. );
  3169. $return .= $writeResult;
  3170. $lpAjaxUrl = api_get_path(WEB_AJAX_PATH).'lp.ajax.php';
  3171. if ($lp_id === false) {
  3172. $url = $lpAjaxUrl.'?a=get_documents&lp_id=&cidReq='.$course_info['code'];
  3173. $return .= "<script>
  3174. $(function() {
  3175. $('.close_div').click(function() {
  3176. var course_id = this.id.split('_')[2];
  3177. var session_id = this.id.split('_')[3];
  3178. $('#document_result_'+course_id+'_'+session_id).hide();
  3179. $('.lp_resource').remove();
  3180. $('.document_preview_container').html('');
  3181. });
  3182. });
  3183. </script>";
  3184. } else {
  3185. // For LPs
  3186. $url = $lpAjaxUrl.'?a=get_documents&lp_id='.$lp_id.'&'.api_get_cidreq();
  3187. }
  3188. if (!empty($overwrite_url)) {
  3189. $url .= '&url='.urlencode(Security::remove_XSS($overwrite_url));
  3190. }
  3191. if ($add_move_button) {
  3192. $url .= '&add_move_button=1';
  3193. }
  3194. $return .= "<script>
  3195. function testResources(id, img) {
  3196. var numericId = id.split('_')[1];
  3197. var parentId = 'doc_id_'+numericId;
  3198. var tempId = 'temp_'+numericId;
  3199. var image = $('#'+img);
  3200. if (image.hasClass('open')) {
  3201. image.removeClass('open');
  3202. image.attr('src', '".Display::returnIconPath('nolines_plus.gif')."');
  3203. $('#'+id).show();
  3204. $('#'+tempId).hide();
  3205. } else {
  3206. image.addClass('open');
  3207. image.attr('src', '".Display::returnIconPath('nolines_minus.gif')."');
  3208. $('#'+id).hide();
  3209. $('#'+tempId).show();
  3210. var tempDiv = $('#'+parentId).find('#'+tempId);
  3211. if (tempDiv.length == 0) {
  3212. $.ajax({
  3213. type: 'GET',
  3214. async: false,
  3215. url: '".$url."',
  3216. data: 'folder_id='+numericId,
  3217. success: function(data) {
  3218. tempDiv = $('#doc_id_'+numericId).append('<div id='+tempId+'>'+data+'</div>');
  3219. }
  3220. });
  3221. }
  3222. }
  3223. }
  3224. </script>";
  3225. if (!$user_in_course) {
  3226. $return = '';
  3227. }
  3228. return $return;
  3229. }
  3230. /**
  3231. * Generate and return an HTML list of resources based on a given array.
  3232. * This list is used to show the course creator a list of available resources to choose from
  3233. * when creating a learning path.
  3234. *
  3235. * @param array $userInfo current user info
  3236. * @param array $course_info
  3237. * @param int $session_id
  3238. * @param array $documents
  3239. * @param bool $lp_id
  3240. * @param string $target
  3241. * @param bool $add_move_button
  3242. * @param string $overwrite_url
  3243. * @param int $folderId
  3244. *
  3245. * @return string
  3246. */
  3247. public static function write_resources_tree(
  3248. $userInfo,
  3249. $course_info,
  3250. $session_id,
  3251. $documents,
  3252. $lp_id = false,
  3253. $target = '',
  3254. $add_move_button = false,
  3255. $overwrite_url = '',
  3256. $folderId = false
  3257. ) {
  3258. $return = '';
  3259. if (!empty($documents)) {
  3260. foreach ($documents as $key => $resource) {
  3261. if (isset($resource['id']) && is_int($resource['id'])) {
  3262. $mainFolderResource = [
  3263. 'id' => $resource['id'],
  3264. 'title' => $key,
  3265. ];
  3266. if ($folderId === false) {
  3267. $return .= self::parseFolder($folderId, $mainFolderResource, $lp_id);
  3268. }
  3269. if (isset($resource['files'])) {
  3270. $return .= self::write_resources_tree(
  3271. $userInfo,
  3272. $course_info,
  3273. $session_id,
  3274. $resource['files'],
  3275. $lp_id,
  3276. $target,
  3277. $add_move_button,
  3278. $overwrite_url
  3279. );
  3280. }
  3281. $return .= '</div>';
  3282. $return .= '</ul>';
  3283. } else {
  3284. if ($resource['filetype'] === 'folder') {
  3285. $return .= self::parseFolder($folderId, $resource, $lp_id);
  3286. } else {
  3287. $return .= self::parseFile(
  3288. $userInfo,
  3289. $course_info,
  3290. $session_id,
  3291. $resource,
  3292. $lp_id,
  3293. $add_move_button,
  3294. $target,
  3295. $overwrite_url
  3296. );
  3297. }
  3298. }
  3299. }
  3300. }
  3301. return $return;
  3302. }
  3303. /**
  3304. * @param int $doc_id
  3305. * @param array $courseInfo
  3306. * @param int $sessionId
  3307. * @param int $user_id
  3308. * @param int $groupId iid
  3309. * @param bool $checkParentVisibility
  3310. *
  3311. * @return bool
  3312. */
  3313. public static function check_visibility_tree(
  3314. $doc_id,
  3315. $courseInfo,
  3316. $sessionId,
  3317. $user_id,
  3318. $groupId = 0,
  3319. $checkParentVisibility = true
  3320. ) {
  3321. if (empty($courseInfo)) {
  3322. return false;
  3323. }
  3324. $courseCode = $courseInfo['code'];
  3325. if (empty($courseCode)) {
  3326. return false;
  3327. }
  3328. $document_data = self::get_document_data_by_id(
  3329. $doc_id,
  3330. $courseCode,
  3331. null,
  3332. $sessionId
  3333. );
  3334. if ($sessionId != 0 && !$document_data) {
  3335. $document_data = self::get_document_data_by_id(
  3336. $doc_id,
  3337. $courseCode,
  3338. null,
  3339. 0
  3340. );
  3341. }
  3342. if (!empty($document_data)) {
  3343. // If admin or course teacher, allow anyway
  3344. if (api_is_platform_admin() || CourseManager::is_course_teacher($user_id, $courseCode)) {
  3345. return true;
  3346. }
  3347. if ($document_data['parent_id'] == false || empty($document_data['parent_id'])) {
  3348. if (!empty($groupId)) {
  3349. return true;
  3350. }
  3351. $visible = self::is_visible_by_id($doc_id, $courseInfo, $sessionId, $user_id);
  3352. return $visible;
  3353. } else {
  3354. $visible = self::is_visible_by_id($doc_id, $courseInfo, $sessionId, $user_id);
  3355. if (!$visible) {
  3356. return false;
  3357. } else {
  3358. if ($checkParentVisibility) {
  3359. return self::check_visibility_tree(
  3360. $document_data['parent_id'],
  3361. $courseInfo,
  3362. $sessionId,
  3363. $user_id,
  3364. $groupId
  3365. );
  3366. }
  3367. return true;
  3368. }
  3369. }
  3370. } else {
  3371. return false;
  3372. }
  3373. }
  3374. /**
  3375. * Index a given document.
  3376. *
  3377. * @param int Document ID inside its corresponding course
  3378. * @param string Course code
  3379. * @param int Session ID (not used yet)
  3380. * @param string Language of document's content (defaults to course language)
  3381. * @param array Array of specific fields (['code'=>'value',...])
  3382. * @param string What to do if the file already exists (default or overwrite)
  3383. * @param bool When set to true, this runs the indexer without actually saving anything to any database
  3384. *
  3385. * @return bool Returns true on presumed success, false on failure
  3386. */
  3387. public static function index_document(
  3388. $docid,
  3389. $course_code,
  3390. $session_id = 0,
  3391. $lang = 'english',
  3392. $specific_fields_values = [],
  3393. $if_exists = '',
  3394. $simulation = false
  3395. ) {
  3396. if (api_get_setting('search_enabled') !== 'true') {
  3397. return false;
  3398. }
  3399. if (empty($docid) or $docid != intval($docid)) {
  3400. return false;
  3401. }
  3402. if (empty($session_id)) {
  3403. $session_id = api_get_session_id();
  3404. }
  3405. $course_info = api_get_course_info($course_code);
  3406. $course_dir = $course_info['path'].'/document';
  3407. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  3408. $base_work_dir = $sys_course_path.$course_dir;
  3409. $course_id = $course_info['real_id'];
  3410. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  3411. $qry = "SELECT path, title FROM $table_document WHERE c_id = $course_id AND id = '$docid' LIMIT 1";
  3412. $result = Database::query($qry);
  3413. if (Database::num_rows($result) == 1) {
  3414. $row = Database::fetch_array($result);
  3415. $doc_path = api_get_path(SYS_COURSE_PATH).$course_dir.$row['path'];
  3416. //TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
  3417. // now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
  3418. $doc_mime = mime_content_type($doc_path);
  3419. $allowed_mime_types = self::file_get_mime_type(true);
  3420. // mime_content_type does not detect correctly some formats that
  3421. // are going to be supported for index, so an extensions array is used for the moment
  3422. if (empty($doc_mime)) {
  3423. $allowed_extensions = [
  3424. 'doc',
  3425. 'docx',
  3426. 'ppt',
  3427. 'pptx',
  3428. 'pps',
  3429. 'ppsx',
  3430. 'xls',
  3431. 'xlsx',
  3432. 'odt',
  3433. 'odp',
  3434. 'ods',
  3435. 'pdf',
  3436. 'txt',
  3437. 'rtf',
  3438. 'msg',
  3439. 'csv',
  3440. 'html',
  3441. 'htm',
  3442. ];
  3443. $extensions = preg_split("/[\/\\.]/", $doc_path);
  3444. $doc_ext = strtolower($extensions[count($extensions) - 1]);
  3445. if (in_array($doc_ext, $allowed_extensions)) {
  3446. switch ($doc_ext) {
  3447. case 'ppt':
  3448. case 'pps':
  3449. $doc_mime = 'application/vnd.ms-powerpoint';
  3450. break;
  3451. case 'xls':
  3452. $doc_mime = 'application/vnd.ms-excel';
  3453. break;
  3454. }
  3455. }
  3456. }
  3457. //@todo move this nightmare in a search controller or something like that!!! J.M
  3458. if (in_array($doc_mime, $allowed_mime_types)) {
  3459. $file_title = $row['title'];
  3460. $file_content = self::get_text_content($doc_path, $doc_mime);
  3461. $course_code = Database::escape_string($course_code);
  3462. $ic_slide = new IndexableChunk();
  3463. $ic_slide->addValue('title', $file_title);
  3464. $ic_slide->addCourseId($course_code);
  3465. $ic_slide->addToolId(TOOL_DOCUMENT);
  3466. $xapian_data = [
  3467. SE_COURSE_ID => $course_code,
  3468. SE_TOOL_ID => TOOL_DOCUMENT,
  3469. SE_DATA => ['doc_id' => $docid],
  3470. SE_USER => api_get_user_id(),
  3471. ];
  3472. $ic_slide->xapian_data = serialize($xapian_data);
  3473. $di = new ChamiloIndexer();
  3474. $return = $di->connectDb(null, null, $lang);
  3475. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  3476. $specific_fields = get_specific_field_list();
  3477. // process different depending on what to do if file exists
  3478. /**
  3479. * @TODO Find a way to really verify if the file had been
  3480. * overwriten. Now all work is done at
  3481. * handle_uploaded_document() and it's difficult to verify it
  3482. */
  3483. if (!empty($if_exists) && $if_exists == 'overwrite') {
  3484. // Overwrite the file on search engine
  3485. // Actually, it consists on a delete of terms from db,
  3486. // insert new ones, create a new search engine document,
  3487. // and remove the old one
  3488. // Get search_did
  3489. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  3490. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  3491. $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid);
  3492. $res = Database::query($sql);
  3493. if (Database::num_rows($res) > 0) {
  3494. $se_ref = Database::fetch_array($res);
  3495. if (!$simulation) {
  3496. $di->remove_document($se_ref['search_did']);
  3497. }
  3498. $all_specific_terms = '';
  3499. foreach ($specific_fields as $specific_field) {
  3500. if (!$simulation) {
  3501. delete_all_specific_field_value($course_code, $specific_field['id'], TOOL_DOCUMENT, $docid);
  3502. }
  3503. // Update search engine
  3504. if (isset($specific_fields_values[$specific_field['code']])) {
  3505. $sterms = trim($specific_fields_values[$specific_field['code']]);
  3506. } else { //if the specific field is not defined, force an empty one
  3507. $sterms = '';
  3508. }
  3509. $all_specific_terms .= ' '.$sterms;
  3510. $sterms = explode(',', $sterms);
  3511. foreach ($sterms as $sterm) {
  3512. $sterm = trim($sterm);
  3513. if (!empty($sterm)) {
  3514. $ic_slide->addTerm($sterm, $specific_field['code']);
  3515. // updated the last param here from $value to $sterm without being sure - see commit15464
  3516. if (!$simulation) {
  3517. add_specific_field_value(
  3518. $specific_field['id'],
  3519. $course_code,
  3520. TOOL_DOCUMENT,
  3521. $docid,
  3522. $sterm
  3523. );
  3524. }
  3525. }
  3526. }
  3527. }
  3528. // Add terms also to content to make terms findable by probabilistic search
  3529. $file_content = $all_specific_terms.' '.$file_content;
  3530. if (!$simulation) {
  3531. $ic_slide->addValue('content', $file_content);
  3532. $di->addChunk($ic_slide);
  3533. // Index and return a new search engine document id
  3534. $did = $di->index();
  3535. if ($did) {
  3536. // update the search_did on db
  3537. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  3538. $sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
  3539. $sql = sprintf($sql, $tbl_se_ref, (int) $did, (int) $se_ref['id']);
  3540. Database::query($sql);
  3541. }
  3542. }
  3543. }
  3544. } else {
  3545. // Add all terms
  3546. $all_specific_terms = '';
  3547. foreach ($specific_fields as $specific_field) {
  3548. if (isset($specific_fields_values[$specific_field['code']])) {
  3549. $sterms = trim($specific_fields_values[$specific_field['code']]);
  3550. } else { //if the specific field is not defined, force an empty one
  3551. $sterms = '';
  3552. }
  3553. $all_specific_terms .= ' '.$sterms;
  3554. if (!empty($sterms)) {
  3555. $sterms = explode(',', $sterms);
  3556. foreach ($sterms as $sterm) {
  3557. if (!$simulation) {
  3558. $ic_slide->addTerm(trim($sterm), $specific_field['code']);
  3559. add_specific_field_value(
  3560. $specific_field['id'],
  3561. $course_code,
  3562. TOOL_DOCUMENT,
  3563. $docid,
  3564. $sterm
  3565. );
  3566. }
  3567. }
  3568. }
  3569. }
  3570. // Add terms also to content to make terms findable by probabilistic search
  3571. $file_content = $all_specific_terms.' '.$file_content;
  3572. if (!$simulation) {
  3573. $ic_slide->addValue('content', $file_content);
  3574. $di->addChunk($ic_slide);
  3575. // Index and return search engine document id
  3576. $did = $di->index();
  3577. if ($did) {
  3578. // Save it to db
  3579. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  3580. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  3581. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  3582. $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid, $did);
  3583. Database::query($sql);
  3584. } else {
  3585. return false;
  3586. }
  3587. }
  3588. }
  3589. } else {
  3590. return false;
  3591. }
  3592. }
  3593. return true;
  3594. }
  3595. /**
  3596. * @return array
  3597. */
  3598. public static function get_web_odf_extension_list()
  3599. {
  3600. return ['ods', 'odt', 'odp'];
  3601. }
  3602. /**
  3603. * Set of extension allowed to use Jodconverter.
  3604. *
  3605. * @param $mode 'from'
  3606. * 'to'
  3607. * 'all'
  3608. * @param $format 'text'
  3609. * 'spreadsheet'
  3610. * 'presentation'
  3611. * 'drawing'
  3612. * 'all'
  3613. *
  3614. * @return array
  3615. */
  3616. public static function getJodconverterExtensionList($mode, $format)
  3617. {
  3618. $extensionList = [];
  3619. $extensionListFromText = [
  3620. 'odt',
  3621. 'sxw',
  3622. 'rtf',
  3623. 'doc',
  3624. 'docx',
  3625. 'wpd',
  3626. 'txt',
  3627. ];
  3628. $extensionListToText = [
  3629. 'pdf',
  3630. 'odt',
  3631. 'sxw',
  3632. 'rtf',
  3633. 'doc',
  3634. 'docx',
  3635. 'txt',
  3636. ];
  3637. $extensionListFromSpreadsheet = [
  3638. 'ods',
  3639. 'sxc',
  3640. 'xls',
  3641. 'xlsx',
  3642. 'csv',
  3643. 'tsv',
  3644. ];
  3645. $extensionListToSpreadsheet = [
  3646. 'pdf',
  3647. 'ods',
  3648. 'sxc',
  3649. 'xls',
  3650. 'xlsx',
  3651. 'csv',
  3652. 'tsv',
  3653. ];
  3654. $extensionListFromPresentation = [
  3655. 'odp',
  3656. 'sxi',
  3657. 'ppt',
  3658. 'pptx',
  3659. ];
  3660. $extensionListToPresentation = [
  3661. 'pdf',
  3662. 'swf',
  3663. 'odp',
  3664. 'sxi',
  3665. 'ppt',
  3666. 'pptx',
  3667. ];
  3668. $extensionListFromDrawing = ['odg'];
  3669. $extensionListToDrawing = ['svg', 'swf'];
  3670. if ($mode === 'from') {
  3671. if ($format === 'text') {
  3672. $extensionList = array_merge($extensionList, $extensionListFromText);
  3673. } elseif ($format === 'spreadsheet') {
  3674. $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
  3675. } elseif ($format === 'presentation') {
  3676. $extensionList = array_merge($extensionList, $extensionListFromPresentation);
  3677. } elseif ($format === 'drawing') {
  3678. $extensionList = array_merge($extensionList, $extensionListFromDrawing);
  3679. } elseif ($format === 'all') {
  3680. $extensionList = array_merge($extensionList, $extensionListFromText);
  3681. $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
  3682. $extensionList = array_merge($extensionList, $extensionListFromPresentation);
  3683. $extensionList = array_merge($extensionList, $extensionListFromDrawing);
  3684. }
  3685. } elseif ($mode === 'to') {
  3686. if ($format === 'text') {
  3687. $extensionList = array_merge($extensionList, $extensionListToText);
  3688. } elseif ($format === 'spreadsheet') {
  3689. $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
  3690. } elseif ($format === 'presentation') {
  3691. $extensionList = array_merge($extensionList, $extensionListToPresentation);
  3692. } elseif ($format === 'drawing') {
  3693. $extensionList = array_merge($extensionList, $extensionListToDrawing);
  3694. } elseif ($format === 'all') {
  3695. $extensionList = array_merge($extensionList, $extensionListToText);
  3696. $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
  3697. $extensionList = array_merge($extensionList, $extensionListToPresentation);
  3698. $extensionList = array_merge($extensionList, $extensionListToDrawing);
  3699. }
  3700. } elseif ($mode === 'all') {
  3701. if ($format === 'text') {
  3702. $extensionList = array_merge($extensionList, $extensionListFromText);
  3703. $extensionList = array_merge($extensionList, $extensionListToText);
  3704. } elseif ($format === 'spreadsheet') {
  3705. $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
  3706. $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
  3707. } elseif ($format === 'presentation') {
  3708. $extensionList = array_merge($extensionList, $extensionListFromPresentation);
  3709. $extensionList = array_merge($extensionList, $extensionListToPresentation);
  3710. } elseif ($format === 'drawing') {
  3711. $extensionList = array_merge($extensionList, $extensionListFromDrawing);
  3712. $extensionList = array_merge($extensionList, $extensionListToDrawing);
  3713. } elseif ($format === 'all') {
  3714. $extensionList = array_merge($extensionList, $extensionListFromText);
  3715. $extensionList = array_merge($extensionList, $extensionListToText);
  3716. $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
  3717. $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
  3718. $extensionList = array_merge($extensionList, $extensionListFromPresentation);
  3719. $extensionList = array_merge($extensionList, $extensionListToPresentation);
  3720. $extensionList = array_merge($extensionList, $extensionListFromDrawing);
  3721. $extensionList = array_merge($extensionList, $extensionListToDrawing);
  3722. }
  3723. }
  3724. return $extensionList;
  3725. }
  3726. /**
  3727. * Get Format type list by extension and mode.
  3728. *
  3729. * @param string $mode Mode to search format type list
  3730. *
  3731. * @example 'from'
  3732. * @example 'to'
  3733. *
  3734. * @param string $extension file extension to check file type
  3735. *
  3736. * @return array
  3737. */
  3738. public static function getFormatTypeListConvertor($mode = 'from', $extension)
  3739. {
  3740. $formatTypesList = [];
  3741. $formatTypes = ['text', 'spreadsheet', 'presentation', 'drawing'];
  3742. foreach ($formatTypes as $formatType) {
  3743. if (in_array($extension, self::getJodconverterExtensionList($mode, $formatType))) {
  3744. $formatTypesList[] = $formatType;
  3745. }
  3746. }
  3747. return $formatTypesList;
  3748. }
  3749. /**
  3750. * @param string $path
  3751. * @param bool $is_certificate_mode
  3752. *
  3753. * @return bool
  3754. */
  3755. public static function is_folder_to_avoid($path, $is_certificate_mode = false)
  3756. {
  3757. $foldersToAvoid = [
  3758. '/HotPotatoes_files',
  3759. '/certificates',
  3760. ];
  3761. $systemFolder = api_get_course_setting('show_system_folders');
  3762. if ($systemFolder == 1) {
  3763. $foldersToAvoid = [];
  3764. }
  3765. if (basename($path) == 'css') {
  3766. return true;
  3767. }
  3768. if ($is_certificate_mode == false) {
  3769. //Certificate results
  3770. if (strstr($path, 'certificates')) {
  3771. return true;
  3772. }
  3773. }
  3774. // Admin setting for Hide/Show the folders of all users
  3775. if (api_get_setting('show_users_folders') == 'false') {
  3776. $foldersToAvoid[] = '/shared_folder';
  3777. if (strstr($path, 'shared_folder_session_')) {
  3778. return true;
  3779. }
  3780. }
  3781. // Admin setting for Hide/Show Default folders to all users
  3782. if (api_get_setting('show_default_folders') == 'false') {
  3783. $foldersToAvoid[] = '/images';
  3784. $foldersToAvoid[] = '/flash';
  3785. $foldersToAvoid[] = '/audio';
  3786. $foldersToAvoid[] = '/video';
  3787. }
  3788. // Admin setting for Hide/Show chat history folder
  3789. if (api_get_setting('show_chat_folder') == 'false') {
  3790. $foldersToAvoid[] = '/chat_files';
  3791. }
  3792. if (is_array($foldersToAvoid)) {
  3793. return in_array($path, $foldersToAvoid);
  3794. } else {
  3795. return false;
  3796. }
  3797. }
  3798. /**
  3799. * @return array
  3800. */
  3801. public static function get_system_folders()
  3802. {
  3803. return [
  3804. '/certificates',
  3805. '/HotPotatoes_files',
  3806. '/chat_files',
  3807. '/images',
  3808. '/flash',
  3809. '/audio',
  3810. '/video',
  3811. '/shared_folder',
  3812. '/learning_path',
  3813. ];
  3814. }
  3815. /**
  3816. * @return array
  3817. */
  3818. public static function getProtectedFolderFromStudent()
  3819. {
  3820. return [
  3821. '/certificates',
  3822. '/HotPotatoes_files',
  3823. '/chat_files',
  3824. '/shared_folder',
  3825. '/learning_path',
  3826. ];
  3827. }
  3828. /**
  3829. * @param array $courseInfo
  3830. *
  3831. * @return string 'visible' or 'invisible' string
  3832. */
  3833. public static function getDocumentDefaultVisibility($courseInfo)
  3834. {
  3835. $settings = api_get_setting('tool_visible_by_default_at_creation');
  3836. $defaultVisibility = 'visible';
  3837. if (isset($settings['documents'])) {
  3838. $portalDefaultVisibility = 'invisible';
  3839. if ($settings['documents'] == 'true') {
  3840. $portalDefaultVisibility = 'visible';
  3841. }
  3842. $defaultVisibility = $portalDefaultVisibility;
  3843. }
  3844. if (api_get_setting('documents_default_visibility_defined_in_course') == 'true') {
  3845. $courseVisibility = api_get_course_setting('documents_default_visibility', $courseInfo);
  3846. if (!empty($courseVisibility) && in_array($courseVisibility, ['visible', 'invisible'])) {
  3847. $defaultVisibility = $courseVisibility;
  3848. }
  3849. }
  3850. return $defaultVisibility;
  3851. }
  3852. /**
  3853. * @param array $courseInfo
  3854. * @param int $id doc id
  3855. * @param string $visibility visible/invisible
  3856. * @param int $userId
  3857. */
  3858. public static function updateVisibilityFromAllSessions($courseInfo, $id, $visibility, $userId)
  3859. {
  3860. $sessionList = SessionManager::get_session_by_course($courseInfo['real_id']);
  3861. if (!empty($sessionList)) {
  3862. foreach ($sessionList as $session) {
  3863. $sessionId = $session['id'];
  3864. api_item_property_update(
  3865. $courseInfo,
  3866. TOOL_DOCUMENT,
  3867. $id,
  3868. $visibility,
  3869. $userId,
  3870. null,
  3871. null,
  3872. null,
  3873. null,
  3874. $sessionId
  3875. );
  3876. }
  3877. }
  3878. }
  3879. /**
  3880. * @param string $filePath
  3881. * @param string $path
  3882. * @param array $courseInfo
  3883. * @param int $sessionId
  3884. * @param string $whatIfFileExists overwrite|rename
  3885. * @param int $userId
  3886. * @param int $groupId
  3887. * @param int $toUserId
  3888. * @param string $comment
  3889. *
  3890. * @return bool|path
  3891. */
  3892. public static function addFileToDocumentTool(
  3893. $filePath,
  3894. $path,
  3895. $courseInfo,
  3896. $sessionId,
  3897. $userId,
  3898. $whatIfFileExists = 'overwrite',
  3899. $groupId = null,
  3900. $toUserId = null,
  3901. $comment = null
  3902. ) {
  3903. if (!file_exists($filePath)) {
  3904. return false;
  3905. }
  3906. $fileInfo = pathinfo($filePath);
  3907. $file = [
  3908. 'name' => $fileInfo['basename'],
  3909. 'tmp_name' => $filePath,
  3910. 'size' => filesize($filePath),
  3911. 'from_file' => true,
  3912. ];
  3913. $course_dir = $courseInfo['path'].'/document';
  3914. $baseWorkDir = api_get_path(SYS_COURSE_PATH).$course_dir;
  3915. $filePath = handle_uploaded_document(
  3916. $courseInfo,
  3917. $file,
  3918. $baseWorkDir,
  3919. $path,
  3920. $userId,
  3921. $groupId,
  3922. $toUserId,
  3923. false,
  3924. $whatIfFileExists,
  3925. false,
  3926. false,
  3927. $comment,
  3928. $sessionId
  3929. );
  3930. if ($filePath) {
  3931. return self::get_document_id(
  3932. $courseInfo,
  3933. $filePath,
  3934. $sessionId
  3935. );
  3936. }
  3937. return false;
  3938. }
  3939. /**
  3940. * Converts wav to mp3 file.
  3941. * Requires the ffmpeg lib. In ubuntu: sudo apt-get install ffmpeg.
  3942. *
  3943. * @param string $wavFile
  3944. * @param bool $removeWavFileIfSuccess
  3945. *
  3946. * @return bool
  3947. */
  3948. public static function convertWavToMp3($wavFile, $removeWavFileIfSuccess = false)
  3949. {
  3950. if (file_exists($wavFile)) {
  3951. try {
  3952. $ffmpeg = \FFMpeg\FFMpeg::create();
  3953. $video = $ffmpeg->open($wavFile);
  3954. $mp3File = str_replace('wav', 'mp3', $wavFile);
  3955. $result = $video->save(new FFMpeg\Format\Audio\Mp3(), $mp3File);
  3956. if ($result && $removeWavFileIfSuccess) {
  3957. unlink($wavFile);
  3958. }
  3959. if (file_exists($mp3File)) {
  3960. return $mp3File;
  3961. }
  3962. } catch (Exception $e) {
  3963. error_log($e->getMessage());
  3964. error_log($e->getPrevious()->getMessage());
  3965. }
  3966. }
  3967. return false;
  3968. }
  3969. /**
  3970. * @param string $documentData wav document information
  3971. * @param array $courseInfo
  3972. * @param int $sessionId
  3973. * @param int $userId user that adds the document
  3974. * @param string $whatIfFileExists
  3975. * @param bool $deleteWavFile
  3976. *
  3977. * @return bool
  3978. */
  3979. public static function addAndConvertWavToMp3(
  3980. $documentData,
  3981. $courseInfo,
  3982. $sessionId,
  3983. $userId,
  3984. $whatIfFileExists = 'overwrite',
  3985. $deleteWavFile = false
  3986. ) {
  3987. if (empty($documentData)) {
  3988. return false;
  3989. }
  3990. if (isset($documentData['absolute_path']) &&
  3991. file_exists($documentData['absolute_path'])
  3992. ) {
  3993. $mp3FilePath = self::convertWavToMp3($documentData['absolute_path']);
  3994. if (!empty($mp3FilePath) && file_exists($mp3FilePath)) {
  3995. $documentId = self::addFileToDocumentTool(
  3996. $mp3FilePath,
  3997. dirname($documentData['path']),
  3998. $courseInfo,
  3999. $sessionId,
  4000. $userId,
  4001. $whatIfFileExists,
  4002. null,
  4003. null,
  4004. $documentData['comment']
  4005. );
  4006. if (!empty($documentId)) {
  4007. if ($deleteWavFile) {
  4008. $coursePath = $courseInfo['directory'].'/document';
  4009. $documentPath = api_get_path(SYS_COURSE_PATH).$coursePath;
  4010. self::delete_document(
  4011. $courseInfo,
  4012. null,
  4013. $documentPath,
  4014. $sessionId,
  4015. $documentData['id']
  4016. );
  4017. }
  4018. return $documentId;
  4019. }
  4020. }
  4021. }
  4022. return false;
  4023. }
  4024. /**
  4025. * Sets.
  4026. *
  4027. * @param string $file ($document_data['path'])
  4028. * @param string $file_url_sys
  4029. *
  4030. * @return string
  4031. */
  4032. public static function generateAudioTempFile($file, $file_url_sys)
  4033. {
  4034. //make temp audio
  4035. $temp_folder = api_get_path(SYS_ARCHIVE_PATH).'temp/audio';
  4036. if (!file_exists($temp_folder)) {
  4037. @mkdir($temp_folder, api_get_permissions_for_new_directories(), true);
  4038. }
  4039. //make htaccess with allow from all, and file index.html into temp/audio
  4040. $htaccess = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess';
  4041. if (!file_exists($htaccess)) {
  4042. $htaccess_content = "order deny,allow\r\nallow from all\r\nOptions -Indexes";
  4043. $fp = @fopen(api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess', 'w');
  4044. if ($fp) {
  4045. fwrite($fp, $htaccess_content);
  4046. fclose($fp);
  4047. }
  4048. }
  4049. //encript temp name file
  4050. $name_crip = sha1(uniqid()); //encript
  4051. $findext = explode(".", $file);
  4052. $extension = $findext[count($findext) - 1];
  4053. $file_crip = $name_crip.'.'.$extension;
  4054. //copy file to temp/audio directory
  4055. $from_sys = $file_url_sys;
  4056. $to_sys = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/'.$file_crip;
  4057. if (file_exists($from_sys)) {
  4058. copy($from_sys, $to_sys);
  4059. }
  4060. // get file from tmp directory
  4061. Session::write('temp_audio_nanogong', $to_sys);
  4062. return api_get_path(WEB_ARCHIVE_PATH).'temp/audio/'.$file_crip;
  4063. }
  4064. /**
  4065. * Erase temp nanogong audio.
  4066. */
  4067. public static function removeGeneratedAudioTempFile()
  4068. {
  4069. $tempAudio = Session::read('temp_audio_nanogong');
  4070. if (!empty(isset($tempAudio)) && is_file($tempAudio)) {
  4071. unlink($tempAudio);
  4072. Session::erase('temp_audio_nanogong');
  4073. }
  4074. }
  4075. /**
  4076. * Check if the path is used in this course.
  4077. *
  4078. * @param array $courseInfo
  4079. * @param string $path
  4080. *
  4081. * @return array
  4082. */
  4083. public static function getDocumentByPathInCourse($courseInfo, $path)
  4084. {
  4085. $table = Database::get_course_table(TABLE_DOCUMENT);
  4086. $path = Database::escape_string($path);
  4087. $courseId = $courseInfo['real_id'];
  4088. if (empty($courseId)) {
  4089. return false;
  4090. }
  4091. $sql = "SELECT * FROM $table WHERE c_id = $courseId AND path = '$path'";
  4092. $result = Database::query($sql);
  4093. return Database::store_result($result, 'ASSOC');
  4094. }
  4095. /**
  4096. * @param array $_course
  4097. *
  4098. * @return int
  4099. */
  4100. public static function createDefaultAudioFolder($_course)
  4101. {
  4102. if (!isset($_course['path'])) {
  4103. return false;
  4104. }
  4105. $audioId = null;
  4106. $path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document/';
  4107. if (!is_dir($path.'audio')) {
  4108. mkdir($path.'audio', api_get_permissions_for_new_directories());
  4109. $audioId = add_document($_course, '/audio', 'folder', 0, get_lang('Audio'));
  4110. api_item_property_update(
  4111. $_course,
  4112. TOOL_DOCUMENT,
  4113. $audioId,
  4114. 'FolderCreated',
  4115. api_get_user_id(),
  4116. null,
  4117. null,
  4118. null,
  4119. null,
  4120. api_get_session_id()
  4121. );
  4122. }
  4123. return $audioId;
  4124. }
  4125. /**
  4126. * Generate a default certificate for a courses.
  4127. *
  4128. * @todo move to certificate lib
  4129. *
  4130. * @global string $css CSS directory
  4131. * @global string $img_dir image directory
  4132. * @global string $default_course_dir Course directory
  4133. * @global string $js JS directory
  4134. *
  4135. * @param array $courseData The course info
  4136. * @param bool $fromBaseCourse
  4137. * @param int $sessionId
  4138. */
  4139. public static function generateDefaultCertificate(
  4140. $courseData,
  4141. $fromBaseCourse = false,
  4142. $sessionId = 0
  4143. ) {
  4144. if (empty($courseData)) {
  4145. return false;
  4146. }
  4147. global $css, $img_dir, $default_course_dir, $js;
  4148. $codePath = api_get_path(REL_CODE_PATH);
  4149. $dir = '/certificates';
  4150. $comment = null;
  4151. $title = get_lang('DefaultCertificate');
  4152. $fileName = api_replace_dangerous_char($title);
  4153. $filePath = api_get_path(SYS_COURSE_PATH)."{$courseData['directory']}/document$dir";
  4154. if (!is_dir($filePath)) {
  4155. mkdir($filePath, api_get_permissions_for_new_directories());
  4156. }
  4157. $fileFullPath = "$filePath/$fileName.html";
  4158. $fileType = 'file';
  4159. $templateContent = file_get_contents(api_get_path(SYS_CODE_PATH).'gradebook/certificate_template/template.html');
  4160. $search = ['{CSS}', '{IMG_DIR}', '{REL_CODE_PATH}', '{COURSE_DIR}'];
  4161. $replace = [$css.$js, $img_dir, $codePath, $default_course_dir];
  4162. $fileContent = str_replace($search, $replace, $templateContent);
  4163. $saveFilePath = "$dir/$fileName.html";
  4164. if ($fromBaseCourse) {
  4165. $defaultCertificateId = self::get_default_certificate_id(
  4166. $courseData['code'],
  4167. 0
  4168. );
  4169. if (!empty($defaultCertificateId)) {
  4170. // We have a certificate from the course base
  4171. $documentData = self::get_document_data_by_id(
  4172. $defaultCertificateId,
  4173. $courseData['code'],
  4174. false,
  4175. 0
  4176. );
  4177. if ($documentData) {
  4178. $fileContent = file_get_contents($documentData['absolute_path']);
  4179. }
  4180. }
  4181. }
  4182. if (file_exists($fileFullPath) === false) {
  4183. $result = file_put_contents($fileFullPath, $fileContent);
  4184. if ($result) {
  4185. $fileSize = filesize($fileFullPath);
  4186. $documentId = add_document(
  4187. $courseData,
  4188. $saveFilePath,
  4189. $fileType,
  4190. $fileSize,
  4191. $title,
  4192. $comment,
  4193. 0, //$readonly = 0,
  4194. true, //$save_visibility = true,
  4195. null, //$group_id = null,
  4196. $sessionId
  4197. );
  4198. api_item_property_update(
  4199. $courseData,
  4200. TOOL_DOCUMENT,
  4201. $documentId,
  4202. 'DocumentAdded',
  4203. api_get_user_id(),
  4204. null,
  4205. null,
  4206. null,
  4207. null,
  4208. $sessionId
  4209. );
  4210. $defaultCertificateId = self::get_default_certificate_id(
  4211. $courseData['code'],
  4212. $sessionId
  4213. );
  4214. if (!isset($defaultCertificateId)) {
  4215. self::attach_gradebook_certificate(
  4216. $courseData['code'],
  4217. $documentId,
  4218. $sessionId
  4219. );
  4220. }
  4221. }
  4222. }
  4223. }
  4224. /**
  4225. * Update the document name.
  4226. *
  4227. * @param int $documentId The document id
  4228. * @param string $newName The new name
  4229. */
  4230. public static function renameDocument($documentId, $newName)
  4231. {
  4232. $documentId = intval($documentId);
  4233. $newName = Database::escape_string($newName);
  4234. $docuentTable = Database::get_course_table(TABLE_DOCUMENT);
  4235. $values = [
  4236. 'title' => $newName,
  4237. ];
  4238. $whereConditions = [
  4239. 'id = ?' => $documentId,
  4240. ];
  4241. Database::update($docuentTable, $values, $whereConditions);
  4242. }
  4243. /**
  4244. * Get folder/file suffix.
  4245. *
  4246. * @param array $courseInfo
  4247. * @param int $sessionId
  4248. * @param int $groupId
  4249. *
  4250. * @return string
  4251. */
  4252. public static function getDocumentSuffix($courseInfo, $sessionId, $groupId)
  4253. {
  4254. // If no session or group, then no suffix.
  4255. if (empty($sessionId) && empty($groupId)) {
  4256. return '';
  4257. }
  4258. return '__'.intval($sessionId).'__'.intval($groupId);
  4259. }
  4260. /**
  4261. * Fix a document name adding session id and group id
  4262. * Turns picture.jpg -> picture__1__2.jpg
  4263. * Where 1 = session id and 2 group id
  4264. * Of session id and group id are empty then the function returns:
  4265. * picture.jpg -> picture.jpg.
  4266. *
  4267. * @param string $name folder or file name
  4268. * @param string $type 'folder' or 'file'
  4269. * @param array $courseInfo
  4270. * @param int $sessionId
  4271. * @param int $groupId
  4272. *
  4273. * @return string
  4274. */
  4275. public static function fixDocumentName($name, $type, $courseInfo, $sessionId, $groupId)
  4276. {
  4277. $suffix = self::getDocumentSuffix($courseInfo, $sessionId, $groupId);
  4278. switch ($type) {
  4279. case 'folder':
  4280. $name = $name.$suffix;
  4281. break;
  4282. case 'file':
  4283. $name = self::addSuffixToFileName($name, $suffix);
  4284. break;
  4285. }
  4286. return $name;
  4287. }
  4288. /**
  4289. * Add a suffix to a file Example:
  4290. * /folder/picture.jpg => to /folder/picture_this.jpg
  4291. * where "_this" is the suffix.
  4292. *
  4293. * @param string $name
  4294. * @param string $suffix
  4295. *
  4296. * @return string
  4297. */
  4298. public static function addSuffixToFileName($name, $suffix)
  4299. {
  4300. $extension = pathinfo($name, PATHINFO_EXTENSION);
  4301. $fileName = pathinfo($name, PATHINFO_FILENAME);
  4302. $dir = pathinfo($name, PATHINFO_DIRNAME);
  4303. if ($dir == '.') {
  4304. $dir = null;
  4305. }
  4306. if (!empty($dir) && $dir != '/') {
  4307. $dir = $dir.'/';
  4308. }
  4309. $name = $dir.$fileName.$suffix.'.'.$extension;
  4310. return $name;
  4311. }
  4312. /**
  4313. * Check if folder exist in the course base or in the session course.
  4314. *
  4315. * @param string $folder Example: /folder/folder2
  4316. * @param array $courseInfo
  4317. * @param int $sessionId
  4318. * @param int $groupId group.id
  4319. *
  4320. * @return bool
  4321. */
  4322. public static function folderExists(
  4323. $folder,
  4324. $courseInfo,
  4325. $sessionId,
  4326. $groupId
  4327. ) {
  4328. $courseId = $courseInfo['real_id'];
  4329. if (empty($courseId)) {
  4330. return false;
  4331. }
  4332. $sessionId = (int) $sessionId;
  4333. $folderWithSuffix = self::fixDocumentName(
  4334. $folder,
  4335. 'folder',
  4336. $courseInfo,
  4337. $sessionId,
  4338. $groupId
  4339. );
  4340. $folder = Database::escape_string($folder);
  4341. $folderWithSuffix = Database::escape_string($folderWithSuffix);
  4342. // Check if pathname already exists inside document table
  4343. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  4344. $sql = "SELECT id, path FROM $tbl_document
  4345. WHERE
  4346. filetype = 'folder' AND
  4347. c_id = $courseId AND
  4348. (path = '$folder' OR path = '$folderWithSuffix') AND
  4349. (session_id = 0 OR session_id = $sessionId)
  4350. ";
  4351. $rs = Database::query($sql);
  4352. if (Database::num_rows($rs)) {
  4353. return true;
  4354. }
  4355. return false;
  4356. }
  4357. /**
  4358. * Check if file exist in the course base or in the session course.
  4359. *
  4360. * @param string $fileName Example: /folder/picture.jpg
  4361. * @param array $courseInfo
  4362. * @param int $sessionId
  4363. * @param int $groupId
  4364. *
  4365. * @return bool
  4366. */
  4367. public static function documentExists(
  4368. $fileName,
  4369. $courseInfo,
  4370. $sessionId,
  4371. $groupId
  4372. ) {
  4373. $courseId = $courseInfo['real_id'];
  4374. if (empty($courseId)) {
  4375. return false;
  4376. }
  4377. $sessionId = (int) $sessionId;
  4378. $fileNameEscape = Database::escape_string($fileName);
  4379. $fileNameWithSuffix = self::fixDocumentName(
  4380. $fileName,
  4381. 'file',
  4382. $courseInfo,
  4383. $sessionId,
  4384. $groupId
  4385. );
  4386. $fileNameWithSuffix = Database::escape_string($fileNameWithSuffix);
  4387. // Check if pathname already exists inside document table
  4388. $table = Database::get_course_table(TABLE_DOCUMENT);
  4389. $sql = "SELECT id, path FROM $table
  4390. WHERE
  4391. filetype = 'file' AND
  4392. c_id = $courseId AND
  4393. (
  4394. path = '".$fileNameEscape."' OR
  4395. path = '$fileNameWithSuffix'
  4396. ) AND
  4397. (session_id = 0 OR session_id = $sessionId)
  4398. ";
  4399. $rs = Database::query($sql);
  4400. if (Database::num_rows($rs)) {
  4401. return true;
  4402. }
  4403. return false;
  4404. }
  4405. /**
  4406. * Undo the suffix applied to a file example:
  4407. * turns picture__1__1.jpg to picture.jpg.
  4408. *
  4409. * @param string $name
  4410. * @param int $courseId
  4411. * @param int $sessionId
  4412. * @param int $groupId
  4413. *
  4414. * @return string
  4415. */
  4416. public static function undoFixDocumentName(
  4417. $name,
  4418. $courseId,
  4419. $sessionId,
  4420. $groupId
  4421. ) {
  4422. if (empty($sessionId) && empty($groupId)) {
  4423. return $name;
  4424. }
  4425. $suffix = self::getDocumentSuffix(
  4426. ['real_id' => $courseId],
  4427. $sessionId,
  4428. $groupId
  4429. );
  4430. $name = str_replace($suffix, '', $name);
  4431. return $name;
  4432. }
  4433. /**
  4434. * @param string $path
  4435. * @param string $name
  4436. * @param array $courseInfo
  4437. * @param int $sessionId
  4438. * @param int $groupId
  4439. *
  4440. * @return string
  4441. */
  4442. public static function getUniqueFileName($path, $name, $courseInfo, $sessionId, $groupId)
  4443. {
  4444. $counter = 1;
  4445. $filePath = $path.$name;
  4446. $uniqueName = $name;
  4447. while ($documentExists = self::documentExists(
  4448. $filePath,
  4449. $courseInfo,
  4450. $sessionId,
  4451. $groupId
  4452. )) {
  4453. $uniqueName = self::addSuffixToFileName($name, '_'.$counter);
  4454. $filePath = $path.$uniqueName;
  4455. $counter++;
  4456. }
  4457. return $uniqueName;
  4458. }
  4459. /**
  4460. * Builds the form that enables the user to
  4461. * select a directory to browse/upload in.
  4462. *
  4463. * @param array An array containing the folders we want to be able to select
  4464. * @param string The current folder (path inside of the "document" directory, including the prefix "/")
  4465. * @param string Group directory, if empty, prevents documents to be uploaded
  4466. * (because group documents cannot be uploaded in root)
  4467. * @param bool Whether to change the renderer (this will add a template <span>
  4468. * to the QuickForm object displaying the form)
  4469. *
  4470. * @return string html form
  4471. */
  4472. public static function build_directory_selector(
  4473. $folders,
  4474. $document_id,
  4475. $group_dir = '',
  4476. $change_renderer = false,
  4477. &$form = null,
  4478. $selectName = 'id'
  4479. ) {
  4480. $doc_table = Database::get_course_table(TABLE_DOCUMENT);
  4481. $course_id = api_get_course_int_id();
  4482. $folder_titles = [];
  4483. if (is_array($folders)) {
  4484. $escaped_folders = [];
  4485. foreach ($folders as $key => &$val) {
  4486. $escaped_folders[$key] = Database::escape_string($val);
  4487. }
  4488. $folder_sql = implode("','", $escaped_folders);
  4489. $sql = "SELECT path, title
  4490. FROM $doc_table
  4491. WHERE
  4492. filetype = 'folder' AND
  4493. c_id = $course_id AND
  4494. path IN ('".$folder_sql."')";
  4495. $res = Database::query($sql);
  4496. $folder_titles = [];
  4497. while ($obj = Database::fetch_object($res)) {
  4498. $folder_titles[$obj->path] = $obj->title;
  4499. }
  4500. }
  4501. $attributes = [];
  4502. if (empty($form)) {
  4503. $form = new FormValidator('selector', 'GET', api_get_self().'?'.api_get_cidreq());
  4504. $attributes = ['onchange' => 'javascript: document.selector.submit();'];
  4505. }
  4506. $form->addElement('hidden', 'cidReq', api_get_course_id());
  4507. $form->addElement('hidden', 'id_session', api_get_session_id());
  4508. $form->addElement('hidden', 'gidReq', api_get_group_id());
  4509. $parent_select = $form->addSelect(
  4510. $selectName,
  4511. get_lang('CurrentDirectory'),
  4512. '',
  4513. $attributes
  4514. );
  4515. // Group documents cannot be uploaded in the root
  4516. if (empty($group_dir)) {
  4517. $parent_select->addOption(get_lang('Documents'), '/');
  4518. if (is_array($folders)) {
  4519. foreach ($folders as $folder_id => &$folder) {
  4520. $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
  4521. $path_parts = explode('/', $folder);
  4522. $folder_titles[$folder] = cut($folder_titles[$folder], 80);
  4523. $counter = count($path_parts) - 2;
  4524. if ($counter > 0) {
  4525. $label = str_repeat('&nbsp;&nbsp;&nbsp;', $counter).' &mdash; '.$folder_titles[$folder];
  4526. } else {
  4527. $label = ' &mdash; '.$folder_titles[$folder];
  4528. }
  4529. $parent_select->addOption($label, $folder_id);
  4530. if ($selected != '') {
  4531. $parent_select->setSelected($folder_id);
  4532. }
  4533. }
  4534. }
  4535. } else {
  4536. if (!empty($folders)) {
  4537. foreach ($folders as $folder_id => &$folder) {
  4538. $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
  4539. $label = $folder_titles[$folder];
  4540. if ($folder == $group_dir) {
  4541. $label = get_lang('Documents');
  4542. } else {
  4543. $path_parts = explode('/', str_replace($group_dir, '', $folder));
  4544. $label = cut($label, 80);
  4545. $label = str_repeat('&nbsp;&nbsp;&nbsp;', count($path_parts) - 2).' &mdash; '.$label;
  4546. }
  4547. $parent_select->addOption($label, $folder_id);
  4548. if ($selected != '') {
  4549. $parent_select->setSelected($folder_id);
  4550. }
  4551. }
  4552. }
  4553. }
  4554. $html = $form->toHtml();
  4555. return $html;
  4556. }
  4557. /**
  4558. * Create a html hyperlink depending on if it's a folder or a file.
  4559. *
  4560. * @param string $documentWebPath
  4561. * @param array $document_data
  4562. * @param bool $show_as_icon - if it is true, only a clickable icon will be shown
  4563. * @param int $visibility (1/0)
  4564. * @param int $counter
  4565. * @param int $size
  4566. * @param bool $isAllowedToEdit
  4567. * @param bool $isCertificateMode
  4568. *
  4569. * @return string url
  4570. */
  4571. public static function create_document_link(
  4572. $documentWebPath,
  4573. $document_data,
  4574. $show_as_icon = false,
  4575. $counter = null,
  4576. $visibility,
  4577. $size = 0,
  4578. $isAllowedToEdit = false,
  4579. $isCertificateMode = false
  4580. ) {
  4581. global $dbl_click_id;
  4582. $www = $documentWebPath;
  4583. $sessionId = api_get_session_id();
  4584. $courseParams = api_get_cidreq();
  4585. $webODFList = self::get_web_odf_extension_list();
  4586. // Get the title or the basename depending on what we're using
  4587. if ($document_data['title'] != '') {
  4588. $title = $document_data['title'];
  4589. } else {
  4590. $title = basename($document_data['path']);
  4591. }
  4592. $filetype = $document_data['filetype'];
  4593. $path = $document_data['path'];
  4594. $url_path = urlencode($document_data['path']);
  4595. $basePageUrl = api_get_path(WEB_CODE_PATH).'document/';
  4596. $pageUrl = $basePageUrl.'document.php';
  4597. // Add class="invisible" on invisible files
  4598. $visibility_class = $visibility == false ? ' class="muted"' : '';
  4599. $forcedownload_link = '';
  4600. $forcedownload_icon = '';
  4601. $prevent_multiple_click = '';
  4602. $force_download_html = '';
  4603. if (!$show_as_icon) {
  4604. // Build download link (icon)
  4605. $forcedownload_link = $filetype == 'folder'
  4606. ? $pageUrl.'?'.$courseParams.'&action=downloadfolder&id='.$document_data['id']
  4607. : $pageUrl.'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
  4608. // Folder download or file download?
  4609. $forcedownload_icon = $filetype == 'folder' ? 'save_pack.png' : 'save.png';
  4610. // Prevent multiple clicks on zipped folder download
  4611. $prevent_multiple_click = $filetype == 'folder' ? " onclick=\"javascript: if(typeof clic_$dbl_click_id == 'undefined' || !clic_$dbl_click_id) { clic_$dbl_click_id=true; window.setTimeout('clic_".($dbl_click_id++)."=false;',10000); } else { return false; }\"" : '';
  4612. }
  4613. $target = '_self';
  4614. $is_browser_viewable_file = false;
  4615. if ($filetype == 'file') {
  4616. // Check the extension
  4617. $ext = explode('.', $path);
  4618. $ext = strtolower($ext[count($ext) - 1]);
  4619. // HTML-files an some other types are shown in a frameset by default.
  4620. $is_browser_viewable_file = self::isBrowserViewable($ext);
  4621. if ($is_browser_viewable_file) {
  4622. if ($ext == 'pdf' || in_array($ext, $webODFList)) {
  4623. $url = $pageUrl.'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
  4624. } else {
  4625. $url = $basePageUrl.'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
  4626. }
  4627. } else {
  4628. // url-encode for problematic characters (we may not call them dangerous characters...)
  4629. //$path = str_replace('%2F', '/', $url_path).'?'.$courseParams;
  4630. $url = $www.str_replace('%2F', '/', $url_path).'?'.$courseParams;
  4631. }
  4632. } else {
  4633. $url = $pageUrl.'?'.$courseParams.'&id='.$document_data['id'];
  4634. }
  4635. if ($isCertificateMode) {
  4636. $url .= '&certificate=true&selectcat='.(isset($_GET['selectcat']) ? $_GET['selectcat'] : '');
  4637. }
  4638. // The little download icon
  4639. $tooltip_title = $title;
  4640. $tooltip_title_alt = $tooltip_title;
  4641. if ($filetype == 'link') {
  4642. $tooltip_title_alt = $title;
  4643. $url = $document_data['comment'].'" target="_blank';
  4644. }
  4645. if ($path == '/shared_folder') {
  4646. $tooltip_title_alt = get_lang('UserFolders');
  4647. } elseif (strstr($path, 'shared_folder_session_')) {
  4648. $tooltip_title_alt = get_lang('UserFolders').' ('.api_get_session_name(api_get_session_id()).')';
  4649. } elseif (strstr($tooltip_title, 'sf_user_')) {
  4650. $userinfo = api_get_user_info(substr($tooltip_title, 8));
  4651. $tooltip_title_alt = get_lang('UserFolder').' '.$userinfo['complete_name'];
  4652. } elseif ($path == '/chat_files') {
  4653. $tooltip_title_alt = get_lang('ChatFiles');
  4654. } elseif ($path == '/learning_path') {
  4655. $tooltip_title_alt = get_lang('LearningPaths');
  4656. } elseif ($path == '/video') {
  4657. $tooltip_title_alt = get_lang('Video');
  4658. } elseif ($path == '/audio') {
  4659. $tooltip_title_alt = get_lang('Audio');
  4660. } elseif ($path == '/flash') {
  4661. $tooltip_title_alt = get_lang('Flash');
  4662. } elseif ($path == '/images') {
  4663. $tooltip_title_alt = get_lang('Images');
  4664. } elseif ($path == '/images/gallery') {
  4665. $tooltip_title_alt = get_lang('DefaultCourseImages');
  4666. }
  4667. $copyToMyFiles = $open_in_new_window_link = '';
  4668. $curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
  4669. $send_to = null;
  4670. $checkExtension = $path;
  4671. $extension = pathinfo($path, PATHINFO_EXTENSION);
  4672. $document_data['file_extension'] = $extension;
  4673. if (!$show_as_icon) {
  4674. if ($filetype == 'folder') {
  4675. if ($isAllowedToEdit ||
  4676. api_is_platform_admin() ||
  4677. api_get_setting('students_download_folders') == 'true'
  4678. ) {
  4679. // filter: when I am into a shared folder, I can only show "my shared folder" for donwload
  4680. if (self::is_shared_folder($curdirpath, $sessionId)) {
  4681. if (preg_match('/shared_folder\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
  4682. preg_match('/shared_folder_session_'.$sessionId.'\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
  4683. $isAllowedToEdit || api_is_platform_admin()
  4684. ) {
  4685. $force_download_html = $size == 0 ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
  4686. Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
  4687. }
  4688. } elseif (!preg_match('/shared_folder/', urldecode($forcedownload_link)) ||
  4689. $isAllowedToEdit ||
  4690. api_is_platform_admin()
  4691. ) {
  4692. $force_download_html = $size == 0 ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
  4693. Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
  4694. }
  4695. }
  4696. } else {
  4697. $force_download_html = $size == 0 ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.' download="'.$document_data['basename'].'">'.
  4698. Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
  4699. }
  4700. // Copy files to user's myfiles
  4701. if (api_get_setting('allow_my_files') === 'true' &&
  4702. api_get_setting('users_copy_files') === 'true' && api_is_anonymous() === false
  4703. ) {
  4704. $copy_myfiles_link = $filetype === 'file' ? $pageUrl.'?'.$courseParams.'&action=copytomyfiles&id='.$document_data['id'] : api_get_self().'?'.$courseParams;
  4705. if ($filetype === 'file') {
  4706. $copyToMyFiles = '<a href="'.$copy_myfiles_link.'" style="float:right"'.$prevent_multiple_click.'>'.
  4707. Display::return_icon('briefcase.png', get_lang('CopyToMyFiles'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
  4708. if (api_get_setting('allow_my_files') === 'false') {
  4709. $copyToMyFiles = '';
  4710. }
  4711. }
  4712. }
  4713. $pdf_icon = '';
  4714. if (!$isAllowedToEdit &&
  4715. $filetype === 'file' &&
  4716. api_get_setting('students_export2pdf') == 'true' &&
  4717. in_array($extension, ['html', 'htm'])
  4718. ) {
  4719. $pdf_icon = ' <a style="float:right".'.$prevent_multiple_click.' href="'.$pageUrl.'?'.$courseParams.'&action=export_to_pdf&id='.$document_data['id'].'&curdirpath='.$curdirpath.'">'.
  4720. Display::return_icon('pdf.png', get_lang('Export2PDF'), [], ICON_SIZE_SMALL).'</a> ';
  4721. }
  4722. if ($is_browser_viewable_file) {
  4723. $open_in_new_window_link = '<a href="'.$www.str_replace('%2F', '/', $url_path).'?'.$courseParams.'" style="float:right"'.$prevent_multiple_click.' target="_blank">'.
  4724. Display::return_icon('open_in_new_window.png', get_lang('OpenInANewWindow'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
  4725. }
  4726. if ($filetype === 'file') {
  4727. // Sound preview
  4728. if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
  4729. (preg_match('/wav$/i', urldecode($checkExtension))) ||
  4730. preg_match('/ogg$/i', urldecode($checkExtension))
  4731. ) {
  4732. return '<span style="float:left" '.$visibility_class.'>'.
  4733. $title.
  4734. '</span>'.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
  4735. } elseif (
  4736. // Show preview
  4737. preg_match('/swf$/i', urldecode($checkExtension)) ||
  4738. preg_match('/png$/i', urldecode($checkExtension)) ||
  4739. preg_match('/gif$/i', urldecode($checkExtension)) ||
  4740. preg_match('/jpg$/i', urldecode($checkExtension)) ||
  4741. preg_match('/jpeg$/i', urldecode($checkExtension)) ||
  4742. preg_match('/bmp$/i', urldecode($checkExtension)) ||
  4743. preg_match('/svg$/i', urldecode($checkExtension))
  4744. ) {
  4745. // Simpler version of showinframesmin.php with no headers
  4746. $url = 'show_content.php?'.$courseParams.'&id='.$document_data['id'];
  4747. $class = 'ajax';
  4748. if ($visibility == false) {
  4749. $class = 'ajax text-muted';
  4750. }
  4751. return Display::url(
  4752. $title,
  4753. $url,
  4754. [
  4755. 'class' => $class,
  4756. 'title' => $tooltip_title_alt,
  4757. 'data-title' => $title,
  4758. 'style' => 'float:left;',
  4759. ]
  4760. )
  4761. .$force_download_html.$send_to.$copyToMyFiles
  4762. .$open_in_new_window_link.$pdf_icon;
  4763. } else {
  4764. // For a "PDF Download" of the file.
  4765. $pdfPreview = null;
  4766. if ($ext != 'pdf' && !in_array($ext, $webODFList)) {
  4767. $url = $basePageUrl.'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
  4768. } else {
  4769. $pdfPreview = Display::url(
  4770. Display::return_icon('preview.png', get_lang('Preview'), null, ICON_SIZE_SMALL),
  4771. api_get_path(WEB_CODE_PATH).'document/showinframes.php?'.$courseParams.'&id='.$document_data['id'],
  4772. ['style' => 'float:right']
  4773. );
  4774. }
  4775. // No plugin just the old and good showinframes.php page
  4776. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" style="float:left" '.$visibility_class.' >'.$title.'</a>'.
  4777. $pdfPreview.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
  4778. }
  4779. } else {
  4780. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.$title.'</a>'.
  4781. $force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
  4782. }
  4783. // end copy files to users myfiles
  4784. } else {
  4785. // Icon column
  4786. if (preg_match('/shared_folder/', urldecode($checkExtension)) &&
  4787. preg_match('/shared_folder$/', urldecode($checkExtension)) == false &&
  4788. preg_match('/shared_folder_session_'.$sessionId.'$/', urldecode($url)) == false
  4789. ) {
  4790. if ($filetype == 'file') {
  4791. //Sound preview
  4792. if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
  4793. (preg_match('/wav$/i', urldecode($checkExtension))) ||
  4794. preg_match('/ogg$/i', urldecode($checkExtension))) {
  4795. $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
  4796. return $soundPreview;
  4797. } elseif (
  4798. // Show preview
  4799. preg_match('/swf$/i', urldecode($checkExtension)) ||
  4800. preg_match('/png$/i', urldecode($checkExtension)) ||
  4801. preg_match('/gif$/i', urldecode($checkExtension)) ||
  4802. preg_match('/jpg$/i', urldecode($checkExtension)) ||
  4803. preg_match('/jpeg$/i', urldecode($checkExtension)) ||
  4804. preg_match('/bmp$/i', urldecode($checkExtension)) ||
  4805. preg_match('/svg$/i', urldecode($checkExtension))
  4806. ) {
  4807. $url = $basePageUrl.'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
  4808. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
  4809. self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
  4810. Display::return_icon('shared.png', get_lang('ResourceShared'), []).
  4811. '</a>';
  4812. } else {
  4813. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
  4814. self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
  4815. Display::return_icon('shared.png', get_lang('ResourceShared'), []).
  4816. '</a>';
  4817. }
  4818. } else {
  4819. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
  4820. self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
  4821. Display::return_icon('shared.png', get_lang('ResourceShared'), []).
  4822. '</a>';
  4823. }
  4824. } else {
  4825. if ($filetype === 'file') {
  4826. // Sound preview with jplayer
  4827. if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
  4828. (preg_match('/wav$/i', urldecode($checkExtension))) ||
  4829. preg_match('/ogg$/i', urldecode($checkExtension))) {
  4830. $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
  4831. return $soundPreview;
  4832. } elseif (
  4833. //Show preview
  4834. preg_match('/html$/i', urldecode($checkExtension)) ||
  4835. preg_match('/htm$/i', urldecode($checkExtension)) ||
  4836. preg_match('/swf$/i', urldecode($checkExtension)) ||
  4837. preg_match('/png$/i', urldecode($checkExtension)) ||
  4838. preg_match('/gif$/i', urldecode($checkExtension)) ||
  4839. preg_match('/jpg$/i', urldecode($checkExtension)) ||
  4840. preg_match('/jpeg$/i', urldecode($checkExtension)) ||
  4841. preg_match('/bmp$/i', urldecode($checkExtension)) ||
  4842. preg_match('/svg$/i', urldecode($checkExtension))
  4843. ) {
  4844. $url = $basePageUrl.'showinframes.php?'.$courseParams.'&id='.$document_data['id']; //without preview
  4845. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
  4846. self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
  4847. '</a>';
  4848. } else {
  4849. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
  4850. self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
  4851. '</a>';
  4852. }
  4853. } else {
  4854. return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
  4855. self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
  4856. '</a>';
  4857. }
  4858. }
  4859. }
  4860. }
  4861. /**
  4862. * Builds an img html tag for the file type.
  4863. *
  4864. * @param string $type (file/folder)
  4865. * @param string $path
  4866. * @param bool $isAllowedToEdit
  4867. *
  4868. * @return string img html tag
  4869. */
  4870. public static function build_document_icon_tag($type, $path, $isAllowedToEdit = null)
  4871. {
  4872. $basename = basename($path);
  4873. $sessionId = api_get_session_id();
  4874. if (is_null($isAllowedToEdit)) {
  4875. $isAllowedToEdit = api_is_allowed_to_edit(null, true);
  4876. }
  4877. $user_image = false;
  4878. if ($type == 'file') {
  4879. $icon = choose_image($basename);
  4880. $basename = substr(strrchr($basename, '.'), 1);
  4881. } elseif ($type == 'link') {
  4882. $icon = 'clouddoc.png';
  4883. $basename = get_lang('CloudFileLink');
  4884. } else {
  4885. if ($path == '/shared_folder') {
  4886. $icon = 'folder_users.png';
  4887. if ($isAllowedToEdit) {
  4888. $basename = get_lang('HelpUsersFolder');
  4889. } else {
  4890. $basename = get_lang('UserFolders');
  4891. }
  4892. } elseif (strstr($basename, 'sf_user_')) {
  4893. $userInfo = api_get_user_info(substr($basename, 8));
  4894. $icon = $userInfo['avatar_small'];
  4895. $basename = get_lang('UserFolder').' '.$userInfo['complete_name'];
  4896. $user_image = true;
  4897. } elseif (strstr($path, 'shared_folder_session_')) {
  4898. $sessionName = api_get_session_name($sessionId);
  4899. if ($isAllowedToEdit) {
  4900. $basename = '***('.$sessionName.')*** '.get_lang('HelpUsersFolder');
  4901. } else {
  4902. $basename = get_lang('UserFolders').' ('.$sessionName.')';
  4903. }
  4904. $icon = 'folder_users.png';
  4905. } else {
  4906. $icon = 'folder_document.png';
  4907. if ($path == '/audio') {
  4908. $icon = 'folder_audio.png';
  4909. if ($isAllowedToEdit) {
  4910. $basename = get_lang('HelpDefaultDirDocuments');
  4911. } else {
  4912. $basename = get_lang('Audio');
  4913. }
  4914. } elseif ($path == '/flash') {
  4915. $icon = 'folder_flash.png';
  4916. if ($isAllowedToEdit) {
  4917. $basename = get_lang('HelpDefaultDirDocuments');
  4918. } else {
  4919. $basename = get_lang('Flash');
  4920. }
  4921. } elseif ($path == '/images') {
  4922. $icon = 'folder_images.png';
  4923. if ($isAllowedToEdit) {
  4924. $basename = get_lang('HelpDefaultDirDocuments');
  4925. } else {
  4926. $basename = get_lang('Images');
  4927. }
  4928. } elseif ($path == '/video') {
  4929. $icon = 'folder_video.png';
  4930. if ($isAllowedToEdit) {
  4931. $basename = get_lang('HelpDefaultDirDocuments');
  4932. } else {
  4933. $basename = get_lang('Video');
  4934. }
  4935. } elseif ($path == '/images/gallery') {
  4936. $icon = 'folder_gallery.png';
  4937. if ($isAllowedToEdit) {
  4938. $basename = get_lang('HelpDefaultDirDocuments');
  4939. } else {
  4940. $basename = get_lang('Gallery');
  4941. }
  4942. } elseif ($path == '/chat_files') {
  4943. $icon = 'folder_chat.png';
  4944. if ($isAllowedToEdit) {
  4945. $basename = get_lang('HelpFolderChat');
  4946. } else {
  4947. $basename = get_lang('ChatFiles');
  4948. }
  4949. } elseif ($path == '/learning_path') {
  4950. $icon = 'folder_learningpath.png';
  4951. if ($isAllowedToEdit) {
  4952. $basename = get_lang('HelpFolderLearningPaths');
  4953. } else {
  4954. $basename = get_lang('LearningPaths');
  4955. }
  4956. }
  4957. }
  4958. }
  4959. if ($user_image) {
  4960. return Display::img($icon, $basename, [], false);
  4961. }
  4962. return Display::return_icon($icon, $basename, [], ICON_SIZE_SMALL);
  4963. }
  4964. /**
  4965. * Creates the row of edit icons for a file/folder.
  4966. *
  4967. * @param array $document_data
  4968. * @param int $id
  4969. * @param bool $is_template
  4970. * @param int $is_read_only
  4971. * @param int $visibility (1/0)
  4972. *
  4973. * @return string html img tags with hyperlinks
  4974. */
  4975. public static function build_edit_icons($document_data, $id, $is_template, $is_read_only = 0, $visibility)
  4976. {
  4977. $sessionId = api_get_session_id();
  4978. $courseParams = api_get_cidreq();
  4979. $document_id = $document_data['id'];
  4980. $type = $document_data['filetype'];
  4981. $is_read_only = $document_data['readonly'];
  4982. $path = $document_data['path'];
  4983. if ($type == 'link') {
  4984. $parent_id = self::get_document_id(
  4985. api_get_course_info(),
  4986. rtrim($path, '/'),
  4987. 0
  4988. );
  4989. } else {
  4990. $parent_id = self::get_document_id(
  4991. api_get_course_info(),
  4992. dirname($path),
  4993. 0
  4994. );
  4995. }
  4996. if (empty($parent_id) && !empty($sessionId)) {
  4997. $parent_id = self::get_document_id(
  4998. api_get_course_info(),
  4999. dirname($path),
  5000. $sessionId
  5001. );
  5002. }
  5003. $curdirpath = dirname($document_data['path']);
  5004. $is_certificate_mode = self::is_certificate_mode($path);
  5005. $curdirpath = urlencode($curdirpath);
  5006. $extension = pathinfo($path, PATHINFO_EXTENSION);
  5007. //@todo Implement remote support for converter
  5008. $usePpt2lp = api_get_setting('service_ppt2lp', 'active') == 'true' && api_get_setting('service_ppt2lp', 'host') == 'localhost';
  5009. $formatTypeList = self::getFormatTypeListConvertor('from', $extension);
  5010. $formatType = current($formatTypeList);
  5011. // If document is read only *or* we're in a session and the document
  5012. // is from a non-session context, hide the edition capabilities
  5013. $modify_icons = [];
  5014. $modify_icons[] = self::getButtonEdit($is_read_only, $document_data, $extension, $is_certificate_mode);
  5015. $modify_icons[] = self::getButtonMove($is_read_only, $document_data, $is_certificate_mode, $parent_id);
  5016. $modify_icons[] = self::getButtonVisibility(
  5017. $is_read_only,
  5018. $visibility,
  5019. $document_data,
  5020. $is_certificate_mode,
  5021. $parent_id
  5022. );
  5023. $modify_icons[] = self::getButtonDelete(
  5024. $is_read_only,
  5025. $document_data,
  5026. $is_certificate_mode,
  5027. $curdirpath,
  5028. $parent_id
  5029. );
  5030. if (!$is_read_only /* or ($session_id!=api_get_session_id()) */) {
  5031. // Add action to covert to PDF, will create a new document whit same filename but .pdf extension
  5032. // @TODO: add prompt to select a format target
  5033. if (!in_array($path, self::get_system_folders())) {
  5034. if ($usePpt2lp && $formatType) {
  5035. $modify_icons[] = Display::url(
  5036. Display::return_icon('convert.png', get_lang('Convert')),
  5037. '#',
  5038. ['class' => 'convertAction', 'data-documentId' => $document_id, 'data-formatType' => $formatType]
  5039. );
  5040. }
  5041. }
  5042. }
  5043. if ($type == 'file' && ($extension == 'html' || $extension == 'htm')) {
  5044. if ($is_template == 0) {
  5045. if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] != '/certificates') || !isset($_GET['curdirpath'])) {
  5046. $modify_icons[] = Display::url(
  5047. Display::return_icon('wizard.png', get_lang('AddAsTemplate')),
  5048. api_get_self()."?$courseParams&curdirpath=$curdirpath&add_as_template=$id"
  5049. );
  5050. }
  5051. if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] == '/certificates') || $is_certificate_mode) {//allow attach certificate to course
  5052. $visibility_icon_certificate = 'nocertificate';
  5053. if (self::get_default_certificate_id(api_get_course_id()) == $id) {
  5054. $visibility_icon_certificate = 'certificate';
  5055. $certificate = get_lang('DefaultCertificate');
  5056. $preview = get_lang('PreviewCertificate');
  5057. $is_preview = true;
  5058. } else {
  5059. $is_preview = false;
  5060. $certificate = get_lang('NoDefaultCertificate');
  5061. }
  5062. if (isset($_GET['selectcat'])) {
  5063. $modify_icons[] = Display::url(
  5064. Display::return_icon($visibility_icon_certificate.'.png', $certificate),
  5065. api_get_self()."?$courseParams&curdirpath=$curdirpath&selectcat=".intval($_GET['selectcat'])."&set_certificate=$id"
  5066. );
  5067. if ($is_preview) {
  5068. $modify_icons[] = Display::url(
  5069. Display::return_icon('preview_view.png', $preview),
  5070. api_get_self()."?$courseParams&curdirpath=$curdirpath&set_preview=$id"
  5071. );
  5072. }
  5073. }
  5074. }
  5075. } else {
  5076. $modify_icons[] = Display::url(
  5077. Display::return_icon('wizard_na.png', get_lang('RemoveAsTemplate')),
  5078. api_get_self()."?$courseParams&curdirpath=$curdirpath&remove_as_template=$id"
  5079. );
  5080. }
  5081. $modify_icons[] = Display::url(
  5082. Display::return_icon('pdf.png', get_lang('Export2PDF')),
  5083. api_get_self()."?$courseParams&action=export_to_pdf&id=$id&curdirpath=$curdirpath"
  5084. );
  5085. }
  5086. return implode(PHP_EOL, $modify_icons);
  5087. }
  5088. /**
  5089. * @param $folders
  5090. * @param $curdirpath
  5091. * @param $move_file
  5092. * @param string $group_dir
  5093. *
  5094. * @return string
  5095. */
  5096. public static function build_move_to_selector($folders, $curdirpath, $move_file, $group_dir = '')
  5097. {
  5098. $form = new FormValidator('move_to', 'post', api_get_self().'?'.api_get_cidreq());
  5099. // Form title
  5100. $form->addHidden('move_file', $move_file);
  5101. $options = [];
  5102. // Group documents cannot be uploaded in the root
  5103. if ($group_dir == '') {
  5104. if ($curdirpath != '/') {
  5105. $options['/'] = get_lang('Documents');
  5106. }
  5107. if (is_array($folders)) {
  5108. foreach ($folders as &$folder) {
  5109. // Hide some folders
  5110. if ($folder == '/HotPotatoes_files' ||
  5111. $folder == '/certificates' ||
  5112. basename($folder) == 'css'
  5113. ) {
  5114. continue;
  5115. }
  5116. // Admin setting for Hide/Show the folders of all users
  5117. if (api_get_setting('show_users_folders') == 'false' &&
  5118. (strstr($folder, '/shared_folder') || strstr($folder, 'shared_folder_session_'))
  5119. ) {
  5120. continue;
  5121. }
  5122. // Admin setting for Hide/Show Default folders to all users
  5123. if (api_get_setting('show_default_folders') == 'false' &&
  5124. (
  5125. $folder == '/images' ||
  5126. $folder == '/flash' ||
  5127. $folder == '/audio' ||
  5128. $folder == '/video' ||
  5129. strstr($folder, '/images/gallery') ||
  5130. $folder == '/video/flv'
  5131. )
  5132. ) {
  5133. continue;
  5134. }
  5135. // Admin setting for Hide/Show chat history folder
  5136. if (api_get_setting('show_chat_folder') == 'false' &&
  5137. $folder == '/chat_files') {
  5138. continue;
  5139. }
  5140. // You cannot move a file to:
  5141. // 1. current directory
  5142. // 2. inside the folder you want to move
  5143. // 3. inside a subfolder of the folder you want to move
  5144. if (($curdirpath != $folder) &&
  5145. ($folder != $move_file) &&
  5146. (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
  5147. ) {
  5148. // If document title is used, we have to display titles instead of real paths...
  5149. $path_displayed = self::get_titles_of_path($folder);
  5150. if (empty($path_displayed)) {
  5151. $path_displayed = get_lang('Untitled');
  5152. }
  5153. $options[$folder] = $path_displayed;
  5154. }
  5155. }
  5156. }
  5157. } else {
  5158. foreach ($folders as $folder) {
  5159. if (($curdirpath != $folder) &&
  5160. ($folder != $move_file) &&
  5161. (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
  5162. ) {
  5163. // Cannot copy dir into his own subdir
  5164. $path_displayed = self::get_titles_of_path($folder);
  5165. $display_folder = substr($path_displayed, strlen($group_dir));
  5166. $display_folder = $display_folder == '' ? get_lang('Documents') : $display_folder;
  5167. $options[$folder] = $display_folder;
  5168. }
  5169. }
  5170. }
  5171. $form->addElement('select', 'move_to', get_lang('MoveTo'), $options);
  5172. $form->addButtonNext(get_lang('MoveElement'), 'move_file_submit');
  5173. return $form->returnForm();
  5174. }
  5175. /**
  5176. * Gets the path translated with title of docs and folders.
  5177. *
  5178. * @param string $path the real path
  5179. *
  5180. * @return the path which should be displayed
  5181. */
  5182. public static function get_titles_of_path($path)
  5183. {
  5184. global $tmp_folders_titles;
  5185. $course_id = api_get_course_int_id();
  5186. $nb_slashes = substr_count($path, '/');
  5187. $current_slash_pos = 0;
  5188. $path_displayed = '';
  5189. for ($i = 0; $i < $nb_slashes; $i++) {
  5190. // For each folder of the path, retrieve title.
  5191. $current_slash_pos = strpos($path, '/', $current_slash_pos + 1);
  5192. $tmp_path = substr($path, strpos($path, '/', 0), $current_slash_pos);
  5193. if (empty($tmp_path)) {
  5194. // If empty, then we are in the final part of the path
  5195. $tmp_path = $path;
  5196. }
  5197. if (!empty($tmp_folders_titles[$tmp_path])) {
  5198. // If this path has soon been stored here we don't need a new query
  5199. $path_displayed .= $tmp_folders_titles[$tmp_path];
  5200. } else {
  5201. $sql = 'SELECT title FROM '.Database::get_course_table(TABLE_DOCUMENT).'
  5202. WHERE c_id = '.$course_id.' AND path LIKE BINARY "'.$tmp_path.'"';
  5203. $rs = Database::query($sql);
  5204. $tmp_title = '/'.Database::result($rs, 0, 0);
  5205. $path_displayed .= $tmp_title;
  5206. $tmp_folders_titles[$tmp_path] = $tmp_title;
  5207. }
  5208. }
  5209. return $path_displayed;
  5210. }
  5211. /**
  5212. * Creates form that asks for the directory name.
  5213. *
  5214. * @return string html-output text for the form
  5215. */
  5216. public static function create_dir_form($dirId)
  5217. {
  5218. global $document_id;
  5219. $form = new FormValidator('create_dir_form', 'post', api_get_self().'?'.api_get_cidreq());
  5220. $form->addElement('hidden', 'create_dir', 1);
  5221. $form->addElement('hidden', 'dir_id', intval($document_id));
  5222. $form->addElement('hidden', 'id', intval($dirId));
  5223. $form->addElement('header', get_lang('CreateDir'));
  5224. $form->addText('dirname', get_lang('NewDir'), ['autofocus' => 'autofocus']);
  5225. $form->addButtonCreate(get_lang('CreateFolder'));
  5226. return $form->returnForm();
  5227. }
  5228. /**
  5229. * Checks whether the user is in shared folder.
  5230. *
  5231. * @param string $curdirpath
  5232. * @param int $sessionId
  5233. *
  5234. * @return bool Return true when user is into shared folder
  5235. */
  5236. public static function is_shared_folder($curdirpath, $sessionId)
  5237. {
  5238. $clean_curdirpath = Security::remove_XSS($curdirpath);
  5239. if ($clean_curdirpath == '/shared_folder') {
  5240. return true;
  5241. } elseif ($clean_curdirpath == '/shared_folder_session_'.$sessionId) {
  5242. return true;
  5243. }
  5244. return false;
  5245. }
  5246. /**
  5247. * Checks whether the user is into any user shared folder.
  5248. *
  5249. * @param string $path
  5250. * @param int $sessionId
  5251. *
  5252. * @return bool Return true when user is in any user shared folder
  5253. */
  5254. public static function is_any_user_shared_folder($path, $sessionId)
  5255. {
  5256. $clean_path = Security::remove_XSS($path);
  5257. if (strpos($clean_path, 'shared_folder/sf_user_')) {
  5258. return true;
  5259. } elseif (strpos($clean_path, 'shared_folder_session_'.$sessionId.'/sf_user_')) {
  5260. return true;
  5261. }
  5262. return false;
  5263. }
  5264. /**
  5265. * Create users shared folder for course.
  5266. *
  5267. * @param int $userId
  5268. * @param array $courseInfo
  5269. * @param int $sessionId
  5270. */
  5271. public static function createUserSharedFolder($userId, array $courseInfo, $sessionId = 0)
  5272. {
  5273. $documentDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document';
  5274. $userInfo = api_get_user_info($userId);
  5275. if (!$sessionId) {
  5276. //Create shared folder. Necessary for recycled courses.
  5277. if (!file_exists($documentDirectory.'/shared_folder')) {
  5278. create_unexisting_directory(
  5279. $courseInfo,
  5280. $userId,
  5281. 0,
  5282. 0,
  5283. 0,
  5284. $documentDirectory,
  5285. '/shared_folder',
  5286. get_lang('UserFolders'),
  5287. 0,
  5288. false,
  5289. false
  5290. );
  5291. }
  5292. // Create dynamic user shared folder
  5293. if (!file_exists($documentDirectory.'/shared_folder/sf_user_'.$userId)) {
  5294. create_unexisting_directory(
  5295. $courseInfo,
  5296. $userId,
  5297. 0,
  5298. 0,
  5299. 0,
  5300. $documentDirectory,
  5301. '/shared_folder/sf_user_'.$userId,
  5302. $userInfo['complete_name'],
  5303. 1,
  5304. false,
  5305. false
  5306. );
  5307. }
  5308. return;
  5309. }
  5310. // Create shared folder session.
  5311. if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId)) {
  5312. create_unexisting_directory(
  5313. $courseInfo,
  5314. api_get_user_id(),
  5315. $sessionId,
  5316. 0,
  5317. 0,
  5318. $documentDirectory,
  5319. '/shared_folder_session_'.$sessionId,
  5320. get_lang('UserFolders').' ('.api_get_session_name($sessionId).')',
  5321. 0,
  5322. false,
  5323. false
  5324. );
  5325. }
  5326. //Create dynamic user shared folder into a shared folder session
  5327. if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId.'/sf_user_'.$userId)) {
  5328. create_unexisting_directory(
  5329. $courseInfo,
  5330. $userId,
  5331. $sessionId,
  5332. 0,
  5333. 0,
  5334. $documentDirectory,
  5335. '/shared_folder_session_'.$sessionId.'/sf_user_'.$userId,
  5336. $userInfo['complete_name'].'('.api_get_session_name($sessionId).')',
  5337. 1,
  5338. false,
  5339. false
  5340. );
  5341. }
  5342. }
  5343. /**
  5344. * Checks whether the user is into his shared folder or into a subfolder.
  5345. *
  5346. * @param int $user_id
  5347. * @param string $path
  5348. * @param int $sessionId
  5349. *
  5350. * @return bool Return true when user is in his user shared folder or into a subfolder
  5351. */
  5352. public static function is_my_shared_folder($user_id, $path, $sessionId)
  5353. {
  5354. $clean_path = Security::remove_XSS($path).'/';
  5355. //for security does not remove the last slash
  5356. $main_user_shared_folder = '/shared_folder\/sf_user_'.$user_id.'\//';
  5357. //for security does not remove the last slash
  5358. $main_user_shared_folder_session = '/shared_folder_session_'.$sessionId.'\/sf_user_'.$user_id.'\//';
  5359. if (preg_match($main_user_shared_folder, $clean_path)) {
  5360. return true;
  5361. } elseif (preg_match($main_user_shared_folder_session, $clean_path)) {
  5362. return true;
  5363. } else {
  5364. return false;
  5365. }
  5366. }
  5367. public static function isBasicCourseFolder($path, $sessionId)
  5368. {
  5369. $cleanPath = Security::remove_XSS($path);
  5370. $basicCourseFolder = '/basic-course-documents__'.$sessionId.'__0';
  5371. return $cleanPath == $basicCourseFolder;
  5372. }
  5373. /**
  5374. * Check if the file name or folder searched exist.
  5375. *
  5376. * @return bool Return true when exist
  5377. */
  5378. public static function search_keyword($document_name, $keyword)
  5379. {
  5380. if (api_strripos($document_name, $keyword) !== false) {
  5381. return true;
  5382. }
  5383. return false;
  5384. }
  5385. /**
  5386. * Checks whether a document can be previewed by using the browser.
  5387. *
  5388. * @param string $file_extension the filename extension of the document (it must be in lower case)
  5389. *
  5390. * @return bool returns TRUE or FALSE
  5391. */
  5392. public static function isBrowserViewable($file_extension)
  5393. {
  5394. static $allowed_extensions = [
  5395. 'htm', 'html', 'xhtml',
  5396. 'gif', 'jpg', 'jpeg', 'png', 'tif', 'tiff',
  5397. 'pdf', 'svg', 'swf',
  5398. 'txt', 'log',
  5399. 'mp4', 'ogg', 'ogv', 'ogx', 'mpg', 'mpeg', 'mov', 'avi', 'webm', 'wmv',
  5400. 'mp3', 'oga', 'wav', 'au', 'wma', 'mid', 'kar',
  5401. ];
  5402. /*
  5403. //TODO: make a admin switch to strict mode
  5404. 1. global default $allowed_extensions
  5405. if (in_array($file_extension, $allowed_extensions)) { // Assignment + a logical check.
  5406. return true;
  5407. }
  5408. 2. check native support
  5409. 3. check plugins: quicktime, mediaplayer, vlc, acrobat, flash, java
  5410. */
  5411. if (!($result = in_array($file_extension, $allowed_extensions))) {
  5412. // Assignment + a logical check.
  5413. return false;
  5414. }
  5415. //check native support (Explorer, Opera, Firefox, Chrome, Safari)
  5416. if ($file_extension == "pdf") {
  5417. return api_browser_support('pdf');
  5418. } elseif ($file_extension == "mp3") {
  5419. return api_browser_support('mp3');
  5420. } elseif ($file_extension == "mp4") {
  5421. return api_browser_support('mp4');
  5422. } elseif ($file_extension == "ogg" || $file_extension == "ogx" || $file_extension == "ogv" || $file_extension == "oga") {
  5423. return api_browser_support('ogg');
  5424. } elseif ($file_extension == "svg") {
  5425. return api_browser_support('svg');
  5426. } elseif ($file_extension == "mpg" || $file_extension == "mpeg") {
  5427. return api_browser_support('mpg');
  5428. } elseif ($file_extension == "mov") {
  5429. return api_browser_support('mov');
  5430. } elseif ($file_extension == "wav") {
  5431. return api_browser_support('wav');
  5432. } elseif ($file_extension == "mid" || $file_extension == "kar") {
  5433. return api_browser_support('mid');
  5434. } elseif ($file_extension == "avi") {
  5435. return api_browser_support('avi');
  5436. } elseif ($file_extension == "wma") {
  5437. return api_browser_support('wma');
  5438. } elseif ($file_extension == "wmv") {
  5439. return api_browser_support('wmv');
  5440. } elseif ($file_extension == "tif" || $file_extension == "tiff") {
  5441. return api_browser_support('tif');
  5442. } elseif ($file_extension == "mov") {
  5443. return api_browser_support('mov');
  5444. } elseif ($file_extension == "au") {
  5445. return api_browser_support('au');
  5446. } elseif ($file_extension == "webm") {
  5447. return api_browser_support('webm');
  5448. }
  5449. return $result;
  5450. }
  5451. /**
  5452. * @param array $courseInfo
  5453. * @param int $sessionId
  5454. *
  5455. * @return array
  5456. */
  5457. public static function getDeletedDocuments($courseInfo, $sessionId = 0)
  5458. {
  5459. $table = Database::get_course_table(TABLE_DOCUMENT);
  5460. $courseId = $courseInfo['real_id'];
  5461. $sessionCondition = api_get_session_condition($sessionId);
  5462. $sql = "SELECT * FROM $table
  5463. WHERE
  5464. path LIKE '%DELETED%' AND
  5465. c_id = $courseId
  5466. $sessionCondition
  5467. ORDER BY path
  5468. ";
  5469. $result = Database::query($sql);
  5470. $files = [];
  5471. while ($document = Database::fetch_array($result, 'ASSOC')) {
  5472. $files[] = $document;
  5473. }
  5474. return $files;
  5475. }
  5476. /**
  5477. * @param int $id
  5478. * @param array $courseInfo
  5479. * @param int $sessionId
  5480. *
  5481. * @return array
  5482. */
  5483. public static function getDeletedDocument($id, $courseInfo, $sessionId = 0)
  5484. {
  5485. if (empty($courseInfo)) {
  5486. return false;
  5487. }
  5488. $table = Database::get_course_table(TABLE_DOCUMENT);
  5489. $courseId = $courseInfo['real_id'];
  5490. $id = (int) $id;
  5491. $sessionCondition = api_get_session_condition($sessionId);
  5492. $sql = "SELECT * FROM $table
  5493. WHERE
  5494. path LIKE '%DELETED%' AND
  5495. id = $id AND
  5496. c_id = $courseId
  5497. $sessionCondition
  5498. LIMIT 1
  5499. ";
  5500. $result = Database::query($sql);
  5501. if (Database::num_rows($result)) {
  5502. $result = Database::fetch_array($result, 'ASSOC');
  5503. return $result;
  5504. }
  5505. return [];
  5506. }
  5507. /**
  5508. * @param int $id
  5509. * @param array $courseInfo
  5510. * @param int $sessionId
  5511. *
  5512. * @return bool
  5513. */
  5514. public static function purgeDocument($id, $courseInfo, $sessionId = 0)
  5515. {
  5516. $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
  5517. if (!empty($document)) {
  5518. $path = $document['path'];
  5519. $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
  5520. my_delete($coursePath.$path);
  5521. // Hard delete.
  5522. self::deleteDocumentFromDb($id, $courseInfo, $sessionId, true);
  5523. return true;
  5524. }
  5525. return false;
  5526. }
  5527. /**
  5528. * @param array $courseInfo
  5529. * @param int $sessionId
  5530. */
  5531. public static function purgeDocuments($courseInfo, $sessionId)
  5532. {
  5533. $files = self::getDeletedDocuments($courseInfo, $sessionId);
  5534. foreach ($files as $file) {
  5535. self::purgeDocument($file['id'], $courseInfo, $sessionId);
  5536. }
  5537. }
  5538. /**
  5539. * @param int $id
  5540. * @param array $courseInfo
  5541. * @param int $sessionId
  5542. */
  5543. public static function downloadDeletedDocument($id, $courseInfo, $sessionId)
  5544. {
  5545. $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
  5546. if (!empty($document)) {
  5547. $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
  5548. if (Security::check_abs_path($coursePath.$document['path'], $coursePath)) {
  5549. self::file_send_for_download($coursePath.$document['path'], true);
  5550. exit;
  5551. }
  5552. }
  5553. }
  5554. /**
  5555. * @param array $courseInfo
  5556. * @param int $sessionId
  5557. *
  5558. * @return bool
  5559. */
  5560. public static function downloadAllDeletedDocument($courseInfo, $sessionId)
  5561. {
  5562. $files = self::getDeletedDocuments($courseInfo, $sessionId);
  5563. if (empty($files)) {
  5564. return false;
  5565. }
  5566. $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
  5567. // Creating a ZIP file.
  5568. $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'.zip';
  5569. $zip = new PclZip($tempZipFile);
  5570. foreach ($files as $file) {
  5571. $zip->add(
  5572. $coursePath.$file['path'],
  5573. PCLZIP_OPT_REMOVE_PATH,
  5574. $coursePath
  5575. );
  5576. }
  5577. if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
  5578. self::file_send_for_download($tempZipFile, true);
  5579. @unlink($tempZipFile);
  5580. exit;
  5581. }
  5582. }
  5583. /**
  5584. * Delete documents from a session in a course.
  5585. *
  5586. * @param array $courseInfo
  5587. * @param int $sessionId
  5588. *
  5589. * @return bool
  5590. */
  5591. public static function deleteDocumentsFromSession($courseInfo, $sessionId)
  5592. {
  5593. if (empty($courseInfo)) {
  5594. return false;
  5595. }
  5596. if (empty($sessionId)) {
  5597. return false;
  5598. }
  5599. $itemPropertyTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
  5600. $documentTable = Database::get_course_table(TABLE_DOCUMENT);
  5601. $conditionSession = api_get_session_condition($sessionId, true, false, 'd.session_id');
  5602. $courseId = $courseInfo['real_id'];
  5603. // get invisible folders
  5604. $sql = "SELECT DISTINCT d.id, path
  5605. FROM $itemPropertyTable i
  5606. INNER JOIN $documentTable d
  5607. ON (i.c_id = d.c_id)
  5608. WHERE
  5609. d.id = i.ref AND
  5610. i.tool = '".TOOL_DOCUMENT."'
  5611. $conditionSession AND
  5612. i.c_id = $courseId AND
  5613. d.c_id = $courseId ";
  5614. $result = Database::query($sql);
  5615. $documents = Database::store_result($result, 'ASSOC');
  5616. if ($documents) {
  5617. $course_dir = $courseInfo['directory'].'/document';
  5618. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  5619. $base_work_dir = $sys_course_path.$course_dir;
  5620. foreach ($documents as $document) {
  5621. $documentId = $document['id'];
  5622. self::delete_document(
  5623. $courseInfo,
  5624. null,
  5625. $base_work_dir,
  5626. $sessionId,
  5627. $documentId
  5628. );
  5629. }
  5630. }
  5631. $sql = "DELETE FROM $documentTable
  5632. WHERE c_id = $courseId AND session_id = $sessionId";
  5633. Database::query($sql);
  5634. $sql = "DELETE FROM $itemPropertyTable
  5635. WHERE c_id = $courseId AND session_id = $sessionId AND tool = '".TOOL_DOCUMENT."'";
  5636. Database::query($sql);
  5637. }
  5638. /**
  5639. * Update the file or directory path in the document db document table.
  5640. *
  5641. * @author - Hugues Peeters <peeters@ipm.ucl.ac.be>
  5642. *
  5643. * @param string $action - action type require : 'delete' or 'update'
  5644. * @param string $old_path - old path info stored to change
  5645. * @param string $new_path - new path info to substitute
  5646. *
  5647. * @desc Update the file or directory path in the document db document table
  5648. */
  5649. public static function updateDbInfo($action, $old_path, $new_path = '')
  5650. {
  5651. $dbTable = Database::get_course_table(TABLE_DOCUMENT);
  5652. $course_id = api_get_course_int_id();
  5653. $old_path = Database::escape_string($old_path);
  5654. switch ($action) {
  5655. case 'delete':
  5656. $query = "DELETE FROM $dbTable
  5657. WHERE
  5658. c_id = $course_id AND
  5659. (
  5660. path LIKE BINARY '".$old_path."' OR
  5661. path LIKE BINARY '".$old_path."/%'
  5662. )";
  5663. Database::query($query);
  5664. break;
  5665. case 'update':
  5666. if ($new_path[0] == '.') {
  5667. $new_path = substr($new_path, 1);
  5668. }
  5669. $new_path = str_replace('//', '/', $new_path);
  5670. // Attempt to update - tested & working for root dir
  5671. $new_path = Database::escape_string($new_path);
  5672. $query = "UPDATE $dbTable SET
  5673. path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
  5674. WHERE
  5675. c_id = $course_id AND
  5676. (path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%')";
  5677. Database::query($query);
  5678. break;
  5679. }
  5680. }
  5681. /**
  5682. * This function calculates the resized width and resized heigt
  5683. * according to the source and target widths
  5684. * and heights, height so that no distortions occur
  5685. * parameters.
  5686. *
  5687. * @param $image = the absolute path to the image
  5688. * @param $target_width = how large do you want your resized image
  5689. * @param $target_height = how large do you want your resized image
  5690. * @param $slideshow (default=0) =
  5691. * indicates weither we are generating images for a slideshow or not,
  5692. * this overrides the $_SESSION["image_resizing"] a bit so that a thumbnail
  5693. * view is also possible when you choose not to resize the source images
  5694. *
  5695. * @return array
  5696. */
  5697. public static function resizeImageSlideShow(
  5698. $image,
  5699. $target_width,
  5700. $target_height,
  5701. $slideshow = 0
  5702. ) {
  5703. // Modifications by Ivan Tcholakov, 04-MAY-2009.
  5704. $result = [];
  5705. $imageResize = Session::read('image_resizing');
  5706. if ($imageResize == 'resizing' || $slideshow == 1) {
  5707. $new_sizes = api_resize_image($image, $target_width, $target_height);
  5708. $result[] = $new_sizes['height'];
  5709. $result[] = $new_sizes['width'];
  5710. } else {
  5711. $size = api_getimagesize($image);
  5712. $result[] = $size['height'];
  5713. $result[] = $size['width'];
  5714. }
  5715. return $result;
  5716. }
  5717. /**
  5718. * Calculates the total size of a directory by adding the sizes (that
  5719. * are stored in the database) of all files & folders in this directory.
  5720. *
  5721. * @param string $path
  5722. * @param bool $can_see_invisible
  5723. *
  5724. * @return int Total size
  5725. */
  5726. public static function getTotalFolderSize($path, $can_see_invisible = false)
  5727. {
  5728. $table_itemproperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  5729. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  5730. $tool_document = TOOL_DOCUMENT;
  5731. $course_id = api_get_course_int_id();
  5732. $session_id = api_get_session_id();
  5733. $session_condition = api_get_session_condition(
  5734. $session_id,
  5735. true,
  5736. true,
  5737. 'props.session_id'
  5738. );
  5739. if (empty($course_id)) {
  5740. return 0;
  5741. }
  5742. $path = Database::escape_string($path);
  5743. $visibility_rule = ' props.visibility '.($can_see_invisible ? '<> 2' : '= 1');
  5744. $sql = "SELECT SUM(table1.size) FROM (
  5745. SELECT props.ref, size
  5746. FROM $table_itemproperty AS props
  5747. INNER JOIN $table_document AS docs
  5748. ON (docs.id = props.ref AND docs.c_id = props.c_id)
  5749. WHERE
  5750. docs.c_id = $course_id AND
  5751. docs.path LIKE '$path/%' AND
  5752. props.c_id = $course_id AND
  5753. props.tool = '$tool_document' AND
  5754. $visibility_rule
  5755. $session_condition
  5756. GROUP BY ref
  5757. ) as table1";
  5758. $result = Database::query($sql);
  5759. if ($result && Database::num_rows($result) != 0) {
  5760. $row = Database::fetch_row($result);
  5761. return $row[0] == null ? 0 : $row[0];
  5762. } else {
  5763. return 0;
  5764. }
  5765. }
  5766. /**
  5767. * Adds a cloud link to the database.
  5768. *
  5769. * @author - Aquilino Blanco Cores <aqblanco@gmail.com>
  5770. *
  5771. * @param array $_course
  5772. * @param string $path
  5773. * @param string $url
  5774. * @param string $name
  5775. *
  5776. * @return int id of document or 0 if already exists or there was a problem creating it
  5777. */
  5778. public static function addCloudLink($_course, $path, $url, $name)
  5779. {
  5780. $file_path = $path;
  5781. if (!self::cloudLinkExists($_course, $path, $url)) {
  5782. $doc_id = add_document($_course, $file_path, 'link', 0, $name, $url);
  5783. if ($doc_id) {
  5784. // Update document item_property
  5785. api_item_property_update(
  5786. $_course,
  5787. TOOL_DOCUMENT,
  5788. $doc_id,
  5789. 'DocumentAdded',
  5790. api_get_user_id(),
  5791. api_get_group_id(),
  5792. api_get_user_id(),
  5793. null,
  5794. null,
  5795. api_get_session_id()
  5796. );
  5797. }
  5798. // If the file is in a folder, we need to update all parent folders
  5799. item_property_update_on_folder($_course, $file_path, api_get_user_id());
  5800. return $doc_id;
  5801. } else {
  5802. return 0;
  5803. }
  5804. }
  5805. /**
  5806. * Deletes a cloud link from the database.
  5807. *
  5808. * @author - Aquilino Blanco Cores <aqblanco@gmail.com>
  5809. *
  5810. * @param array $courseInfo
  5811. * @param string $documentId
  5812. *
  5813. * @return bool true if success / false if an error occurred
  5814. */
  5815. public static function deleteCloudLink($courseInfo, $documentId)
  5816. {
  5817. if (empty($documentId) || empty($courseInfo)) {
  5818. return false;
  5819. }
  5820. $documentId = (int) $documentId;
  5821. $fileDeletedFromDb = false;
  5822. if (!empty($documentId)) {
  5823. self::deleteDocumentFromDb($documentId, $courseInfo, 0, true);
  5824. // checking
  5825. $table = Database::get_course_table(TABLE_DOCUMENT);
  5826. $courseId = $courseInfo['real_id'];
  5827. echo $sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
  5828. $result = Database::query($sql);
  5829. $exists = Database::num_rows($result) > 0;
  5830. $fileDeletedFromDb = !$exists;
  5831. }
  5832. return $fileDeletedFromDb;
  5833. }
  5834. /**
  5835. * Gets the id of a cloud link with a given path.
  5836. *
  5837. * @author - Aquilino Blanco Cores <aqblanco@gmail.com>
  5838. *
  5839. * @param array $courseInfo
  5840. * @param string $path
  5841. * @param string $url
  5842. *
  5843. * @return int link's id / false if no link found
  5844. */
  5845. public static function getCloudLinkId($courseInfo, $path, $url)
  5846. {
  5847. $table = Database::get_course_table(TABLE_DOCUMENT);
  5848. if (empty($courseInfo)) {
  5849. return false;
  5850. }
  5851. $courseId = (int) $courseInfo['real_id'];
  5852. $path = Database::escape_string($path);
  5853. if (substr($path, -1) != '/') {
  5854. // Add final slash to path if not present
  5855. $path .= '/';
  5856. }
  5857. if (!empty($courseId) && !empty($path)) {
  5858. $sql = "SELECT id FROM $table
  5859. WHERE
  5860. c_id = $courseId AND
  5861. path LIKE BINARY '$path' AND
  5862. comment = '$url' AND
  5863. filetype = 'link'
  5864. LIMIT 1";
  5865. $result = Database::query($sql);
  5866. if ($result && Database::num_rows($result)) {
  5867. $row = Database::fetch_array($result);
  5868. return intval($row[0]);
  5869. }
  5870. }
  5871. return false;
  5872. }
  5873. /**
  5874. * Checks if a cloud link exists.
  5875. *
  5876. * @author - Aquilino Blanco Cores <aqblanco@gmail.com>
  5877. *
  5878. * @param array $courseInfo
  5879. * @param string $path
  5880. * @param string $url
  5881. *
  5882. * @return bool true if it exists false in other case
  5883. */
  5884. public static function cloudLinkExists($courseInfo, $path, $url)
  5885. {
  5886. $exists = self::getCloudLinkId($courseInfo, $path, $url);
  5887. return $exists;
  5888. }
  5889. /**
  5890. * Gets the wellformed URLs regular expression in order to use it on forms' verifications.
  5891. *
  5892. * @author Aquilino Blanco Cores <aqblanco@gmail.com>
  5893. *
  5894. * @return string the well formed URLs regular expressions string
  5895. */
  5896. public static function getWellFormedUrlRegex()
  5897. {
  5898. return '/\(?((http|https|ftp):\/\/)(?:((?:[^\W\s]|\.|-|[:]{1})+)@{1})?((?:www.)?(?:[^\W\s]|\.|-)+[\.][^\W\s]{2,4}|localhost(?=\/)|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::(\d*))?([\/]?[^\s\?]*[\/]{1})*(?:\/?([^\s\n\?\[\]\{\}\#]*(?:(?=\.)){1}|[^\s\n\?\[\]\{\}\.\#]*)?([\.]{1}[^\s\?\#]*)?)?(?:\?{1}([^\s\n\#\[\]]*))?([\#][^\s\n]*)?\)?/i';
  5899. }
  5900. /**
  5901. * Gets the files hosting sites' whitelist.
  5902. *
  5903. * @author Aquilino Blanco Cores <aqblanco@gmail.com>
  5904. *
  5905. * @return array the sites list
  5906. */
  5907. public static function getFileHostingWhiteList()
  5908. {
  5909. return [
  5910. 'asuswebstorage.com',
  5911. 'dropbox.com',
  5912. 'dropboxusercontent.com',
  5913. 'fileserve.com',
  5914. 'drive.google.com',
  5915. 'docs.google.com',
  5916. 'icloud.com',
  5917. 'mediafire.com',
  5918. 'mega.nz',
  5919. 'onedrive.live.com',
  5920. 'slideshare.net',
  5921. 'scribd.com',
  5922. 'wetransfer.com',
  5923. 'box.com',
  5924. 'livefilestore.com', // OneDrive
  5925. ];
  5926. }
  5927. /**
  5928. * @param int $userId
  5929. *
  5930. * @return array Example [ 0 => ['code' => 'ABC', 'directory' => 'ABC0', 'path' => '/images/gallery/test.png', 'code_path' => 'ABC:/images/gallery/test.png'], 1 => ...]
  5931. */
  5932. public static function getAllDocumentsCreatedByUser($userId)
  5933. {
  5934. $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
  5935. $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
  5936. $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
  5937. $userId = (int) $userId;
  5938. $sql = "SELECT DISTINCT c.code, c.directory, docs.path
  5939. FROM $tblItemProperty AS last
  5940. INNER JOIN $tblDocument AS docs
  5941. ON (
  5942. docs.id = last.ref AND
  5943. docs.c_id = last.c_id AND
  5944. docs.filetype <> 'folder'
  5945. )
  5946. INNER JOIN $tblCourse as c
  5947. ON (
  5948. docs.c_id = c.id
  5949. )
  5950. WHERE
  5951. last.tool = '".TOOL_DOCUMENT."' AND
  5952. last.insert_user_id = $userId AND
  5953. docs.path NOT LIKE '%_DELETED_%'
  5954. ORDER BY c.directory, docs.path
  5955. ";
  5956. $result = Database::query($sql);
  5957. $list = [];
  5958. if (Database::num_rows($result) != 0) {
  5959. while ($row = Database::fetch_array($result, 'ASSOC')) {
  5960. $row['code_path'] = $row['code'].':'.$row['path'];
  5961. $list[] = $row;
  5962. }
  5963. }
  5964. return $list;
  5965. }
  5966. /**
  5967. * Parse file information into a link.
  5968. *
  5969. * @param array $userInfo Current user info
  5970. * @param array $course_info
  5971. * @param int $session_id
  5972. * @param array $resource
  5973. * @param int $lp_id
  5974. * @param bool $add_move_button
  5975. * @param string $target
  5976. * @param string $overwrite_url
  5977. *
  5978. * @return string|null
  5979. */
  5980. private static function parseFile(
  5981. $userInfo,
  5982. $course_info,
  5983. $session_id,
  5984. $resource,
  5985. $lp_id,
  5986. $add_move_button,
  5987. $target,
  5988. $overwrite_url
  5989. ) {
  5990. $img_sys_path = api_get_path(SYS_CODE_PATH).'img/';
  5991. $web_code_path = api_get_path(WEB_CODE_PATH);
  5992. $documentId = $resource['id'];
  5993. $path = $resource['path'];
  5994. if (empty($path)) {
  5995. $num = 0;
  5996. } else {
  5997. $num = substr_count($path, '/') - 1;
  5998. }
  5999. // It's a file.
  6000. $icon = choose_image($path);
  6001. $position = strrpos($icon, '.');
  6002. $icon = substr($icon, 0, $position).'_small.gif';
  6003. $my_file_title = $resource['title'];
  6004. $visibility = $resource['visibility'];
  6005. // If title is empty we try to use the path
  6006. if (empty($my_file_title)) {
  6007. $my_file_title = basename($path);
  6008. }
  6009. // Show the "image name" not the filename of the image.
  6010. if ($lp_id) {
  6011. // LP URL
  6012. $url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&action=add_item&type='.TOOL_DOCUMENT.'&file='.$documentId.'&lp_id='.$lp_id;
  6013. } else {
  6014. // Direct document URL
  6015. $url = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
  6016. }
  6017. if (!empty($overwrite_url)) {
  6018. $overwrite_url = Security::remove_XSS($overwrite_url);
  6019. $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId;
  6020. }
  6021. $img = Display::returnIconPath($icon);
  6022. if (!file_exists($img_sys_path.$icon)) {
  6023. $img = Display::returnIconPath('default_small.gif');
  6024. }
  6025. $link = Display::url(
  6026. '<img alt="" src="'.$img.'" title="" />&nbsp;'.$my_file_title,
  6027. $url,
  6028. ['target' => $target, 'class' => 'moved']
  6029. );
  6030. $directUrl = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
  6031. $link .= '&nbsp;'.Display::url(
  6032. Display::return_icon('preview_view.png', get_lang('Preview')),
  6033. $directUrl,
  6034. ['target' => '_blank']
  6035. );
  6036. $visibilityClass = null;
  6037. if ($visibility == 0) {
  6038. $visibilityClass = ' text-muted ';
  6039. }
  6040. $return = null;
  6041. if ($lp_id == false) {
  6042. $return .= '<li class="doc_resource '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
  6043. } else {
  6044. $return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
  6045. }
  6046. $return .= '<div class="item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
  6047. if ($add_move_button) {
  6048. $return .= '<a class="moved" href="#">';
  6049. $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY);
  6050. $return .= '</a> ';
  6051. }
  6052. $return .= $link;
  6053. $sessionStar = api_get_session_image($resource['session_id'], $userInfo['status']);
  6054. $return .= $sessionStar;
  6055. $return .= '</div></li>';
  6056. return $return;
  6057. }
  6058. /**
  6059. * @param int $folderId
  6060. * @param array $resource
  6061. * @param int $lp_id
  6062. *
  6063. * @return string|null
  6064. */
  6065. private static function parseFolder($folderId, $resource, $lp_id)
  6066. {
  6067. $title = isset($resource['title']) ? $resource['title'] : null;
  6068. $path = isset($resource['path']) ? $resource['path'] : null;
  6069. if (empty($path)) {
  6070. $num = 0;
  6071. } else {
  6072. $num = substr_count($path, '/');
  6073. }
  6074. // It's a folder.
  6075. //hide some folders
  6076. if (in_array(
  6077. $path,
  6078. ['shared_folder', 'chat_files', 'HotPotatoes_files', 'css', 'certificates']
  6079. )) {
  6080. return null;
  6081. } elseif (preg_match('/_groupdocs/', $path)) {
  6082. return null;
  6083. } elseif (preg_match('/sf_user_/', $path)) {
  6084. return null;
  6085. } elseif (preg_match('/shared_folder_session_/', $path)) {
  6086. return null;
  6087. }
  6088. //$onclick = '';
  6089. // if in LP, hidden folder are displayed in grey
  6090. $folder_class_hidden = '';
  6091. if ($lp_id) {
  6092. if (isset($resource['visible']) && $resource['visible'] == 0) {
  6093. $folder_class_hidden = ' doc_folder_hidden'; // in base.css
  6094. }
  6095. }
  6096. $onclick = 'onclick="javascript: testResources(\'res_'.$resource['id'].'\',\'img_'.$resource['id'].'\')"';
  6097. $return = null;
  6098. if (empty($path)) {
  6099. $return = '<ul class="lp_resource">';
  6100. }
  6101. $return .= '<li class="doc_folder'.$folder_class_hidden.'" id="doc_id_'.$resource['id'].'" style="margin-left:'.($num * 18).'px; ">';
  6102. $image = Display::returnIconPath('nolines_plus.gif');
  6103. if (empty($path)) {
  6104. $image = Display::returnIconPath('nolines_minus.gif');
  6105. }
  6106. $return .= '<img style="cursor: pointer;" src="'.$image.'" align="absmiddle" id="img_'.$resource['id'].'" '.$onclick.'>';
  6107. $return .= Display::return_icon('lp_folder.gif').'&nbsp;';
  6108. $return .= '<span '.$onclick.' style="cursor: pointer;" >'.$title.'</span>';
  6109. $return .= '</li>';
  6110. if (empty($path)) {
  6111. if ($folderId == false) {
  6112. $return .= '<div id="res_'.$resource['id'].'" >';
  6113. } else {
  6114. $return .= '<div id="res_'.$resource['id'].'" style="display: none;" >';
  6115. }
  6116. }
  6117. return $return;
  6118. }
  6119. /**
  6120. * Get the button to edit document.
  6121. *
  6122. * @param bool $isReadOnly
  6123. * @param array $documentData
  6124. * @param string $extension
  6125. * @param bool $isCertificateMode
  6126. *
  6127. * @return string
  6128. */
  6129. private static function getButtonEdit($isReadOnly, array $documentData, $extension, $isCertificateMode)
  6130. {
  6131. $extension = strtolower($extension);
  6132. $iconEn = Display::return_icon('edit.png', get_lang('Modify'));
  6133. $iconDis = Display::return_icon('edit_na.png', get_lang('Modify'));
  6134. $courseParams = api_get_cidreq();
  6135. $webOdfExtensionList = self::get_web_odf_extension_list();
  6136. $path = $documentData['path'];
  6137. $document_id = $documentData['id'];
  6138. if ($isReadOnly) {
  6139. if (!api_is_course_admin() && !api_is_platform_admin()) {
  6140. return $iconDis;
  6141. }
  6142. if (
  6143. $extension == 'svg' && api_browser_support('svg') &&
  6144. api_get_setting('enabled_support_svg') == 'true'
  6145. ) {
  6146. return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
  6147. }
  6148. if (
  6149. in_array($extension, $webOdfExtensionList) &&
  6150. api_get_configuration_value('enabled_support_odf') === true
  6151. ) {
  6152. return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
  6153. }
  6154. if (
  6155. in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
  6156. api_get_setting('enabled_support_pixlr') == 'true'
  6157. ) {
  6158. return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
  6159. }
  6160. return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
  6161. }
  6162. if (in_array($path, self::get_system_folders())) {
  6163. return $iconDis;
  6164. }
  6165. if ($isCertificateMode) {
  6166. return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id&curdirpath=/certificates");
  6167. }
  6168. $sessionId = api_get_session_id();
  6169. if ($sessionId && $documentData['session_id'] != $sessionId) {
  6170. return $iconDis;
  6171. }
  6172. if (
  6173. $extension == 'svg' && api_browser_support('svg') &&
  6174. api_get_setting('enabled_support_svg') == 'true'
  6175. ) {
  6176. return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
  6177. }
  6178. if (
  6179. in_array($extension, $webOdfExtensionList) &&
  6180. api_get_configuration_value('enabled_support_odf') === true
  6181. ) {
  6182. return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
  6183. }
  6184. if (
  6185. in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
  6186. api_get_setting('enabled_support_pixlr') == 'true'
  6187. ) {
  6188. return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
  6189. }
  6190. return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
  6191. }
  6192. /**
  6193. * Get the button to move document.
  6194. *
  6195. * @param bool $isReadOnly
  6196. * @param array $documentData
  6197. * @param bool $isCertificateMode
  6198. * @param int $parentId
  6199. *
  6200. * @return string
  6201. */
  6202. private static function getButtonMove($isReadOnly, array $documentData, $isCertificateMode, $parentId)
  6203. {
  6204. $iconEn = Display::return_icon('move.png', get_lang('Move'));
  6205. $iconDis = Display::return_icon('move_na.png', get_lang('Move'));
  6206. if ($isReadOnly) {
  6207. return $iconDis;
  6208. }
  6209. $path = $documentData['path'];
  6210. $document_id = $documentData['id'];
  6211. $sessionId = api_get_session_id();
  6212. $courseParams = api_get_cidreq();
  6213. if ($isCertificateMode || in_array($path, self::get_system_folders())) {
  6214. return $iconDis;
  6215. }
  6216. if ($sessionId) {
  6217. if ($documentData['session_id'] != $sessionId) {
  6218. return $iconDis;
  6219. }
  6220. }
  6221. $urlMoveParams = http_build_query(['id' => $parentId, 'move' => $document_id]);
  6222. return Display::url(
  6223. $iconEn,
  6224. api_get_self()."?$courseParams&$urlMoveParams"
  6225. );
  6226. }
  6227. /**
  6228. * Get the button to set visibility to document.
  6229. *
  6230. * @param bool $isReadOnly
  6231. * @param int $visibility
  6232. * @param array $documentData
  6233. * @param bool $isCertificateMode
  6234. * @param int $parentId
  6235. *
  6236. * @return string|null
  6237. */
  6238. private static function getButtonVisibility(
  6239. $isReadOnly,
  6240. $visibility,
  6241. array $documentData,
  6242. $isCertificateMode,
  6243. $parentId
  6244. ) {
  6245. $visibility_icon = $visibility == 0 ? 'invisible' : 'visible';
  6246. $visibility_command = $visibility == 0 ? 'set_visible' : 'set_invisible';
  6247. $courseParams = api_get_cidreq();
  6248. if ($isReadOnly) {
  6249. if (api_is_allowed_to_edit() || api_is_platform_admin()) {
  6250. return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
  6251. }
  6252. return null;
  6253. }
  6254. if ($isCertificateMode) {
  6255. return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
  6256. }
  6257. if (api_is_allowed_to_edit() || api_is_platform_admin()) {
  6258. $tip_visibility = $visibility_icon == 'invisible' ? get_lang('Show') : get_lang('Hide');
  6259. return Display::url(
  6260. Display::return_icon($visibility_icon.'.png', $tip_visibility),
  6261. api_get_self()."?$courseParams&id=$parentId&$visibility_command={$documentData['id']}"
  6262. );
  6263. }
  6264. return null;
  6265. }
  6266. /**
  6267. * GEt the button to delete a document.
  6268. *
  6269. * @param bool $isReadOnly
  6270. * @param array $documentData
  6271. * @param bool $isCertificateMode
  6272. * @param string $curDirPath
  6273. * @param int $parentId
  6274. *
  6275. * @return string
  6276. */
  6277. private static function getButtonDelete(
  6278. $isReadOnly,
  6279. array $documentData,
  6280. $isCertificateMode,
  6281. $curDirPath,
  6282. $parentId
  6283. ) {
  6284. $iconEn = Display::return_icon('delete.png', get_lang('Delete'));
  6285. $iconDis = Display::return_icon('delete_na.png', get_lang('ThisFolderCannotBeDeleted'));
  6286. $path = $documentData['path'];
  6287. $id = $documentData['id'];
  6288. $courseParams = api_get_cidreq();
  6289. if ($isReadOnly) {
  6290. return $iconDis;
  6291. }
  6292. if (in_array($path, self::get_system_folders())) {
  6293. return $iconDis;
  6294. }
  6295. $titleToShow = addslashes(basename($documentData['title']));
  6296. $urlDeleteParams = http_build_query([
  6297. 'curdirpath' => $curDirPath,
  6298. 'action' => 'delete_item',
  6299. 'id' => $parentId,
  6300. 'deleteid' => $documentData['id'],
  6301. ]);
  6302. $btn = Display::url(
  6303. $iconEn,
  6304. '#',
  6305. [
  6306. 'data-item-title' => $titleToShow,
  6307. 'data-href' => api_get_self()."?$courseParams&$urlDeleteParams",
  6308. 'data-toggle' => 'modal',
  6309. 'data-target' => '#confirm-delete',
  6310. ]
  6311. );
  6312. if (
  6313. isset($_GET['curdirpath']) &&
  6314. $_GET['curdirpath'] == '/certificates' &&
  6315. self::get_default_certificate_id(api_get_course_id()) == $id
  6316. ) {
  6317. return $btn;
  6318. }
  6319. if ($isCertificateMode) {
  6320. return $btn;
  6321. }
  6322. $sessionId = api_get_session_id();
  6323. if ($sessionId) {
  6324. if ($documentData['session_id'] != $sessionId) {
  6325. return $iconDis;
  6326. }
  6327. }
  6328. return $btn;
  6329. }
  6330. }