document.lib.php 264 KB

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