document.lib.php 165 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * This is the document library for Chamilo.
  5. * It is / will be used to provide a service layer to all document-using tools.
  6. * and eliminate code duplication fro group documents, scorm documents, main documents.
  7. * Include/require it in your code to use its functionality.
  8. *
  9. * @package chamilo.library
  10. */
  11. /**
  12. * Code
  13. */
  14. class DocumentManager
  15. {
  16. private function __construct()
  17. {
  18. }
  19. /**
  20. * @param string
  21. * @return the document folder quota for the current course, in bytes, or the default quota
  22. */
  23. public static function get_course_quota($course_code = null)
  24. {
  25. if (empty($course_code)) {
  26. $course_info = api_get_course_info();
  27. } else {
  28. $course_info = api_get_course_info($course_code);
  29. }
  30. $course_quota = null;
  31. if (empty($course_info)) {
  32. return DEFAULT_DOCUMENT_QUOTA;
  33. } else {
  34. $course_quota = $course_info['disk_quota'];
  35. }
  36. if (is_null($course_quota) || empty($course_quota)) {
  37. // Course table entry for quota was null, then use default value
  38. $course_quota = DEFAULT_DOCUMENT_QUOTA;
  39. }
  40. return $course_quota;
  41. }
  42. /**
  43. * Get the content type of a file by checking the extension
  44. * We could use mime_content_type() with php-versions > 4.3,
  45. * but this doesn't work as it should on Windows installations
  46. *
  47. * @param string $filename or boolean TRUE to return complete array
  48. * @author ? first version
  49. * @author Bert Vanderkimpen
  50. * @return string
  51. *
  52. */
  53. public static function file_get_mime_type($filename)
  54. {
  55. // All MIME types in an array (from 1.6, this is the authorative source)
  56. // Please, keep this alphabetical if you add something to this list!
  57. $mime_types = array(
  58. 'ai' => 'application/postscript',
  59. 'aif' => 'audio/x-aiff',
  60. 'aifc' => 'audio/x-aiff',
  61. 'aiff' => 'audio/x-aiff',
  62. 'asf' => 'video/x-ms-asf',
  63. 'asc' => 'text/plain',
  64. 'au' => 'audio/basic',
  65. 'avi' => 'video/x-msvideo',
  66. 'bcpio' => 'application/x-bcpio',
  67. 'bin' => 'application/octet-stream',
  68. 'bmp' => 'image/bmp',
  69. 'cdf' => 'application/x-netcdf',
  70. 'class' => 'application/octet-stream',
  71. 'cpio' => 'application/x-cpio',
  72. 'cpt' => 'application/mac-compactpro',
  73. 'csh' => 'application/x-csh',
  74. 'css' => 'text/css',
  75. 'dcr' => 'application/x-director',
  76. 'dir' => 'application/x-director',
  77. 'djv' => 'image/vnd.djvu',
  78. 'djvu' => 'image/vnd.djvu',
  79. 'dll' => 'application/octet-stream',
  80. 'dmg' => 'application/x-diskcopy',
  81. 'dms' => 'application/octet-stream',
  82. 'doc' => 'application/msword',
  83. 'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
  84. 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  85. 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  86. 'dvi' => 'application/x-dvi',
  87. 'dwg' => 'application/vnd.dwg',
  88. 'dwf' => 'application/vnd.dwf',
  89. 'dxf' => 'application/vnd.dxf',
  90. 'dxr' => 'application/x-director',
  91. 'eps' => 'application/postscript',
  92. 'epub' => 'application/epub+zip',
  93. 'etx' => 'text/x-setext',
  94. 'exe' => 'application/octet-stream',
  95. 'ez' => 'application/andrew-inset',
  96. 'gif' => 'image/gif',
  97. 'gtar' => 'application/x-gtar',
  98. 'gz' => 'application/x-gzip',
  99. 'hdf' => 'application/x-hdf',
  100. 'hqx' => 'application/mac-binhex40',
  101. 'htm' => 'text/html',
  102. 'html' => 'text/html',
  103. 'ice' => 'x-conference-xcooltalk',
  104. 'ief' => 'image/ief',
  105. 'iges' => 'model/iges',
  106. 'igs' => 'model/iges',
  107. 'jar' => 'application/java-archiver',
  108. 'jpe' => 'image/jpeg',
  109. 'jpeg' => 'image/jpeg',
  110. 'jpg' => 'image/jpeg',
  111. 'js' => 'application/x-javascript',
  112. 'kar' => 'audio/midi',
  113. 'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
  114. 'latex' => 'application/x-latex',
  115. 'lha' => 'application/octet-stream',
  116. 'log' => 'text/plain',
  117. 'lzh' => 'application/octet-stream',
  118. 'm1a' => 'audio/mpeg',
  119. 'm2a' => 'audio/mpeg',
  120. 'm3u' => 'audio/x-mpegurl',
  121. 'man' => 'application/x-troff-man',
  122. 'me' => 'application/x-troff-me',
  123. 'mesh' => 'model/mesh',
  124. 'mid' => 'audio/midi',
  125. 'midi' => 'audio/midi',
  126. 'mov' => 'video/quicktime',
  127. 'movie' => 'video/x-sgi-movie',
  128. 'mp2' => 'audio/mpeg',
  129. 'mp3' => 'audio/mpeg',
  130. 'mp4' => 'video/mpeg4-generic',
  131. 'mpa' => 'audio/mpeg',
  132. 'mpe' => 'video/mpeg',
  133. 'mpeg' => 'video/mpeg',
  134. 'mpg' => 'video/mpeg',
  135. 'mpga' => 'audio/mpeg',
  136. 'ms' => 'application/x-troff-ms',
  137. 'msh' => 'model/mesh',
  138. 'mxu' => 'video/vnd.mpegurl',
  139. 'nc' => 'application/x-netcdf',
  140. 'oda' => 'application/oda',
  141. 'oga' => 'audio/ogg',
  142. 'ogg' => 'application/ogg',
  143. 'ogx' => 'application/ogg',
  144. 'ogv' => 'video/ogg',
  145. 'pbm' => 'image/x-portable-bitmap',
  146. 'pct' => 'image/pict',
  147. 'pdb' => 'chemical/x-pdb',
  148. 'pdf' => 'application/pdf',
  149. 'pgm' => 'image/x-portable-graymap',
  150. 'pgn' => 'application/x-chess-pgn',
  151. 'pict' => 'image/pict',
  152. 'png' => 'image/png',
  153. 'pnm' => 'image/x-portable-anymap',
  154. 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
  155. 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
  156. 'pps' => 'application/vnd.ms-powerpoint',
  157. 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
  158. 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
  159. 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
  160. 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
  161. 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  162. 'ppm' => 'image/x-portable-pixmap',
  163. 'ppt' => 'application/vnd.ms-powerpoint',
  164. 'pps' => 'application/vnd.ms-powerpoint',
  165. 'ps' => 'application/postscript',
  166. 'qt' => 'video/quicktime',
  167. 'ra' => 'audio/x-realaudio',
  168. 'ram' => 'audio/x-pn-realaudio',
  169. 'rar' => 'image/x-rar-compressed',
  170. 'ras' => 'image/x-cmu-raster',
  171. 'rgb' => 'image/x-rgb',
  172. 'rm' => 'audio/x-pn-realaudio',
  173. 'roff' => 'application/x-troff',
  174. 'rpm' => 'audio/x-pn-realaudio-plugin',
  175. 'rtf' => 'text/rtf',
  176. 'rtx' => 'text/richtext',
  177. 'sgm' => 'text/sgml',
  178. 'sgml' => 'text/sgml',
  179. 'sh' => 'application/x-sh',
  180. 'shar' => 'application/x-shar',
  181. 'silo' => 'model/mesh',
  182. 'sib' => 'application/X-Sibelius-Score',
  183. 'sit' => 'application/x-stuffit',
  184. 'skd' => 'application/x-koan',
  185. 'skm' => 'application/x-koan',
  186. 'skp' => 'application/x-koan',
  187. 'skt' => 'application/x-koan',
  188. 'smi' => 'application/smil',
  189. 'smil' => 'application/smil',
  190. 'snd' => 'audio/basic',
  191. 'so' => 'application/octet-stream',
  192. 'spl' => 'application/x-futuresplash',
  193. 'src' => 'application/x-wais-source',
  194. 'sv4cpio' => 'application/x-sv4cpio',
  195. 'sv4crc' => 'application/x-sv4crc',
  196. 'svf' => 'application/vnd.svf',
  197. 'svg' => 'image/svg+xml',
  198. //'svgz' => 'image/svg+xml',
  199. 'swf' => 'application/x-shockwave-flash',
  200. 'sxc' => 'application/vnd.sun.xml.calc',
  201. 'sxi' => 'application/vnd.sun.xml.impress',
  202. 'sxw' => 'application/vnd.sun.xml.writer',
  203. 't' => 'application/x-troff',
  204. 'tar' => 'application/x-tar',
  205. 'tcl' => 'application/x-tcl',
  206. 'tex' => 'application/x-tex',
  207. 'texi' => 'application/x-texinfo',
  208. 'texinfo' => 'application/x-texinfo',
  209. 'tga' => 'image/x-targa',
  210. 'tif' => 'image/tif',
  211. 'tiff' => 'image/tiff',
  212. 'tr' => 'application/x-troff',
  213. 'tsv' => 'text/tab-seperated-values',
  214. 'txt' => 'text/plain',
  215. 'ustar' => 'application/x-ustar',
  216. 'vcd' => 'application/x-cdlink',
  217. 'vrml' => 'model/vrml',
  218. 'wav' => 'audio/x-wav',
  219. 'wbmp' => 'image/vnd.wap.wbmp',
  220. 'wbxml' => 'application/vnd.wap.wbxml',
  221. 'wml' => 'text/vnd.wap.wml',
  222. 'wmlc' => 'application/vnd.wap.wmlc',
  223. 'wmls' => 'text/vnd.wap.wmlscript',
  224. 'wmlsc' => 'application/vnd.wap.wmlscriptc',
  225. 'wma' => 'audio/x-ms-wma',
  226. 'wmv' => 'video/x-ms-wmv',
  227. 'wrl' => 'model/vrml',
  228. 'xbm' => 'image/x-xbitmap',
  229. 'xht' => 'application/xhtml+xml',
  230. 'xhtml' => 'application/xhtml+xml',
  231. 'xls' => 'application/vnd.ms-excel',
  232. 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
  233. 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
  234. 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  235. 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
  236. 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
  237. 'xml' => 'text/xml',
  238. 'xpm' => 'image/x-xpixmap',
  239. 'xsl' => 'text/xml',
  240. 'xwd' => 'image/x-windowdump',
  241. 'xyz' => 'chemical/x-xyz',
  242. 'zip' => 'application/zip'
  243. );
  244. if ($filename === true) {
  245. return $mime_types;
  246. }
  247. //get the extension of the file
  248. $extension = explode('.', $filename);
  249. //$filename will be an array if a . was found
  250. if (is_array($extension)) {
  251. $extension = strtolower($extension[sizeof($extension) - 1]);
  252. }
  253. //file without extension
  254. else {
  255. $extension = 'empty';
  256. }
  257. //if the extension is found, return the content type
  258. if (isset($mime_types[$extension])) {
  259. return $mime_types[$extension];
  260. }
  261. //else return octet-stream
  262. return 'application/octet-stream';
  263. }
  264. /**
  265. * @param string
  266. * @param string
  267. * @return true if the user is allowed to see the document, false otherwise
  268. * @author Sergio A Kessler, first version
  269. * @author Roan Embrechts, bugfix
  270. * @todo not only check if a file is visible, but also check if the user is allowed to see the file??
  271. */
  272. public static function file_visible_to_user($this_course, $doc_url)
  273. {
  274. $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
  275. if ($is_allowed_to_edit) {
  276. return true;
  277. } else {
  278. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  279. $tbl_item_property = $this_course . 'item_property';
  280. $doc_url = Database::escape_string($doc_url);
  281. $query = "SELECT 1 FROM $tbl_document AS docs,$tbl_item_property AS props
  282. WHERE props.tool = 'document' AND docs.id=props.ref AND props.visibility <> '1' AND docs.path = '$doc_url'";
  283. $result = Database::query($query);
  284. return (Database::num_rows($result) == 0);
  285. }
  286. }
  287. /**
  288. * This function streams a file to the client
  289. *
  290. * @param string $full_file_name
  291. * @param boolean $forced
  292. * @param string $name
  293. * @return false if file doesn't exist, true if stream succeeded
  294. */
  295. public static function file_send_for_download($full_file_name, $forced = false, $name = '')
  296. {
  297. if (!is_file($full_file_name)) {
  298. return false;
  299. }
  300. $filename = ($name == '') ? basename($full_file_name) : replace_dangerous_char($name);
  301. $len = filesize($full_file_name);
  302. // Fixing error when file name contains a ","
  303. $filename = str_replace(',', '', $filename);
  304. if ($forced) {
  305. // Force the browser to save the file instead of opening it
  306. global $_configuration;
  307. if (isset($_configuration['enable_x_sendfile_headers']) && !empty($_configuration['enable_x_sendfile_headers'])) {
  308. header("X-Sendfile: $filename");
  309. }
  310. header('Content-type: application/octet-stream');
  311. header('Content-length: ' . $len);
  312. if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
  313. header('Content-Disposition: filename= ' . $filename);
  314. } else {
  315. header('Content-Disposition: attachment; filename= ' . $filename);
  316. }
  317. if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
  318. header('Pragma: ');
  319. header('Cache-Control: ');
  320. header('Cache-Control: public'); // IE cannot download from sessions without a cache
  321. }
  322. header('Content-Description: ' . $filename);
  323. header('Content-transfer-encoding: binary');
  324. $res = fopen($full_file_name, 'r');
  325. fpassthru($res);
  326. return true;
  327. } else {
  328. //no forced download, just let the browser decide what to do according to the mimetype
  329. $content_type = self::file_get_mime_type($filename);
  330. header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
  331. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  332. // Commented to avoid double caching declaration when playing with IE and HTTPS
  333. //header('Cache-Control: no-cache, must-revalidate');
  334. //header('Pragma: no-cache');
  335. switch ($content_type) {
  336. case 'text/html':
  337. $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
  338. if (!empty($encoding)) {
  339. $content_type .= '; charset=' . $encoding;
  340. }
  341. break;
  342. case 'text/plain':
  343. $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
  344. if (!empty($encoding)) {
  345. $content_type .= '; charset=' . $encoding;
  346. }
  347. break;
  348. case 'application/vnd.dwg':
  349. case 'application/vnd.dwf':
  350. header('Content-type: application/octet-stream');
  351. break;
  352. }
  353. header('Content-type: ' . $content_type);
  354. header('Content-Length: ' . $len);
  355. $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
  356. if (strpos($user_agent, 'msie')) {
  357. header('Content-Disposition: ; filename= ' . $filename);
  358. } else {
  359. header('Content-Disposition: inline; filename= ' . $filename);
  360. }
  361. readfile($full_file_name);
  362. return true;
  363. }
  364. }
  365. /**
  366. * This function streams a string to the client for download.
  367. * You have to ensure that the calling script then stops processing (exit();)
  368. * otherwise it may cause subsequent use of the page to want to download
  369. * other pages in php rather than interpreting them.
  370. *
  371. * @param string The string contents
  372. * @param boolean Whether "save" mode is forced (or opening directly authorized)
  373. * @param string The name of the file in the end (including extension)
  374. * @return false if file doesn't exist, true if stream succeeded
  375. */
  376. public static function string_send_for_download($full_string, $forced = false, $name = '')
  377. {
  378. $filename = $name;
  379. $len = strlen($full_string);
  380. if ($forced) {
  381. //force the browser to save the file instead of opening it
  382. header('Content-type: application/octet-stream');
  383. //header('Content-Type: application/force-download');
  384. header('Content-length: ' . $len);
  385. if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
  386. header('Content-Disposition: filename= ' . $filename);
  387. } else {
  388. header('Content-Disposition: attachment; filename= ' . $filename);
  389. }
  390. if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
  391. header('Pragma: ');
  392. header('Cache-Control: ');
  393. header('Cache-Control: public'); // IE cannot download from sessions without a cache
  394. }
  395. header('Content-Description: ' . $filename);
  396. header('Content-transfer-encoding: binary');
  397. //$fp = fopen($full_string, 'r');
  398. //fpassthru($fp);
  399. echo $full_string;
  400. return true;
  401. //You have to ensure that the calling script then stops processing (exit();)
  402. //otherwise it may cause subsequent use of the page to want to download
  403. //other pages in php rather than interpreting them.
  404. } else {
  405. //no forced download, just let the browser decide what to do according to the mimetype
  406. $content_type = self::file_get_mime_type($filename);
  407. header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
  408. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  409. header('Cache-Control: no-cache, must-revalidate');
  410. header('Pragma: no-cache');
  411. switch ($content_type) {
  412. case 'text/html':
  413. $encoding = @api_detect_encoding_html($full_string);
  414. if (!empty($encoding)) {
  415. $content_type .= '; charset=' . $encoding;
  416. }
  417. break;
  418. case 'text/plain':
  419. $encoding = @api_detect_encoding(strip_tags($full_string));
  420. if (!empty($encoding)) {
  421. $content_type .= '; charset=' . $encoding;
  422. }
  423. break;
  424. }
  425. header('Content-type: ' . $content_type);
  426. header('Content-Length: ' . $len);
  427. $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
  428. if (strpos($user_agent, 'msie')) {
  429. header('Content-Disposition: ; filename= ' . $filename);
  430. } else {
  431. header('Content-Disposition: inline; filename= ' . $filename);
  432. }
  433. echo($full_string);
  434. //You have to ensure that the calling script then stops processing (exit();)
  435. //otherwise it may cause subsequent use of the page to want to download
  436. //other pages in php rather than interpreting them.
  437. return true;
  438. }
  439. }
  440. /**
  441. * Fetches all document data for the given user/group
  442. *
  443. * @param array $_course
  444. * @param string $path
  445. * @param int $to_group_id
  446. * @param int $to_user_id
  447. * @param boolean $can_see_invisible
  448. * @param boolean $search
  449. * @return array with all document data
  450. */
  451. public static function get_all_document_data(
  452. $_course,
  453. $path = '/',
  454. $to_group_id = 0,
  455. $to_user_id = null,
  456. $can_see_invisible = false,
  457. $search = false
  458. ) {
  459. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  460. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  461. if (!is_null($to_user_id)) {
  462. $to_field = 'last.to_user_id';
  463. $to_value = $to_user_id;
  464. } else {
  465. $to_field = 'last.to_group_id';
  466. $to_value = $to_group_id;
  467. }
  468. // Escape underscores in the path so they don't act as a wildcard
  469. $path = Database::escape_string(str_replace('_', '\_', $path));
  470. $to_user_id = Database::escape_string($to_user_id);
  471. $to_value = Database::escape_string($to_value);
  472. $visibility_bit = ' <> 2';
  473. // The given path will not end with a slash, unless it's the root '/'
  474. // so no root -> add slash
  475. $added_slash = ($path == '/') ? '' : '/';
  476. // Condition for the session
  477. $current_session_id = api_get_session_id();
  478. $condition_session = " AND (id_session = '$current_session_id' OR (id_session = '0') )";
  479. // Condition for search (get ALL folders and documents)
  480. $sql = "SELECT
  481. docs.id,
  482. docs.filetype,
  483. docs.path,
  484. docs.title,
  485. docs.comment,
  486. docs.size,
  487. docs.readonly,
  488. docs.session_id,
  489. last.id_session item_property_session_id,
  490. last.lastedit_date,
  491. last.visibility,
  492. last.insert_user_id
  493. FROM $TABLE_ITEMPROPERTY AS last
  494. INNER JOIN $TABLE_DOCUMENT AS docs
  495. ON (
  496. docs.id = last.ref AND last.tool = '".TOOL_DOCUMENT."' AND
  497. docs.c_id = {$_course['real_id']} AND
  498. last.c_id = {$_course['real_id']}
  499. )
  500. WHERE
  501. docs.path LIKE '" . $path . $added_slash . "%' AND
  502. docs.path NOT LIKE '" . $path . $added_slash . "%/%' AND
  503. $to_field = $to_value AND
  504. last.visibility
  505. $visibility_bit
  506. $condition_session
  507. ";
  508. $result = Database::query($sql);
  509. $doc_list = array();
  510. $document_data = array();
  511. $is_allowed_to_edit = api_is_allowed_to_edit(null, true);
  512. if ($result !== false && Database::num_rows($result) != 0) {
  513. while ($row = Database::fetch_array($result, 'ASSOC')) {
  514. if (api_is_coach()) {
  515. // Looking for course items that are invisible to hide it in the session
  516. if (in_array($row['id'], array_keys($doc_list))) {
  517. if ($doc_list[$row['id']]['item_property_session_id'] == 0 &&
  518. $doc_list[$row['id']]['session_id'] == 0
  519. ) {
  520. if ($doc_list[$row['id']]['visibility'] == 0) {
  521. unset($document_data[$row['id']]);
  522. continue;
  523. }
  524. }
  525. }
  526. $doc_list[$row['id']] = $row;
  527. }
  528. if (!api_is_coach() && !$is_allowed_to_edit) {
  529. $doc_list[] = $row;
  530. }
  531. if ($row['filetype'] == 'file' && pathinfo($row['path'], PATHINFO_EXTENSION) == 'html') {
  532. // Templates management
  533. $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
  534. $sql = "SELECT id FROM $table_template
  535. WHERE
  536. course_code = '" . $_course['code'] . "' AND
  537. user_id = '".api_get_user_id()."' AND
  538. ref_doc = '".$row['id']."'";
  539. $template_result = Database::query($sql);
  540. $row['is_template'] = (Database::num_rows($template_result) > 0) ? 1 : 0;
  541. }
  542. // Just filling $document_data.
  543. $document_data[$row['id']] = $row;
  544. }
  545. // Only for the student we filter the results see BT#1652
  546. if (!api_is_coach() && !$is_allowed_to_edit) {
  547. $ids_to_remove = array();
  548. $my_repeat_ids = $temp = array();
  549. // Selecting repeated ids
  550. foreach ($doc_list as $row) {
  551. if (in_array($row['id'], array_keys($temp))) {
  552. $my_repeat_ids[] = $row['id'];
  553. }
  554. $temp[$row['id']] = $row;
  555. }
  556. //@todo use the DocumentManager::is_visible function
  557. // Checking disponibility in a session
  558. foreach ($my_repeat_ids as $id) {
  559. foreach ($doc_list as $row) {
  560. if ($id == $row['id']) {
  561. if ($row['visibility'] == 0 && $row['item_property_session_id'] == 0) {
  562. $delete_repeated[$id] = true;
  563. }
  564. if ($row['visibility'] == 0 && $row['item_property_session_id'] != 0) {
  565. $delete_repeated[$id] = true;
  566. }
  567. }
  568. }
  569. }
  570. foreach ($doc_list as $key => $row) {
  571. if (in_array($row['visibility'], array('0', '2')) && !in_array($row['id'], $my_repeat_ids)) {
  572. $ids_to_remove[] = $row['id'];
  573. unset($doc_list[$key]);
  574. }
  575. }
  576. foreach ($document_data as $row) {
  577. if (in_array($row['id'], $ids_to_remove)) {
  578. unset($document_data[$row['id']]);
  579. }
  580. if (isset($delete_repeated[$row['id']]) && $delete_repeated[$row['id']]) {
  581. unset($document_data[$row['id']]);
  582. }
  583. }
  584. // Checking parents visibility
  585. $final_document_data = array();
  586. foreach ($document_data as $row) {
  587. $is_visible = DocumentManager::check_visibility_tree(
  588. $row['id'],
  589. $_course['code'],
  590. $current_session_id,
  591. api_get_user_id(),
  592. $to_group_id
  593. );
  594. if ($is_visible) {
  595. $final_document_data[$row['id']] = $row;
  596. }
  597. }
  598. } else {
  599. $final_document_data = $document_data;
  600. }
  601. return $final_document_data;
  602. } else {
  603. return false;
  604. }
  605. }
  606. /**
  607. * Gets the paths of all folders in a course
  608. * can show all folders (except for the deleted ones) or only visible ones
  609. * @param array $_course
  610. * @param int $to_group_id
  611. * @param boolean $can_see_invisible
  612. *
  613. * @return array with paths
  614. */
  615. public static function get_all_document_folders(
  616. $_course,
  617. $to_group_id = '0',
  618. $can_see_invisible = false
  619. ) {
  620. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  621. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  622. $to_group_id = intval($to_group_id);
  623. $document_folders = array();
  624. if ($can_see_invisible) {
  625. //condition for the session
  626. $session_id = api_get_session_id();
  627. $condition_session = api_get_session_condition($session_id);
  628. $show_users_condition = "";
  629. if (api_get_setting('show_users_folders') == 'false') {
  630. $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
  631. }
  632. if ($to_group_id <> 0) {
  633. $sql = "SELECT DISTINCT docs.id, path
  634. FROM $TABLE_ITEMPROPERTY AS last INNER JOIN $TABLE_DOCUMENT AS docs
  635. ON (
  636. docs.id = last.ref AND
  637. last.tool = '" . TOOL_DOCUMENT . "' AND
  638. last.c_id = {$_course['real_id']} AND
  639. docs.c_id = {$_course['real_id']}
  640. )
  641. WHERE
  642. docs.filetype = 'folder' AND
  643. last.to_group_id = " . $to_group_id . " AND
  644. docs.path NOT LIKE '%shared_folder%' AND
  645. last.visibility <> 2 $condition_session ";
  646. } else {
  647. $sql = "SELECT DISTINCT docs.id, path
  648. FROM $TABLE_ITEMPROPERTY AS last INNER JOIN $TABLE_DOCUMENT AS docs
  649. ON (
  650. docs.id = last.ref AND
  651. last.tool = '" . TOOL_DOCUMENT . "' AND
  652. last.c_id = {$_course['real_id']} AND
  653. docs.c_id = {$_course['real_id']}
  654. )
  655. WHERE
  656. docs.filetype = 'folder' AND
  657. last.to_group_id = 0 AND
  658. last.visibility <> 2
  659. $show_users_condition $condition_session ";
  660. }
  661. $result = Database::query($sql);
  662. if ($result && Database::num_rows($result) != 0) {
  663. while ($row = Database::fetch_array($result, 'ASSOC')) {
  664. if (DocumentManager::is_folder_to_avoid($row['path'])) {
  665. continue;
  666. }
  667. $document_folders[$row['id']] = $row['path'];
  668. }
  669. if (!empty($document_folders)) {
  670. natsort($document_folders);
  671. }
  672. return $document_folders;
  673. } else {
  674. return false;
  675. }
  676. } else {
  677. // No invisible folders
  678. // Condition for the session
  679. $session_id = api_get_session_id();
  680. $condition_session = api_get_session_condition($session_id);
  681. //get visible folders
  682. $sql = "SELECT DISTINCT docs.id, path
  683. FROM
  684. $TABLE_ITEMPROPERTY AS last, $TABLE_DOCUMENT AS docs
  685. WHERE
  686. docs.id = last.ref AND
  687. docs.filetype = 'folder' AND
  688. last.tool = '" . TOOL_DOCUMENT . "' AND
  689. last.to_group_id = " . $to_group_id . " AND
  690. last.visibility = 1 $condition_session AND
  691. last.c_id = {$_course['real_id']} AND
  692. docs.c_id = {$_course['real_id']} ";
  693. $result = Database::query($sql);
  694. $visibleFolders = array();
  695. while ($row = Database::fetch_array($result, 'ASSOC')) {
  696. $visibleFolders[$row['id']] = $row['path'];
  697. }
  698. //condition for the session
  699. $session_id = api_get_session_id();
  700. $condition_session = api_get_session_condition($session_id);
  701. //get invisible folders
  702. $sql = "SELECT DISTINCT docs.id, path
  703. FROM $TABLE_ITEMPROPERTY AS last, $TABLE_DOCUMENT AS docs
  704. WHERE
  705. docs.id = last.ref AND
  706. docs.filetype = 'folder' AND
  707. last.tool = '" . TOOL_DOCUMENT . "' AND
  708. last.to_group_id = " . $to_group_id . " AND
  709. last.visibility = 0 $condition_session AND
  710. last.c_id = {$_course['real_id']} AND
  711. docs.c_id = {$_course['real_id']} ";
  712. $result = Database::query($sql);
  713. $invisibleFolders = array();
  714. while ($row = Database::fetch_array($result, 'ASSOC')) {
  715. //condition for the session
  716. $session_id = api_get_session_id();
  717. $condition_session = api_get_session_condition($session_id);
  718. //get visible folders in the invisible ones -> they are invisible too
  719. $sql = "SELECT DISTINCT docs.id, path
  720. FROM $TABLE_ITEMPROPERTY AS last, $TABLE_DOCUMENT AS docs
  721. WHERE
  722. docs.id = last.ref AND
  723. docs.path LIKE '" . Database::escape_string($row['path']) . "/%' AND
  724. docs.filetype = 'folder' AND
  725. last.tool = '" . TOOL_DOCUMENT . "' AND
  726. last.to_group_id = " . $to_group_id . " AND
  727. last.visibility = 1 $condition_session AND
  728. last.c_id = {$_course['real_id']} AND
  729. docs.c_id = {$_course['real_id']} ";
  730. $folder_in_invisible_result = Database::query($sql);
  731. while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
  732. $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
  733. }
  734. }
  735. //if both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
  736. if (is_array($visibleFolders) && is_array($invisibleFolders)) {
  737. $document_folders = array_diff($visibleFolders, $invisibleFolders);
  738. natsort($document_folders);
  739. return $document_folders;
  740. } elseif (is_array($visibleFolders)) {
  741. natsort($visibleFolders);
  742. return $visibleFolders;
  743. } else {
  744. //no visible folders found
  745. return false;
  746. }
  747. }
  748. }
  749. /**
  750. * This check if a document has the readonly property checked, then see if the user
  751. * is the owner of this file, if all this is true then return true.
  752. *
  753. * @param array $_course
  754. * @param int $user_id id of the current user
  755. * @param string $file path stored in the database (if not defined, $documentId must be used)
  756. * @param int $document_id in case you dont have the file path ,insert the id of the file here and leave $file in blank ''
  757. * @param bool $to_delete
  758. * @param int $sessionId
  759. * @return boolean true/false
  760. * */
  761. public static function check_readonly(
  762. $_course,
  763. $user_id,
  764. $file = null,
  765. $document_id = '',
  766. $to_delete = false,
  767. $sessionId = null,
  768. $documentId = null
  769. ) {
  770. if (empty($sessionId)) {
  771. $sessionId = api_get_session_id();
  772. } else {
  773. $sessionId = intval($sessionId);
  774. }
  775. if (empty($document_id) || !is_numeric($document_id)) {
  776. $document_id = self::get_document_id($_course, $file, $sessionId);
  777. } else {
  778. $document_id = intval($document_id);
  779. }
  780. $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  781. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  782. $course_id = $_course['real_id'];
  783. if ($to_delete) {
  784. if (self::is_folder($_course, $document_id)) {
  785. if (!empty($file)) {
  786. $path = Database::escape_string($file);
  787. $what_to_check_sql = "SELECT td.id, readonly, tp.insert_user_id
  788. FROM $TABLE_DOCUMENT td , $TABLE_PROPERTY tp
  789. WHERE td.c_id = $course_id AND
  790. tp.c_id = $course_id AND
  791. td.session_id = $sessionId AND
  792. tp.ref= td.id AND
  793. (path='" . $path . "' OR path LIKE BINARY '" . $path . "/%' ) ";
  794. // Get all id's of documents that are deleted
  795. $what_to_check_result = Database::query($what_to_check_sql);
  796. if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
  797. // file with readonly set to 1 exist?
  798. $readonly_set = false;
  799. while ($row = Database::fetch_array($what_to_check_result)) {
  800. //query to delete from item_property table
  801. if ($row['readonly'] == 1) {
  802. if (!($row['insert_user_id'] == $user_id)) {
  803. $readonly_set = true;
  804. break;
  805. }
  806. }
  807. }
  808. if ($readonly_set) {
  809. return true;
  810. }
  811. }
  812. }
  813. return false;
  814. }
  815. }
  816. if (!empty($document_id)) {
  817. $sql = "SELECT a.insert_user_id, b.readonly
  818. FROM $TABLE_PROPERTY a, $TABLE_DOCUMENT b
  819. WHERE
  820. a.c_id = $course_id AND
  821. b.c_id = $course_id AND
  822. a.ref = b.id and a.ref = $document_id LIMIT 1";
  823. $result = Database::query($sql);
  824. $doc_details = Database ::fetch_array($result, 'ASSOC');
  825. if ($doc_details['readonly'] == 1) {
  826. return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
  827. }
  828. }
  829. return false;
  830. }
  831. /**
  832. * This check if a document is a folder or not
  833. * @param array $_course
  834. * @param int $document_id of the item
  835. * @return boolean true/false
  836. * */
  837. public static function is_folder($_course, $document_id)
  838. {
  839. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  840. $course_id = $_course['real_id'];
  841. $document_id = Database::escape_string($document_id);
  842. $sql = "SELECT filetype FROM $TABLE_DOCUMENT WHERE c_id = $course_id AND id= $document_id";
  843. $result = Database::fetch_array(Database::query($sql), 'ASSOC');
  844. return $result['filetype'] == 'folder';
  845. }
  846. /**
  847. * @param int $document_id
  848. * @param array $course_info
  849. * @param int $session_id
  850. * @param bool $remove_content_from_db
  851. */
  852. public static function deleteDocumentFromDb(
  853. $document_id,
  854. $course_info = array(),
  855. $session_id = 0,
  856. $remove_content_from_db = false
  857. ) {
  858. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  859. $TABLE_ITEMPROPERTY = Database :: get_course_table(TABLE_ITEM_PROPERTY);
  860. // Deleting from the DB
  861. $user_id = api_get_user_id();
  862. $document_id = intval($document_id);
  863. if (empty($course_info)) {
  864. $course_info = api_get_course_info();
  865. }
  866. if (empty($session_id)) {
  867. $session_id = api_get_session_id();
  868. }
  869. // Soft DB delete
  870. api_item_property_update(
  871. $course_info,
  872. TOOL_DOCUMENT,
  873. $document_id,
  874. 'delete',
  875. $user_id,
  876. null,
  877. null,
  878. null,
  879. null,
  880. $session_id
  881. );
  882. self::delete_document_from_search_engine($course_info['code'], $document_id);
  883. self::unset_document_as_template($document_id, $course_info['code'], $user_id);
  884. //Hard DB delete
  885. if ($remove_content_from_db) {
  886. $sql = "DELETE FROM $TABLE_ITEMPROPERTY
  887. WHERE
  888. c_id = {$course_info['real_id']} AND
  889. ref = ".$document_id." AND
  890. tool='".TOOL_DOCUMENT."'";
  891. Database::query($sql);
  892. $sql = "DELETE FROM $TABLE_DOCUMENT
  893. WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
  894. Database::query($sql);
  895. self::delete_document_metadata($document_id);
  896. }
  897. }
  898. /**
  899. * @param int $document_id
  900. */
  901. public static function delete_document_metadata($document_id)
  902. {
  903. //needed to deleted medadata
  904. require_once api_get_path(SYS_CODE_PATH) . 'metadata/md_funcs.php';
  905. require_once api_get_path(LIBRARY_PATH) . 'fileManage.lib.php';
  906. $mdStore = new mdstore(true);
  907. //delete metadata
  908. $eid = 'Document' . '.' . $document_id;
  909. $mdStore->mds_delete($eid);
  910. $mdStore->mds_delete_offspring($eid);
  911. }
  912. /**
  913. * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
  914. * Files/folders that are inside a deleted folder get visibility 2
  915. *
  916. * @param array $_course
  917. * @param string $path, path stored in the database
  918. * @param string $base_work_dir, path to the documents folder (if not defined, $documentId must be used)
  919. * @param int $sessionId The ID of the session, if any
  920. * @param int $documentId The document id, if available
  921. * @return boolean true/false
  922. * @todo now only files/folders in a folder get visibility 2, we should rename them too.
  923. * @todo We should be able to get rid of this later when using only documentId (check further usage)
  924. */
  925. public static function delete_document(
  926. $_course,
  927. $path = null,
  928. $base_work_dir,
  929. $sessionId = null,
  930. $documentId = null,
  931. $groupId = null
  932. ) {
  933. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  934. if (empty($groupId)) {
  935. $groupId = api_get_group_id();
  936. } else {
  937. $groupId = intval($groupId);
  938. }
  939. if (empty($sessionId)) {
  940. $sessionId = api_get_session_id();
  941. } else {
  942. $sessionId = intval($sessionId);
  943. }
  944. $course_id = $_course['real_id'];
  945. if (empty($course_id)) {
  946. return false;
  947. }
  948. if (empty($base_work_dir)) {
  949. return false;
  950. }
  951. if (empty($documentId)) {
  952. $documentId = self::get_document_id($_course, $path, $sessionId);
  953. $docInfo = self::get_document_data_by_id(
  954. $documentId,
  955. $_course['code'],
  956. false,
  957. $sessionId
  958. );
  959. $path = $docInfo['path'];
  960. } else {
  961. $docInfo = self::get_document_data_by_id(
  962. $documentId,
  963. $_course['code'],
  964. false,
  965. $sessionId
  966. );
  967. if (empty($docInfo)) {
  968. return false;
  969. }
  970. $path = $docInfo['path'];
  971. }
  972. $documentId = intval($documentId);
  973. if (empty($path) || empty($docInfo) || empty($documentId)) {
  974. return false;
  975. }
  976. $itemInfo = api_get_item_property_info($_course['real_id'], TOOL_DOCUMENT, $documentId, 0);
  977. if (empty($itemInfo)) {
  978. return false;
  979. }
  980. // File was already deleted.
  981. if ($itemInfo['lastedit_type'] == 'DocumentDeleted' ||
  982. $itemInfo['lastedit_type'] == 'delete' ||
  983. $itemInfo['visibility'] == 2
  984. ) {
  985. return false;
  986. }
  987. // Filtering by group.
  988. if ($itemInfo['to_group_id'] != $groupId) {
  989. return false;
  990. }
  991. $document_exists_in_disk = file_exists($base_work_dir.$path);
  992. $new_path = $path.'_DELETED_'.$documentId;
  993. $file_deleted_from_db = false;
  994. $file_deleted_from_disk = false;
  995. $file_renamed_from_disk = false;
  996. if ($documentId) {
  997. // Deleting doc from the DB.
  998. self::deleteDocumentFromDb($documentId, $_course, $sessionId);
  999. // Checking
  1000. // $file_exists_in_db = self::get_document_data_by_id($documentId, $_course['code']);
  1001. $file_deleted_from_db = true;
  1002. }
  1003. // Looking for children.
  1004. if ($docInfo['filetype'] == 'folder') {
  1005. $cleanPath = Database::escape_string($path);
  1006. // Deleted files inside this folder.
  1007. $sql = "SELECT id FROM $TABLE_DOCUMENT
  1008. WHERE
  1009. c_id = $course_id AND
  1010. session_id = $sessionId AND
  1011. path LIKE BINARY '".$cleanPath."/%'";
  1012. // Get all id's of documents that are deleted.
  1013. $result = Database::query($sql);
  1014. if ($result && Database::num_rows($result) != 0) {
  1015. // Recursive delete.
  1016. while ($row = Database::fetch_array($result)) {
  1017. self::delete_document(
  1018. $_course,
  1019. null,
  1020. $base_work_dir,
  1021. $sessionId,
  1022. $row['id']
  1023. );
  1024. }
  1025. }
  1026. }
  1027. if ($document_exists_in_disk) {
  1028. if (api_get_setting('permanently_remove_deleted_files') == 'true') {
  1029. // Delete documents, do it like this so metadata gets deleted too
  1030. my_delete($base_work_dir.$path);
  1031. // Hard delete.
  1032. self::deleteDocumentFromDb($documentId, $_course, $sessionId, true);
  1033. $file_deleted_from_disk = true;
  1034. } else {
  1035. // Set visibility to 2 and rename file/folder to xxx_DELETED_#id (soft delete)
  1036. if (is_file($base_work_dir.$path) || is_dir($base_work_dir.$path)) {
  1037. if (rename($base_work_dir.$path, $base_work_dir.$new_path)) {
  1038. $new_path = Database::escape_string($new_path);
  1039. $sql = "UPDATE $TABLE_DOCUMENT
  1040. SET path = '".$new_path."'
  1041. WHERE
  1042. c_id = $course_id AND
  1043. session_id = $sessionId AND
  1044. id = ".$documentId;
  1045. Database::query($sql);
  1046. // Soft delete.
  1047. self::deleteDocumentFromDb($documentId, $_course, $sessionId);
  1048. // Change path of sub folders and documents in database.
  1049. $old_item_path = $docInfo['path'];
  1050. $new_item_path = $new_path.substr($old_item_path, strlen($path));
  1051. $new_item_path = Database::escape_string($new_item_path);
  1052. $sql = "UPDATE $TABLE_DOCUMENT
  1053. SET path = '".$new_item_path."'
  1054. WHERE
  1055. c_id = $course_id AND
  1056. session_id = $sessionId AND
  1057. id = ".$documentId;
  1058. Database::query($sql);
  1059. $file_renamed_from_disk = true;
  1060. } else {
  1061. // Couldn't rename - file permissions problem?
  1062. error_log(
  1063. __FILE__.' '.__LINE__.': Error renaming '.$base_work_dir.$path.' to '.$base_work_dir.$new_path.'. This is probably due to file permissions',
  1064. 0
  1065. );
  1066. }
  1067. }
  1068. }
  1069. }
  1070. // Checking inconsistency
  1071. //error_log('Doc status: (1 del db :'.($file_deleted_from_db?'yes':'no').') - (2 del disk: '.($file_deleted_from_disk?'yes':'no').') - (3 ren disk: '.($file_renamed_from_disk?'yes':'no').')');
  1072. if ($file_deleted_from_db && $file_deleted_from_disk ||
  1073. $file_deleted_from_db && $file_renamed_from_disk
  1074. ) {
  1075. return true;
  1076. } else {
  1077. //Something went wrong
  1078. //The file or directory isn't there anymore (on the filesystem)
  1079. // This means it has been removed externally. To prevent a
  1080. // blocking error from happening, we drop the related items from the
  1081. // item_property and the document table.
  1082. error_log(
  1083. __FILE__.' '.__LINE__.': System inconsistency detected. The file or directory '.$base_work_dir.$path.' seems to have been removed from the filesystem independently from the web platform. To restore consistency, the elements using the same path will be removed from the database',
  1084. 0
  1085. );
  1086. return false;
  1087. }
  1088. }
  1089. /**
  1090. * Removes documents from search engine database
  1091. *
  1092. * @param string $course_id Course code
  1093. * @param int $document_id Document id to delete
  1094. */
  1095. public static function delete_document_from_search_engine($course_id, $document_id)
  1096. {
  1097. // remove from search engine if enabled
  1098. if (api_get_setting('search_enabled') == 'true') {
  1099. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  1100. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  1101. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
  1102. $res = Database::query($sql);
  1103. if (Database::num_rows($res) > 0) {
  1104. $row2 = Database::fetch_array($res);
  1105. require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
  1106. $di = new ChamiloIndexer();
  1107. $di->remove_document((int) $row2['search_did']);
  1108. }
  1109. $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  1110. $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
  1111. Database::query($sql);
  1112. // remove terms from db
  1113. require_once api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php';
  1114. delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
  1115. }
  1116. }
  1117. /**
  1118. * Gets the id of a document with a given path
  1119. *
  1120. * @param array $courseInfo
  1121. * @param string $path
  1122. * @param int $sessionId
  1123. * @return int id of document / false if no doc found
  1124. */
  1125. public static function get_document_id($courseInfo, $path, $sessionId = null)
  1126. {
  1127. $TABLE_DOCUMENT = Database :: get_course_table(TABLE_DOCUMENT);
  1128. $course_id = $courseInfo['real_id'];
  1129. if (!isset($sessionId)) {
  1130. $sessionId = api_get_session_id();
  1131. } else {
  1132. $sessionId = intval($sessionId);
  1133. }
  1134. $path = Database::escape_string($path);
  1135. if (!empty($course_id) && !empty($path)) {
  1136. $sql = "SELECT id FROM $TABLE_DOCUMENT
  1137. WHERE
  1138. c_id = $course_id AND
  1139. path LIKE BINARY '$path' AND
  1140. session_id = $sessionId
  1141. LIMIT 1";
  1142. $result = Database::query($sql);
  1143. if ($result && Database::num_rows($result)) {
  1144. $row = Database::fetch_array($result);
  1145. return intval($row[0]);
  1146. }
  1147. }
  1148. return false;
  1149. }
  1150. /**
  1151. * Gets the document data with a given id
  1152. *
  1153. * @param int $id Document ID (id field in c_document table)
  1154. * @param string $course_code course code (c_id field in document table)
  1155. * @param bool $load_parents load parents?
  1156. * @param int $session_id The session ID, 0 if requires context *out of* session, and null to use global context
  1157. * @return array document content
  1158. */
  1159. public static function get_document_data_by_id($id, $course_code, $load_parents = false, $session_id = null)
  1160. {
  1161. $course_info = api_get_course_info($course_code);
  1162. $course_id = $course_info['real_id'];
  1163. if (empty($course_info)) {
  1164. return false;
  1165. }
  1166. if (isset($session_id)) {
  1167. $session_id = intval($session_id);
  1168. } else {
  1169. $session_id = api_get_session_id();
  1170. }
  1171. $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
  1172. $TABLE_DOCUMENT = Database :: get_course_table(TABLE_DOCUMENT);
  1173. $id = intval($id);
  1174. $sql = "SELECT * FROM $TABLE_DOCUMENT
  1175. WHERE c_id = $course_id AND session_id = $session_id AND id = $id";
  1176. $result = Database::query($sql);
  1177. if ($result && Database::num_rows($result) == 1) {
  1178. $row = Database::fetch_array($result, 'ASSOC');
  1179. //@todo need to clarify the name of the URLs not nice right now
  1180. $url_path = urlencode($row['path']);
  1181. $path = str_replace('%2F', '/', $url_path);
  1182. $row['url'] = api_get_path(WEB_CODE_PATH) . 'document/showinframes.php?cidReq=' . $course_code . '&id=' . $id;
  1183. $row['document_url'] = api_get_path(WEB_CODE_PATH) . 'document/document.php?cidReq=' . $course_code . '&id=' . $id;
  1184. $row['absolute_path'] = api_get_path(SYS_COURSE_PATH) . $course_info['path'] . '/document' . $row['path'];
  1185. $row['absolute_path_from_document'] = '/document' . $row['path'];
  1186. $pathinfo = pathinfo($row['path']);
  1187. $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'] . '/';
  1188. $row['direct_url'] = $www . $path;
  1189. if (dirname($row['path']) == '.') {
  1190. $row['parent_id'] = '0';
  1191. } else {
  1192. $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
  1193. }
  1194. $parents = array();
  1195. //Use to generate parents (needed for the breadcrumb)
  1196. //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
  1197. if ($load_parents) {
  1198. $dir_array = explode('/', $row['path']);
  1199. $dir_array = array_filter($dir_array);
  1200. $array_len = count($dir_array) + 1;
  1201. $real_dir = '';
  1202. for ($i = 1; $i < $array_len; $i++) {
  1203. //$sub_visibility = true;
  1204. $real_dir .= '/' . $dir_array[$i];
  1205. $parent_id = self::get_document_id($course_info, $real_dir);
  1206. if ($session_id != 0 && empty($parent_id)) {
  1207. $parent_id = self::get_document_id($course_info, $real_dir, 0);
  1208. }
  1209. if (!empty($parent_id)) {
  1210. $sub_document_data = self::get_document_data_by_id($parent_id, $course_code, false, $session_id);
  1211. if ($session_id != 0 and !$sub_document_data) {
  1212. $sub_document_data = self::get_document_data_by_id($parent_id, $course_code, false, 0);
  1213. }
  1214. //@todo add visibility here
  1215. $parents[] = $sub_document_data;
  1216. }
  1217. }
  1218. }
  1219. $row['parents'] = $parents;
  1220. return $row;
  1221. }
  1222. return false;
  1223. }
  1224. /**
  1225. * Allow to set a specific document as a new template for FCKEditor for a particular user in a particular course
  1226. *
  1227. * @param string $title
  1228. * @param string $description
  1229. * @param int $document_id_for_template the document id
  1230. * @param string $course_code
  1231. * @param int $user_id
  1232. */
  1233. public static function set_document_as_template($title, $description, $document_id_for_template, $course_code, $user_id, $image)
  1234. {
  1235. // Database table definition
  1236. $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
  1237. // creating the sql statement
  1238. $sql = "INSERT INTO $table_template
  1239. (title, description, course_code, user_id, ref_doc, image)
  1240. VALUES (
  1241. '" . Database::escape_string($title) . "',
  1242. '" . Database::escape_string($description) . "',
  1243. '" . Database::escape_string($course_code) . "',
  1244. '" . Database::escape_string($user_id) . "',
  1245. '" . Database::escape_string($document_id_for_template) . "',
  1246. '" . Database::escape_string($image) . "')";
  1247. Database::query($sql);
  1248. return true;
  1249. }
  1250. /**
  1251. * Unset a document as template
  1252. *
  1253. * @param int $document_id
  1254. * @param string $couse_code
  1255. * @param int $user_id
  1256. */
  1257. public static function unset_document_as_template($document_id, $course_code, $user_id)
  1258. {
  1259. $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
  1260. $course_code = Database::escape_string($course_code);
  1261. $user_id = Database::escape_string($user_id);
  1262. $document_id = Database::escape_string($document_id);
  1263. $sql = 'SELECT id FROM ' . $table_template . ' WHERE course_code="' . $course_code . '" AND user_id="' . $user_id . '" AND ref_doc="' . $document_id . '"';
  1264. $result = Database::query($sql);
  1265. $template_id = Database::result($result, 0, 0);
  1266. include_once(api_get_path(LIBRARY_PATH) . 'fileManage.lib.php');
  1267. my_delete(api_get_path(SYS_CODE_PATH) . 'upload/template_thumbnails/' . $template_id . '.jpg');
  1268. $sql = 'DELETE FROM ' . $table_template . ' WHERE course_code="' . $course_code . '" AND user_id="' . $user_id . '" AND ref_doc="' . $document_id . '"';
  1269. Database::query($sql);
  1270. }
  1271. /**
  1272. * Return true if the documentpath have visibility=1 as item_property (you should use the is_visible_by_id)
  1273. *
  1274. * @param string $document_path the relative complete path of the document
  1275. * @param array $course the _course array info of the document's course
  1276. * @param int
  1277. * @param string
  1278. */
  1279. public static function is_visible($doc_path, $course, $session_id = 0, $file_type = 'file')
  1280. {
  1281. $docTable = Database::get_course_table(TABLE_DOCUMENT);
  1282. $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
  1283. $course_id = $course['real_id'];
  1284. //note the extra / at the end of doc_path to match every path in the document table that is part of the document path
  1285. $doc_path = Database::escape_string($doc_path);
  1286. $session_id = intval($session_id);
  1287. $condition = "AND id_session IN ('$session_id', '0') ";
  1288. // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
  1289. /*
  1290. When using hotpotatoes files, a new html files are generated
  1291. in the hotpotatoes folder to display the test.
  1292. The genuine html file is copied to math4.htm(user_id).t.html
  1293. Images files are not copied, and keep same name.
  1294. To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
  1295. In this case, we have to remove (user_id).t.html to check the visibility of the file
  1296. For images, we just check the path of the image file.
  1297. Exemple of hotpotatoes folder :
  1298. A.jpg
  1299. maths4-consigne.jpg
  1300. maths4.htm
  1301. maths4.htm1.t.html
  1302. maths4.htm52.t.html
  1303. maths4.htm654.t.html
  1304. omega.jpg
  1305. theta.jpg
  1306. */
  1307. if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
  1308. $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
  1309. }
  1310. if (!in_array($file_type, array('file', 'folder'))) {
  1311. $file_type = 'file';
  1312. }
  1313. $sql = "SELECT visibility FROM $docTable d INNER JOIN $propTable ip
  1314. ON (d.id = ip.ref AND d.c_id = $course_id AND ip.c_id = $course_id)
  1315. WHERE ip.tool = '" . TOOL_DOCUMENT . "' $condition AND
  1316. filetype = '$file_type' AND locate(concat(path,'/'),'" . $doc_path . "/')=1";
  1317. $result = Database::query($sql);
  1318. $is_visible = false;
  1319. if (Database::num_rows($result) > 0) {
  1320. $row = Database::fetch_array($result, 'ASSOC');
  1321. if ($row['visibility'] == 1) {
  1322. $is_visible = $_SESSION['is_allowed_in_course'] || api_is_platform_admin();
  1323. }
  1324. }
  1325. /* improved protection of documents viewable directly through the url:
  1326. incorporates the same protections of the course at the url of
  1327. documents:
  1328. access allowed for the whole world Open, access allowed for
  1329. users registered on the platform Private access, document accessible
  1330. only to course members (see the Users list), Completely closed;
  1331. the document is only accessible to the course admin and
  1332. teaching assistants.*/
  1333. //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
  1334. return $is_visible;
  1335. }
  1336. /**
  1337. * Return true if user can see a file
  1338. *
  1339. * @param int document id
  1340. * @param array course info
  1341. * @param int
  1342. * @param int
  1343. * @param bool
  1344. * @return bool
  1345. */
  1346. public static function is_visible_by_id($doc_id, $course_info, $session_id, $user_id, $admins_can_see_everything = true)
  1347. {
  1348. $is_visible = false;
  1349. $user_in_course = false;
  1350. //1. Checking the course array
  1351. if (empty($course_info)) {
  1352. $course_info = api_get_course_info();
  1353. if (empty($course_info)) {
  1354. return false;
  1355. }
  1356. }
  1357. $doc_id = intval($doc_id);
  1358. $session_id = intval($session_id);
  1359. //2. Course and Session visibility are handle in local.inc.php/global.inc.php
  1360. //3. Checking if user exist in course/session
  1361. if ($session_id == 0) {
  1362. if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code']) || api_is_platform_admin()) {
  1363. $user_in_course = true;
  1364. }
  1365. // Check if course is open then we can consider that the student is registered to the course
  1366. if (isset($course_info) && in_array($course_info['visibility'], array(COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD))) {
  1367. $user_in_course = true;
  1368. }
  1369. } else {
  1370. $user_status = SessionManager::get_user_status_in_course_session($user_id, $course_info['code'], $session_id);
  1371. if (in_array($user_status, array('0', '2', '6'))) {
  1372. //is true if is an student, course session teacher or coach
  1373. $user_in_course = true;
  1374. }
  1375. }
  1376. //4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
  1377. if ($user_in_course) {
  1378. //4.1 Checking document visibility for a Course
  1379. if ($session_id == 0) {
  1380. $item_info = api_get_item_property_info($course_info['real_id'], 'document', $doc_id, 0);
  1381. if (isset($item_info['visibility'])) {
  1382. // True for admins if document exists
  1383. if ($admins_can_see_everything && api_is_platform_admin()) {
  1384. return true;
  1385. }
  1386. if ($item_info['visibility'] == 1) {
  1387. return true;
  1388. }
  1389. }
  1390. } else {
  1391. //4.2 Checking document visibility for a Course in a Session
  1392. $item_info = api_get_item_property_info($course_info['real_id'], 'document', $doc_id, 0);
  1393. $item_info_in_session = api_get_item_property_info($course_info['real_id'], 'document', $doc_id, $session_id);
  1394. // True for admins if document exists
  1395. if (isset($item_info['visibility'])) {
  1396. if ($admins_can_see_everything && api_is_platform_admin())
  1397. return true;
  1398. }
  1399. if (isset($item_info_in_session['visibility'])) {
  1400. if ($item_info_in_session['visibility'] == 1) {
  1401. return true;
  1402. }
  1403. } else {
  1404. if ($item_info['visibility'] == 1) {
  1405. return true;
  1406. }
  1407. }
  1408. }
  1409. } elseif ($admins_can_see_everything && api_is_platform_admin()) {
  1410. return true;
  1411. }
  1412. return false;
  1413. }
  1414. /**
  1415. * Allow attach a certificate to a course
  1416. * @param string The course id
  1417. * @param int The document id
  1418. * @return void()
  1419. */
  1420. function attach_gradebook_certificate($course_id, $document_id)
  1421. {
  1422. $tbl_category = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1423. $session_id = api_get_session_id();
  1424. if ($session_id == 0 || is_null($session_id)) {
  1425. $sql_session = 'AND (session_id=' . Database::escape_string($session_id) . ' OR isnull(session_id)) ';
  1426. } elseif ($session_id > 0) {
  1427. $sql_session = 'AND session_id=' . Database::escape_string($session_id);
  1428. } else {
  1429. $sql_session = '';
  1430. }
  1431. $sql = 'UPDATE ' . $tbl_category . ' SET document_id="' . Database::escape_string($document_id) . '"
  1432. WHERE course_code="' . Database::escape_string($course_id) . '" ' . $sql_session;
  1433. Database::query($sql);
  1434. }
  1435. /**
  1436. * get the document id of default certificate
  1437. * @param string The course id
  1438. * @return int The default certificate id
  1439. */
  1440. static function get_default_certificate_id($course_id)
  1441. {
  1442. $tbl_category = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1443. $session_id = api_get_session_id();
  1444. if ($session_id == 0 || is_null($session_id)) {
  1445. $sql_session = 'AND (session_id=' . Database::escape_string($session_id) . ' OR isnull(session_id)) ';
  1446. } elseif ($session_id > 0) {
  1447. $sql_session = 'AND session_id=' . Database::escape_string($session_id);
  1448. } else {
  1449. $sql_session = '';
  1450. }
  1451. $sql = 'SELECT document_id FROM ' . $tbl_category . ' WHERE course_code="' . Database::escape_string($course_id) . '" ' . $sql_session;
  1452. $rs = Database::query($sql);
  1453. $num = Database::num_rows($rs);
  1454. if ($num == 0) {
  1455. return null;
  1456. }
  1457. $row = Database::fetch_array($rs);
  1458. return $row['document_id'];
  1459. }
  1460. /**
  1461. * allow replace user info in file html
  1462. * @param string The course code
  1463. * @return string The html content of the certificate
  1464. */
  1465. static function replace_user_info_into_html($user_id, $course_code, $is_preview = false)
  1466. {
  1467. $user_id = intval($user_id);
  1468. $course_info = api_get_course_info($course_code);
  1469. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1470. $course_id = $course_info['real_id'];
  1471. $document_id = self::get_default_certificate_id($course_code);
  1472. if ($document_id) {
  1473. $sql = "SELECT path FROM $tbl_document WHERE c_id = $course_id AND id = $document_id";
  1474. $rs = Database::query($sql);
  1475. $new_content = '';
  1476. $all_user_info = array();
  1477. if (Database::num_rows($rs)) {
  1478. $row = Database::fetch_array($rs);
  1479. $filepath = api_get_path(SYS_COURSE_PATH) . $course_info['path'] . '/document' . $row['path'];
  1480. if (is_file($filepath)) {
  1481. $my_content_html = file_get_contents($filepath);
  1482. }
  1483. $all_user_info = self::get_all_info_to_certificate($user_id, $course_code, $is_preview);
  1484. $info_to_be_replaced_in_content_html = $all_user_info[0];
  1485. $info_to_replace_in_content_html = $all_user_info[1];
  1486. $new_content = str_replace($info_to_be_replaced_in_content_html, $info_to_replace_in_content_html, $my_content_html);
  1487. }
  1488. return array('content' => $new_content, 'variables' => $all_user_info);
  1489. }
  1490. return array();
  1491. }
  1492. /**
  1493. * return all content to replace and all content to be replace
  1494. */
  1495. static function get_all_info_to_certificate($user_id, $course_id, $is_preview = false)
  1496. {
  1497. $info_list = array();
  1498. $user_id = intval($user_id);
  1499. $course_info = api_get_course_info($course_id);
  1500. //info portal
  1501. $organization_name = api_get_setting('Institution');
  1502. $portal_name = api_get_setting('siteName');
  1503. //Extra user data information
  1504. $extra_user_info_data = UserManager::get_extra_user_data($user_id, false, false, false, true);
  1505. //Student information
  1506. $user_info = api_get_user_info($user_id);
  1507. $first_name = $user_info['firstname'];
  1508. $last_name = $user_info['lastname'];
  1509. $official_code = $user_info['official_code'];
  1510. //Teacher information
  1511. $info_teacher_id = UserManager::get_user_id_of_course_admin_or_session_admin($course_id);
  1512. $teacher_info = api_get_user_info($info_teacher_id);
  1513. $teacher_first_name = $teacher_info['firstname'];
  1514. $teacher_last_name = $teacher_info['lastname'];
  1515. // info gradebook certificate
  1516. $info_grade_certificate = UserManager::get_info_gradebook_certificate($course_id, $user_id);
  1517. $date_certificate = $info_grade_certificate['created_at'];
  1518. $date_long_certificate = '';
  1519. $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
  1520. if (!empty($date_certificate)) {
  1521. $date_long_certificate = api_convert_and_format_date($date_certificate);
  1522. $date_no_time = api_convert_and_format_date($date_certificate, DATE_FORMAT_LONG_NO_DAY);
  1523. }
  1524. if ($is_preview) {
  1525. $date_long_certificate = api_convert_and_format_date(api_get_utc_datetime());
  1526. $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
  1527. }
  1528. $url = api_get_path(WEB_PATH) . 'certificates/index.php?id=' . $info_grade_certificate['id'];
  1529. //replace content
  1530. $info_to_replace_in_content_html = array($first_name,
  1531. $last_name,
  1532. $organization_name,
  1533. $portal_name,
  1534. $teacher_first_name,
  1535. $teacher_last_name,
  1536. $official_code,
  1537. $date_long_certificate,
  1538. $date_no_time,
  1539. $course_id,
  1540. $course_info['name'],
  1541. $info_grade_certificate['grade'],
  1542. $url,
  1543. '<a href="' . $url . '" target="_blank">' . get_lang('CertificateOnlineLink') . '</a>',
  1544. '((certificate_barcode))',
  1545. );
  1546. $info_to_be_replaced_in_content_html = array('((user_firstname))',
  1547. '((user_lastname))',
  1548. '((gradebook_institution))',
  1549. '((gradebook_sitename))',
  1550. '((teacher_firstname))',
  1551. '((teacher_lastname))',
  1552. '((official_code))',
  1553. '((date_certificate))',
  1554. '((date_certificate_no_time))',
  1555. '((course_code))',
  1556. '((course_title))',
  1557. '((gradebook_grade))',
  1558. '((certificate_link))',
  1559. '((certificate_link_html))',
  1560. '((certificate_barcode))',
  1561. );
  1562. if (!empty($extra_user_info_data)) {
  1563. foreach ($extra_user_info_data as $key_extra => $value_extra) {
  1564. $info_to_be_replaced_in_content_html[] = '((' . strtolower($key_extra) . '))';
  1565. $info_to_replace_in_content_html[] = $value_extra;
  1566. }
  1567. }
  1568. $info_list[] = $info_to_be_replaced_in_content_html;
  1569. $info_list[] = $info_to_replace_in_content_html;
  1570. return $info_list;
  1571. }
  1572. /**
  1573. * Remove default certificate
  1574. * @param string The course code
  1575. * @param int The document id of the default certificate
  1576. * @return void()
  1577. */
  1578. public static function remove_attach_certificate($course_id, $default_certificate_id)
  1579. {
  1580. if (empty($default_certificate_id)) {
  1581. return false;
  1582. }
  1583. $default_certificate = self::get_default_certificate_id($course_id);
  1584. if ((int) $default_certificate == (int) $default_certificate_id) {
  1585. $tbl_category = Database :: get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
  1586. $session_id = api_get_session_id();
  1587. if ($session_id == 0 || is_null($session_id)) {
  1588. $sql_session = 'AND (session_id=' . Database::escape_string($session_id) . ' OR isnull(session_id)) ';
  1589. } elseif ($session_id > 0) {
  1590. $sql_session = 'AND session_id=' . Database::escape_string($session_id);
  1591. } else {
  1592. $sql_session = '';
  1593. }
  1594. $sql = 'UPDATE ' . $tbl_category . ' SET document_id=null
  1595. WHERE
  1596. course_code = "' . Database::escape_string($course_id) . '" AND
  1597. document_id="' . $default_certificate_id . '" ' . $sql_session;
  1598. Database::query($sql);
  1599. }
  1600. }
  1601. /**
  1602. * Create directory certificate
  1603. * @param string The course code
  1604. * @return void()
  1605. */
  1606. public static function create_directory_certificate_in_course($course_id)
  1607. {
  1608. $course_info = api_get_course_info($course_id);
  1609. if (!empty($course_info)) {
  1610. $to_group_id = 0;
  1611. $to_user_id = null;
  1612. $course_dir = $course_info['path'] . "/document/";
  1613. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  1614. $base_work_dir = $sys_course_path . $course_dir;
  1615. $base_work_dir_test = $base_work_dir . 'certificates';
  1616. $dir_name = '/certificates';
  1617. $post_dir_name = get_lang('CertificatesFiles');
  1618. $visibility_command = 'invisible';
  1619. if (!is_dir($base_work_dir_test)) {
  1620. $created_dir = create_unexisting_directory(
  1621. $course_info,
  1622. api_get_user_id(),
  1623. api_get_session_id(),
  1624. $to_group_id,
  1625. $to_user_id,
  1626. $base_work_dir,
  1627. $dir_name,
  1628. $post_dir_name
  1629. );
  1630. $update_id = self::get_document_id_of_directory_certificate();
  1631. api_item_property_update($course_info, TOOL_DOCUMENT, $update_id, $visibility_command, api_get_user_id());
  1632. }
  1633. }
  1634. }
  1635. /**
  1636. * Get the document id of the directory certificate
  1637. * @param string The course id
  1638. * @return int The document id of the directory certificate
  1639. */
  1640. public static function get_document_id_of_directory_certificate()
  1641. {
  1642. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1643. $course_id = api_get_course_int_id();
  1644. $sql = "SELECT id FROM $tbl_document WHERE c_id = $course_id AND path='/certificates' ";
  1645. $rs = Database::query($sql);
  1646. $row = Database::fetch_array($rs);
  1647. return $row['id'];
  1648. }
  1649. /**
  1650. * Check if a directory given is for certificate
  1651. * @param string path of directory
  1652. * @return bool true if is a certificate or false otherwise
  1653. */
  1654. public static function is_certificate_mode($dir)
  1655. {
  1656. // I'm in the certification module?
  1657. $is_certificate_mode = false;
  1658. $is_certificate_array = explode('/', $dir);
  1659. array_shift($is_certificate_array);
  1660. if (isset($is_certificate_array[0]) && $is_certificate_array[0] == 'certificates') {
  1661. $is_certificate_mode = true;
  1662. }
  1663. return $is_certificate_mode;
  1664. }
  1665. /**
  1666. * Gets the list of included resources as a list of absolute or relative paths from a html file or string html
  1667. * This allows for a better SCORM export or replace urls inside content html from copy course
  1668. * The list will generally include pictures, flash objects, java applets, or any other
  1669. * stuff included in the source of the current item. The current item is expected
  1670. * to be an HTML file or string html. If it is not, then the function will return and empty list.
  1671. * @param string source html (content or path)
  1672. * @param bool is file or string html
  1673. * @param string type (one of the app tools) - optional (otherwise takes the current item's type)
  1674. * @param int level of recursivity we're in
  1675. * @return array List of file paths. An additional field containing 'local' or 'remote' helps determine
  1676. * if the file should be copied into the zip or just linked
  1677. */
  1678. public static function get_resources_from_source_html($source_html, $is_file = false, $type = null, $recursivity = 1)
  1679. {
  1680. $max = 5;
  1681. $attributes = array();
  1682. $wanted_attributes = array('src', 'url', '@import', 'href', 'value', 'flashvars');
  1683. $explode_attributes = array('flashvars' => 'file');
  1684. $abs_path = '';
  1685. if ($recursivity > $max) {
  1686. return array();
  1687. }
  1688. if (!isset($type)) {
  1689. $type = TOOL_DOCUMENT;
  1690. }
  1691. if (!$is_file) {
  1692. $attributes = self::parse_HTML_attributes($source_html, $wanted_attributes, $explode_attributes);
  1693. } else {
  1694. if (is_file($source_html)) {
  1695. $abs_path = $source_html;
  1696. //for now, read the whole file in one go (that's gonna be a problem when the file is too big)
  1697. $info = pathinfo($abs_path);
  1698. $ext = $info['extension'];
  1699. switch (strtolower($ext)) {
  1700. case 'html' :
  1701. case 'htm' :
  1702. case 'shtml':
  1703. case 'css' :
  1704. $file_content = file_get_contents($abs_path);
  1705. //get an array of attributes from the HTML source
  1706. $attributes = self::parse_HTML_attributes($file_content, $wanted_attributes, $explode_attributes);
  1707. break;
  1708. default :
  1709. break;
  1710. }
  1711. } else {
  1712. return false;
  1713. }
  1714. }
  1715. $files_list = array();
  1716. switch ($type) {
  1717. case TOOL_DOCUMENT :
  1718. case TOOL_QUIZ:
  1719. case 'sco':
  1720. foreach ($wanted_attributes as $attr) {
  1721. if (isset($attributes[$attr])) {
  1722. //find which kind of path these are (local or remote)
  1723. $sources = $attributes[$attr];
  1724. foreach ($sources as $source) {
  1725. //skip what is obviously not a resource
  1726. if (strpos($source, '+this.'))
  1727. continue; //javascript code - will still work unaltered
  1728. if (strpos($source, '.') === false)
  1729. continue; //no dot, should not be an external file anyway
  1730. if (strpos($source, 'mailto:'))
  1731. continue; //mailto link
  1732. if (strpos($source, ';') && !strpos($source, '&amp;'))
  1733. continue; //avoid code - that should help
  1734. if ($attr == 'value') {
  1735. if (strpos($source, 'mp3file')) {
  1736. $files_list[] = array(substr($source, 0, strpos($source, '.swf') + 4), 'local', 'abs');
  1737. $mp3file = substr($source, strpos($source, 'mp3file=') + 8);
  1738. if (substr($mp3file, 0, 1) == '/') {
  1739. $files_list[] = array($mp3file, 'local', 'abs');
  1740. } else {
  1741. $files_list[] = array($mp3file, 'local', 'rel');
  1742. }
  1743. } elseif (strpos($source, 'flv=') === 0) {
  1744. $source = substr($source, 4);
  1745. if (strpos($source, '&') > 0) {
  1746. $source = substr($source, 0, strpos($source, '&'));
  1747. }
  1748. if (strpos($source, '://') > 0) {
  1749. if (strpos($source, api_get_path(WEB_PATH)) !== false) {
  1750. //we found the current portal url
  1751. $files_list[] = array($source, 'local', 'url');
  1752. } else {
  1753. //we didn't find any trace of current portal
  1754. $files_list[] = array($source, 'remote', 'url');
  1755. }
  1756. } else {
  1757. $files_list[] = array($source, 'local', 'abs');
  1758. }
  1759. /* skipping anything else to avoid two entries
  1760. (while the others can have sub-files in their url, flv's can't)*/
  1761. continue;
  1762. }
  1763. }
  1764. if (strpos($source, '://') > 0) {
  1765. //cut at '?' in a URL with params
  1766. if (strpos($source, '?') > 0) {
  1767. $second_part = substr($source, strpos($source, '?'));
  1768. if (strpos($second_part, '://') > 0) {
  1769. //if the second part of the url contains a url too, treat the second one before cutting
  1770. $pos1 = strpos($second_part, '=');
  1771. $pos2 = strpos($second_part, '&');
  1772. $second_part = substr($second_part, $pos1 + 1, $pos2 - ($pos1 + 1));
  1773. if (strpos($second_part, api_get_path(WEB_PATH)) !== false) {
  1774. //we found the current portal url
  1775. $files_list[] = array($second_part, 'local', 'url');
  1776. $in_files_list[] = self::get_resources_from_source_html($second_part, true, TOOL_DOCUMENT, $recursivity + 1);
  1777. if (count($in_files_list) > 0) {
  1778. $files_list = array_merge($files_list, $in_files_list);
  1779. }
  1780. } else {
  1781. //we didn't find any trace of current portal
  1782. $files_list[] = array($second_part, 'remote', 'url');
  1783. }
  1784. } elseif (strpos($second_part, '=') > 0) {
  1785. if (substr($second_part, 0, 1) === '/') {
  1786. //link starts with a /, making it absolute (relative to DocumentRoot)
  1787. $files_list[] = array($second_part, 'local', 'abs');
  1788. $in_files_list[] = self::get_resources_from_source_html($second_part, true, TOOL_DOCUMENT, $recursivity + 1);
  1789. if (count($in_files_list) > 0) {
  1790. $files_list = array_merge($files_list, $in_files_list);
  1791. }
  1792. } elseif (strstr($second_part, '..') === 0) {
  1793. //link is relative but going back in the hierarchy
  1794. $files_list[] = array($second_part, 'local', 'rel');
  1795. //$dir = api_get_path(SYS_CODE_PATH);//dirname($abs_path);
  1796. //$new_abs_path = realpath($dir.'/'.$second_part);
  1797. $dir = '';
  1798. if (!empty($abs_path)) {
  1799. $dir = dirname($abs_path) . '/';
  1800. }
  1801. $new_abs_path = realpath($dir . $second_part);
  1802. $in_files_list[] = self::get_resources_from_source_html($new_abs_path, true, TOOL_DOCUMENT, $recursivity + 1);
  1803. if (count($in_files_list) > 0) {
  1804. $files_list = array_merge($files_list, $in_files_list);
  1805. }
  1806. } else {
  1807. //no starting '/', making it relative to current document's path
  1808. if (substr($second_part, 0, 2) == './') {
  1809. $second_part = substr($second_part, 2);
  1810. }
  1811. $files_list[] = array($second_part, 'local', 'rel');
  1812. $dir = '';
  1813. if (!empty($abs_path)) {
  1814. $dir = dirname($abs_path) . '/';
  1815. }
  1816. $new_abs_path = realpath($dir . $second_part);
  1817. $in_files_list[] = self::get_resources_from_source_html($new_abs_path, true, TOOL_DOCUMENT, $recursivity + 1);
  1818. if (count($in_files_list) > 0) {
  1819. $files_list = array_merge($files_list, $in_files_list);
  1820. }
  1821. }
  1822. }
  1823. //leave that second part behind now
  1824. $source = substr($source, 0, strpos($source, '?'));
  1825. if (strpos($source, '://') > 0) {
  1826. if (strpos($source, api_get_path(WEB_PATH)) !== false) {
  1827. //we found the current portal url
  1828. $files_list[] = array($source, 'local', 'url');
  1829. $in_files_list[] = self::get_resources_from_source_html($source, true, TOOL_DOCUMENT, $recursivity + 1);
  1830. if (count($in_files_list) > 0) {
  1831. $files_list = array_merge($files_list, $in_files_list);
  1832. }
  1833. } else {
  1834. //we didn't find any trace of current portal
  1835. $files_list[] = array($source, 'remote', 'url');
  1836. }
  1837. } else {
  1838. //no protocol found, make link local
  1839. if (substr($source, 0, 1) === '/') {
  1840. //link starts with a /, making it absolute (relative to DocumentRoot)
  1841. $files_list[] = array($source, 'local', 'abs');
  1842. $in_files_list[] = self::get_resources_from_source_html($source, true, TOOL_DOCUMENT, $recursivity + 1);
  1843. if (count($in_files_list) > 0) {
  1844. $files_list = array_merge($files_list, $in_files_list);
  1845. }
  1846. } elseif (strstr($source, '..') === 0) { //link is relative but going back in the hierarchy
  1847. $files_list[] = array($source, 'local', 'rel');
  1848. $dir = '';
  1849. if (!empty($abs_path)) {
  1850. $dir = dirname($abs_path) . '/';
  1851. }
  1852. $new_abs_path = realpath($dir . $source);
  1853. $in_files_list[] = self::get_resources_from_source_html($new_abs_path, true, TOOL_DOCUMENT, $recursivity + 1);
  1854. if (count($in_files_list) > 0) {
  1855. $files_list = array_merge($files_list, $in_files_list);
  1856. }
  1857. } else {
  1858. //no starting '/', making it relative to current document's path
  1859. if (substr($source, 0, 2) == './') {
  1860. $source = substr($source, 2);
  1861. }
  1862. $files_list[] = array($source, 'local', 'rel');
  1863. $dir = '';
  1864. if (!empty($abs_path)) {
  1865. $dir = dirname($abs_path) . '/';
  1866. }
  1867. $new_abs_path = realpath($dir . $source);
  1868. $in_files_list[] = self::get_resources_from_source_html($new_abs_path, true, TOOL_DOCUMENT, $recursivity + 1);
  1869. if (count($in_files_list) > 0) {
  1870. $files_list = array_merge($files_list, $in_files_list);
  1871. }
  1872. }
  1873. }
  1874. }
  1875. //found some protocol there
  1876. if (strpos($source, api_get_path(WEB_PATH)) !== false) {
  1877. //we found the current portal url
  1878. $files_list[] = array($source, 'local', 'url');
  1879. $in_files_list[] = self::get_resources_from_source_html($source, true, TOOL_DOCUMENT, $recursivity + 1);
  1880. if (count($in_files_list) > 0) {
  1881. $files_list = array_merge($files_list, $in_files_list);
  1882. }
  1883. } else {
  1884. //we didn't find any trace of current portal
  1885. $files_list[] = array($source, 'remote', 'url');
  1886. }
  1887. } else {
  1888. //no protocol found, make link local
  1889. if (substr($source, 0, 1) === '/') {
  1890. //link starts with a /, making it absolute (relative to DocumentRoot)
  1891. $files_list[] = array($source, 'local', 'abs');
  1892. $in_files_list[] = self::get_resources_from_source_html($source, true, TOOL_DOCUMENT, $recursivity + 1);
  1893. if (count($in_files_list) > 0) {
  1894. $files_list = array_merge($files_list, $in_files_list);
  1895. }
  1896. } elseif (strpos($source, '..') === 0) {
  1897. //link is relative but going back in the hierarchy
  1898. $files_list[] = array($source, 'local', 'rel');
  1899. $dir = '';
  1900. if (!empty($abs_path)) {
  1901. $dir = dirname($abs_path) . '/';
  1902. }
  1903. $new_abs_path = realpath($dir . $source);
  1904. $in_files_list[] = self::get_resources_from_source_html($new_abs_path, true, TOOL_DOCUMENT, $recursivity + 1);
  1905. if (count($in_files_list) > 0) {
  1906. $files_list = array_merge($files_list, $in_files_list);
  1907. }
  1908. } else {
  1909. //no starting '/', making it relative to current document's path
  1910. if (substr($source, 0, 2) == './') {
  1911. $source = substr($source, 2);
  1912. }
  1913. $files_list[] = array($source, 'local', 'rel');
  1914. $dir = '';
  1915. if (!empty($abs_path)) {
  1916. $dir = dirname($abs_path) . '/';
  1917. }
  1918. $new_abs_path = realpath($dir . $source);
  1919. $in_files_list[] = self::get_resources_from_source_html($new_abs_path, true, TOOL_DOCUMENT, $recursivity + 1);
  1920. if (count($in_files_list) > 0) {
  1921. $files_list = array_merge($files_list, $in_files_list);
  1922. }
  1923. }
  1924. }
  1925. }
  1926. }
  1927. }
  1928. break;
  1929. default: //ignore
  1930. break;
  1931. }
  1932. $checked_files_list = array();
  1933. $checked_array_list = array();
  1934. if (count($files_list) > 0) {
  1935. foreach ($files_list as $idx => $file) {
  1936. if (!empty($file[0])) {
  1937. if (!in_array($file[0], $checked_files_list)) {
  1938. $checked_files_list[] = $files_list[$idx][0];
  1939. $checked_array_list[] = $files_list[$idx];
  1940. }
  1941. }
  1942. }
  1943. }
  1944. return $checked_array_list;
  1945. }
  1946. /**
  1947. * Parses the HTML attributes given as string.
  1948. *
  1949. * @param string HTML attribute string
  1950. * @param array List of attributes that we want to get back
  1951. * @param array
  1952. * @return array An associative array of attributes
  1953. * @author Based on a function from the HTML_Common2 PEAR module *
  1954. */
  1955. public static function parse_HTML_attributes($attrString, $wanted = array(), $explode_variables = array())
  1956. {
  1957. $attributes = array();
  1958. $regs = array();
  1959. $reduced = false;
  1960. if (count($wanted) > 0) {
  1961. $reduced = true;
  1962. }
  1963. try {
  1964. //Find all occurences of something that looks like a URL
  1965. // The structure of this regexp is:
  1966. // (find protocol) then
  1967. // (optionally find some kind of space 1 or more times) then
  1968. // find (either an equal sign or a bracket) followed by an optional space
  1969. // followed by some text without quotes (between quotes itself or not)
  1970. // then possible closing brackets if we were in the opening bracket case
  1971. // OR something like @import()
  1972. $res = preg_match_all(
  1973. '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]*))' .
  1974. // '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]|[^\x00-\x7F])*)' . -> seems to be taking too much
  1975. // '/(((([A-Za-z_:])([^\x00-\x7F])*)' . -> takes only last letter of parameter name
  1976. '([ \n\t\r]+)?(' .
  1977. // '(=([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+))' . -> doesn't restrict close enough to the url itself
  1978. '(=([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+))' .
  1979. '|' .
  1980. // '(\(([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)\))' . -> doesn't restrict close enough to the url itself
  1981. '(\(([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+)\))' .
  1982. '))' .
  1983. '|' .
  1984. // '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))?/', -> takes a lot (like 100's of thousands of empty possibilities)
  1985. '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))/',
  1986. $attrString,
  1987. $regs
  1988. );
  1989. } catch (Exception $e) {
  1990. error_log('Caught exception: ' . $e->getMessage(), 0);
  1991. }
  1992. if ($res) {
  1993. for ($i = 0; $i < count($regs[1]); $i++) {
  1994. $name = trim($regs[3][$i]);
  1995. $check = trim($regs[0][$i]);
  1996. $value = trim($regs[10][$i]);
  1997. if (empty($value) and !empty($regs[13][$i])) {
  1998. $value = $regs[13][$i];
  1999. }
  2000. if (empty($name) && !empty($regs[16][$i])) {
  2001. $name = '@import';
  2002. $value = trim($regs[16][$i]);
  2003. }
  2004. if (!empty($name)) {
  2005. if (!$reduced OR in_array(strtolower($name), $wanted)) {
  2006. if ($name == $check) {
  2007. $attributes[strtolower($name)][] = strtolower($name);
  2008. } else {
  2009. if (!empty($value) && ($value[0] == '\'' || $value[0] == '"')) {
  2010. $value = substr($value, 1, -1);
  2011. }
  2012. if ($value == 'API.LMSGetValue(name') {
  2013. $value = 'API.LMSGetValue(name)';
  2014. }
  2015. //Gets the xx.flv value from the string flashvars="width=320&height=240&autostart=false&file=xxx.flv&repeat=false"
  2016. if (isset($explode_variables[$name])) {
  2017. $value_modified = str_replace('&amp;', '&', $value);
  2018. $value_array = explode('&', $value_modified);
  2019. foreach ($value_array as $item) {
  2020. list($key, $item_value) = explode('=', $item);
  2021. if ($key == $explode_variables[$name]) {
  2022. $attributes[strtolower($name)][] = $item_value;
  2023. }
  2024. }
  2025. }
  2026. $attributes[strtolower($name)][] = $value;
  2027. }
  2028. }
  2029. }
  2030. }
  2031. }
  2032. return $attributes;
  2033. }
  2034. /**
  2035. * Replace urls inside content html from a copy course
  2036. * @param string content html
  2037. * @param string origin course code
  2038. * @param string destination course directory
  2039. * @param string
  2040. * @return string new content html with replaced urls or return false if content is not a string
  2041. */
  2042. static function replace_urls_inside_content_html_from_copy_course(
  2043. $content_html,
  2044. $origin_course_code,
  2045. $destination_course_directory,
  2046. $origin_course_path_from_zip = null,
  2047. $origin_course_info_path = null
  2048. ) {
  2049. require_once api_get_path(LIBRARY_PATH) . 'fileUpload.lib.php';
  2050. if (empty($content_html)) {
  2051. return false;
  2052. }
  2053. $orig_source_html = DocumentManager::get_resources_from_source_html($content_html);
  2054. $orig_course_info = api_get_course_info($origin_course_code);
  2055. //Course does not exist in the current DB probably this cames from a zip file?
  2056. if (empty($orig_course_info)) {
  2057. if (!empty($origin_course_path_from_zip)) {
  2058. $orig_course_path = $origin_course_path_from_zip.'/';
  2059. $orig_course_info_path = $origin_course_info_path;
  2060. }
  2061. } else {
  2062. $orig_course_path = api_get_path(SYS_PATH).'courses/'.$orig_course_info['path'] . '/';
  2063. $orig_course_info_path = $orig_course_info['path'];
  2064. }
  2065. $destination_course_code = CourseManager::get_course_id_from_path($destination_course_directory);
  2066. $destination_course_info = api_get_course_info($destination_course_code);
  2067. $dest_course_path = api_get_path(SYS_COURSE_PATH) . $destination_course_directory . '/';
  2068. $user_id = api_get_user_id();
  2069. if (!empty($orig_source_html)) {
  2070. foreach ($orig_source_html as $source) {
  2071. // get information about source url
  2072. $real_orig_url = $source[0]; // url
  2073. $scope_url = $source[1]; // scope (local, remote)
  2074. $type_url = $source[2]; // tyle (rel, abs, url)
  2075. // Get path and query from origin url
  2076. $orig_parse_url = parse_url($real_orig_url);
  2077. $real_orig_path = isset($orig_parse_url['path']) ? $orig_parse_url['path'] : null;
  2078. $real_orig_query = isset($orig_parse_url['query']) ? $orig_parse_url['query'] : null;
  2079. // Replace origin course code by destination course code from origin url query
  2080. $dest_url_query = '';
  2081. if (!empty($real_orig_query)) {
  2082. $dest_url_query = '?' . $real_orig_query;
  2083. if (strpos($dest_url_query, $origin_course_code) !== false) {
  2084. $dest_url_query = str_replace($origin_course_code, $destination_course_code, $dest_url_query);
  2085. }
  2086. }
  2087. if ($scope_url == 'local') {
  2088. if ($type_url == 'abs' || $type_url == 'rel') {
  2089. $document_file = strstr($real_orig_path, 'document');
  2090. if (strpos($real_orig_path, $document_file) !== false) {
  2091. $origin_filepath = $orig_course_path.$document_file;
  2092. $destination_filepath = $dest_course_path.$document_file;
  2093. // copy origin file inside destination course
  2094. if (file_exists($origin_filepath)) {
  2095. $filepath_dir = dirname($destination_filepath);
  2096. if (!is_dir($filepath_dir)) {
  2097. $perm = api_get_permissions_for_new_directories();
  2098. $result = @mkdir($filepath_dir, $perm, true);
  2099. if ($result) {
  2100. $filepath_to_add = str_replace(array($dest_course_path, 'document'), '', $filepath_dir);
  2101. //Add to item properties to the new folder
  2102. $doc_id = add_document($destination_course_info, $filepath_to_add, 'folder', 0, basename($filepath_to_add));
  2103. api_item_property_update($destination_course_info, TOOL_DOCUMENT, $doc_id, 'FolderCreated', $user_id, null, null, null, null);
  2104. }
  2105. }
  2106. if (!file_exists($destination_filepath)) {
  2107. $result = @copy($origin_filepath, $destination_filepath);
  2108. if ($result) {
  2109. $filepath_to_add = str_replace(array($dest_course_path, 'document'), '', $destination_filepath);
  2110. $size = filesize($destination_filepath);
  2111. //Add to item properties to the file
  2112. $doc_id = add_document($destination_course_info, $filepath_to_add, 'file', $size, basename($filepath_to_add));
  2113. api_item_property_update($destination_course_info, TOOL_DOCUMENT, $doc_id, 'FolderCreated', $user_id, null, null, null, null);
  2114. }
  2115. }
  2116. }
  2117. // Replace origin course path by destination course path
  2118. if (strpos($content_html, $real_orig_url) !== false) {
  2119. //$origin_course_code
  2120. $url_course_path = str_replace($orig_course_info_path.'/'.$document_file, '', $real_orig_path);
  2121. $destination_url = $url_course_path . $destination_course_directory . '/' . $document_file . $dest_url_query;
  2122. //If the course code doesn't exist in the path? what we do? Nothing! see BT#1985
  2123. if (strpos($real_orig_path, $origin_course_code) === false) {
  2124. $url_course_path = $real_orig_path;
  2125. $destination_url = $real_orig_path;
  2126. }
  2127. $content_html = str_replace($real_orig_url, $destination_url, $content_html);
  2128. }
  2129. }
  2130. // replace origin course code by destination course code from origin url
  2131. if (strpos($real_orig_url, '?') === 0) {
  2132. $dest_url = str_replace($origin_course_code, $destination_course_code, $real_orig_url);
  2133. $content_html = str_replace($real_orig_url, $dest_url, $content_html);
  2134. }
  2135. } else {
  2136. if ($type_url == 'url') {
  2137. }
  2138. }
  2139. }
  2140. }
  2141. }
  2142. return $content_html;
  2143. }
  2144. /**
  2145. * Replace urls inside content html when moving a file
  2146. * @todo this code is only called in document.php but is commented
  2147. * @param string content html
  2148. * @param string origin
  2149. * @param string destination
  2150. * @return string new content html with replaced urls or return false if content is not a string
  2151. */
  2152. function replace_urls_inside_content_html_when_moving_file($file_name, $original_path, $destiny_path)
  2153. {
  2154. if (substr($original_path, strlen($original_path) - 1, strlen($original_path)) == '/') {
  2155. $original = $original_path . $file_name;
  2156. } else {
  2157. $original = $original_path . '/' . $file_name;
  2158. }
  2159. if (substr($destiny_path, strlen($destiny_path) - 1, strlen($destiny_path)) == '/') {
  2160. $destination = $destiny_path . $file_name;
  2161. } else {
  2162. $destination = $destiny_path . '/' . $file_name;
  2163. }
  2164. $original_count = count(explode('/', $original));
  2165. $destination_count = count(explode('/', $destination));
  2166. if ($original_count == $destination_count) {
  2167. //Nothing to change
  2168. return true;
  2169. }
  2170. if ($original_count > $destination_count) {
  2171. $mode = 'outside';
  2172. } else {
  2173. $mode = 'inside';
  2174. }
  2175. //We do not select the $original_path becayse the file was already moved
  2176. $content_html = file_get_contents($destiny_path . '/' . $file_name);
  2177. $destination_file = $destiny_path . '/' . $file_name;
  2178. $pre_original = strstr($original_path, 'document');
  2179. $pre_destin = strstr($destiny_path, 'document');
  2180. $pre_original = substr($pre_original, 8, strlen($pre_original));
  2181. $pre_destin = substr($pre_destin, 8, strlen($pre_destin));
  2182. $levels = count(explode('/', $pre_destin)) - 1;
  2183. $link_to_add = '';
  2184. for ($i = 1; $i <= $levels; $i++) {
  2185. $link_to_add .= '../';
  2186. }
  2187. if ($pre_original == '/') {
  2188. $pre_original = '';
  2189. }
  2190. if ($pre_destin == '/') {
  2191. $pre_destin = '';
  2192. }
  2193. if ($pre_original != '') {
  2194. $pre_original = '..' . $pre_original . '/';
  2195. }
  2196. if ($pre_destin != '') {
  2197. $pre_destin = '..' . $pre_destin . '/';
  2198. }
  2199. $levels = explode('/', $pre_original);
  2200. $count_pre_destination_levels = 0;
  2201. foreach ($levels as $item) {
  2202. if (!empty($item) && $item != '..') {
  2203. $count_pre_destination_levels++;
  2204. }
  2205. }
  2206. $count_pre_destination_levels--;
  2207. //$count_pre_destination_levels = count() - 3;
  2208. if ($count_pre_destination_levels == 0) {
  2209. $count_pre_destination_levels = 1;
  2210. }
  2211. //echo '$count_pre_destination_levels '. $count_pre_destination_levels;
  2212. $pre_remove = '';
  2213. for ($i = 1; $i <= $count_pre_destination_levels; $i++) {
  2214. $pre_remove .='..\/';
  2215. }
  2216. $orig_source_html = DocumentManager::get_resources_from_source_html($content_html);
  2217. foreach ($orig_source_html as $source) {
  2218. // get information about source url
  2219. $real_orig_url = $source[0]; // url
  2220. $scope_url = $source[1]; // scope (local, remote)
  2221. $type_url = $source[2]; // tyle (rel, abs, url)
  2222. // Get path and query from origin url
  2223. $orig_parse_url = parse_url($real_orig_url);
  2224. $real_orig_path = $orig_parse_url['path'];
  2225. $real_orig_query = $orig_parse_url['query'];
  2226. // Replace origin course code by destination course code from origin url query
  2227. /*
  2228. $dest_url_query = '';
  2229. if (!empty($real_orig_query)) {
  2230. $dest_url_query = '?'.$real_orig_query;
  2231. if (strpos($dest_url_query,$origin_course_code) !== false) {
  2232. $dest_url_query = str_replace($origin_course_code, $destination_course_code, $dest_url_query);
  2233. }
  2234. } */
  2235. if ($scope_url == 'local') {
  2236. if ($type_url == 'abs' || $type_url == 'rel') {
  2237. $document_file = strstr($real_orig_path, 'document');
  2238. if (strpos($real_orig_path, $document_file) !== false) {
  2239. echo 'continue1';
  2240. continue;
  2241. } else {
  2242. $real_orig_url_temp = '';
  2243. if ($mode == 'inside') {
  2244. $real_orig_url_temp = str_replace('../', '', $real_orig_url);
  2245. $destination_url = $link_to_add . $real_orig_url_temp;
  2246. } else {
  2247. $real_orig_url_temp = $real_orig_url;
  2248. $destination_url = preg_replace("/" . $pre_remove . "/", '', $real_orig_url, 1);
  2249. }
  2250. if ($real_orig_url == $destination_url) {
  2251. //echo 'continue2';
  2252. continue;
  2253. }
  2254. $content_html = str_replace($real_orig_url, $destination_url, $content_html);
  2255. }
  2256. } else {
  2257. echo 'continue3';
  2258. continue;
  2259. }
  2260. }
  2261. }
  2262. $return = file_put_contents($destination, $content_html);
  2263. return $return;
  2264. }
  2265. /**
  2266. * @param int $document_id
  2267. * @param string $course_code
  2268. */
  2269. public static function export_to_pdf($document_id, $course_code)
  2270. {
  2271. require_once api_get_path(LIBRARY_PATH) . 'pdf.lib.php';
  2272. $course_data = api_get_course_info($course_code);
  2273. $document_data = self::get_document_data_by_id($document_id, $course_code);
  2274. $file_path = api_get_path(SYS_COURSE_PATH) . $course_data['path'] . '/document' . $document_data['path'];
  2275. $pdf = new PDF();
  2276. $pdf->html_to_pdf($file_path, $document_data['title'], $course_code);
  2277. }
  2278. /**
  2279. * Uploads a document
  2280. *
  2281. * @param array $files the $_FILES variable
  2282. * @param string $path
  2283. * @param string $title
  2284. * @param string $comment
  2285. * @param int $unzip unzip or not the file
  2286. * @param string $if_exists overwrite, rename or warn (default)
  2287. * @param bool $index_document index document (search xapian module)
  2288. * @param bool $show_output print html messages
  2289. * @return array|bool
  2290. */
  2291. public static function upload_document(
  2292. $files,
  2293. $path,
  2294. $title = null,
  2295. $comment = null,
  2296. $unzip = 0,
  2297. $if_exists = null,
  2298. $index_document = false,
  2299. $show_output = false
  2300. ) {
  2301. require_once api_get_path(LIBRARY_PATH) . 'fileUpload.lib.php';
  2302. $course_info = api_get_course_info();
  2303. $course_dir = $course_info['path'] . '/document';
  2304. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  2305. $base_work_dir = $sys_course_path . $course_dir;
  2306. if (isset($files['file'])) {
  2307. $upload_ok = process_uploaded_file($files['file'], $show_output);
  2308. if ($upload_ok) {
  2309. // File got on the server without problems, now process it
  2310. $new_path = handle_uploaded_document(
  2311. $course_info,
  2312. $files['file'],
  2313. $base_work_dir,
  2314. $path,
  2315. api_get_user_id(),
  2316. api_get_group_id(),
  2317. null,
  2318. $unzip,
  2319. $if_exists,
  2320. $show_output
  2321. );
  2322. if ($new_path) {
  2323. $docid = DocumentManager::get_document_id($course_info, $new_path);
  2324. if (!empty($docid)) {
  2325. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  2326. $params = array();
  2327. if (!empty($title)) {
  2328. $params['title'] = get_document_title($title);
  2329. } else {
  2330. if ($if_exists == 'rename') {
  2331. $new_path = basename($new_path);
  2332. $params['title'] = get_document_title($new_path);
  2333. } else {
  2334. $params['title'] = get_document_title($files['file']['name']);
  2335. }
  2336. }
  2337. if (!empty($comment)) {
  2338. $params['comment'] = trim($comment);
  2339. }
  2340. Database::update($table_document, $params, array('id = ? AND c_id = ? ' => array($docid, $course_info['real_id'])));
  2341. }
  2342. // Showing message when sending zip files
  2343. if ($new_path === true && $unzip == 1 && $show_output) {
  2344. Display::display_confirmation_message(get_lang('UplUploadSucceeded') . '<br />', false);
  2345. }
  2346. if ($index_document) {
  2347. self::index_document($docid, $course_info['code'], null, $_POST['language'], $_REQUEST, $if_exists);
  2348. }
  2349. if (!empty($docid) && is_numeric($docid)) {
  2350. $document_data = self::get_document_data_by_id($docid, $course_info['code']);
  2351. return $document_data;
  2352. }
  2353. }
  2354. }
  2355. }
  2356. return false;
  2357. }
  2358. /**
  2359. * Obtains the text inside the file with the right parser
  2360. */
  2361. function get_text_content($doc_path, $doc_mime)
  2362. {
  2363. // TODO: review w$ compatibility
  2364. // Use usual exec output lines array to store stdout instead of a temp file
  2365. // because we need to store it at RAM anyway before index on ChamiloIndexer object
  2366. $ret_val = null;
  2367. switch ($doc_mime) {
  2368. case 'text/plain':
  2369. $handle = fopen($doc_path, 'r');
  2370. $output = array(fread($handle, filesize($doc_path)));
  2371. fclose($handle);
  2372. break;
  2373. case 'application/pdf':
  2374. exec("pdftotext $doc_path -", $output, $ret_val);
  2375. break;
  2376. case 'application/postscript':
  2377. $temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
  2378. exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
  2379. if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
  2380. return false;
  2381. }
  2382. exec("pdftotext $temp_file -", $output, $ret_val);
  2383. unlink($temp_file);
  2384. break;
  2385. case 'application/msword':
  2386. exec("catdoc $doc_path", $output, $ret_val);
  2387. break;
  2388. case 'text/html':
  2389. exec("html2text $doc_path", $output, $ret_val);
  2390. break;
  2391. case 'text/rtf':
  2392. // Note: correct handling of code pages in unrtf
  2393. // on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
  2394. exec("unrtf --text $doc_path", $output, $ret_val);
  2395. if ($ret_val == 127) { // command not found
  2396. return false;
  2397. }
  2398. // Avoid index unrtf comments
  2399. if (is_array($output) && count($output) > 1) {
  2400. $parsed_output = array();
  2401. foreach ($output as & $line) {
  2402. if (!preg_match('/^###/', $line, $matches)) {
  2403. if (!empty($line)) {
  2404. $parsed_output[] = $line;
  2405. }
  2406. }
  2407. }
  2408. $output = $parsed_output;
  2409. }
  2410. break;
  2411. case 'application/vnd.ms-powerpoint':
  2412. exec("catppt $doc_path", $output, $ret_val);
  2413. break;
  2414. case 'application/vnd.ms-excel':
  2415. exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
  2416. break;
  2417. }
  2418. $content = '';
  2419. if (!is_null($ret_val)) {
  2420. if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
  2421. return false;
  2422. }
  2423. }
  2424. if (isset($output)) {
  2425. foreach ($output as & $line) {
  2426. $content .= $line . "\n";
  2427. }
  2428. return $content;
  2429. } else {
  2430. return false;
  2431. }
  2432. }
  2433. /**
  2434. * Calculates the total size of all documents in a course
  2435. *
  2436. * @author Bert vanderkimpen
  2437. * @param int $to_group_id (to calculate group document space)
  2438. * @return int total size
  2439. */
  2440. static function documents_total_space($course_id = null, $group_id = null, $session_id = null)
  2441. {
  2442. $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2443. $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
  2444. if (isset($course_id)) {
  2445. $course_id = intval($course_id);
  2446. } else {
  2447. $course_id = api_get_course_int_id();
  2448. }
  2449. $group_condition = null;
  2450. if (isset($group_id)) {
  2451. $group_id = intval($group_id);
  2452. $group_condition = " AND props.to_group_id='" . $group_id . "' ";
  2453. }
  2454. $session_condition = null;
  2455. if (isset($session_id)) {
  2456. $session_id = intval($session_id);
  2457. $session_condition = " AND props.id_session='" . $session_id . "' ";
  2458. }
  2459. $sql = "SELECT SUM(size)
  2460. FROM $TABLE_ITEMPROPERTY AS props,
  2461. $TABLE_DOCUMENT AS docs
  2462. WHERE props.c_id = $course_id AND
  2463. docs.c_id = $course_id AND
  2464. docs.id = props.ref AND
  2465. props.tool = '" . TOOL_DOCUMENT . "' AND
  2466. props.visibility <> 2
  2467. $group_condition
  2468. $session_condition
  2469. ";
  2470. $result = Database::query($sql);
  2471. if ($result && Database::num_rows($result) != 0) {
  2472. $row = Database::fetch_row($result);
  2473. return $row[0];
  2474. } else {
  2475. return 0;
  2476. }
  2477. }
  2478. /**
  2479. * Here we count 1 Kilobyte = 1024 Bytes, 1 Megabyte = 1048576 Bytes
  2480. */
  2481. static function display_quota($course_quota, $already_consumed_space)
  2482. {
  2483. $course_quota_m = round($course_quota / 1048576);
  2484. $already_consumed_space_m = round($already_consumed_space / 1048576);
  2485. $message = get_lang('MaximumAllowedQuota') . ' <strong>' . $course_quota_m . ' megabyte</strong>.<br />';
  2486. $message .= get_lang('CourseCurrentlyUses') . ' <strong>' . $already_consumed_space_m . ' megabyte</strong>.<br />';
  2487. $percentage = round(($already_consumed_space / $course_quota * 100), 1);
  2488. $other_percentage = $percentage < 100 ? 100 - $percentage : 0;
  2489. // Decide where to place percentage in graph
  2490. if ($percentage >= 50) {
  2491. $text_in_filled = '&nbsp;' . $other_percentage . '%';
  2492. $text_in_unfilled = '';
  2493. } else {
  2494. $text_in_unfilled = '&nbsp;' . $other_percentage . '%';
  2495. $text_in_filled = '';
  2496. }
  2497. // Decide the background colour of the graph
  2498. if ($percentage < 65) {
  2499. $colour = '#00BB00'; // Safe - green
  2500. } elseif ($percentage < 90) {
  2501. $colour = '#ffd400'; // Filling up - yelloworange
  2502. } else {
  2503. $colour = '#DD0000'; // Full - red
  2504. }
  2505. // This is used for the table width: a table of only 100 pixels looks too small
  2506. $visual_percentage = 4 * $percentage;
  2507. $visual_other_percentage = 4 * $other_percentage;
  2508. $message .= get_lang('PercentageQuotaInUse') . ': <strong>' . $percentage . '%</strong>.<br />' .
  2509. get_lang('PercentageQuotaFree') . ': <strong>' . $other_percentage . '%</strong>.<br />';
  2510. $show_percentage = '&nbsp;' . $percentage . '%';
  2511. $message .= '<div style="width: 80%; text-align: center; -moz-border-radius: 5px 5px 5px 5px; border: 1px solid #aaa; background-image: url(\'' . api_get_path(WEB_CODE_PATH) . 'css/' . api_get_visual_theme() . '/images/bg-header4.png\');" class="document-quota-bar">' .
  2512. '<div style="width:' . $percentage . '%; background-color: #bbb; border-right:3px groove #bbb; -moz-border-radius:5px;">&nbsp;</div>' .
  2513. '<span style="margin-top: -15px; margin-left:-15px; position: absolute;font-weight:bold;">' . $show_percentage . '</span></div>';
  2514. echo $message;
  2515. }
  2516. /**
  2517. * Display the document quota in a simple way
  2518. *
  2519. * Here we count 1 Kilobyte = 1024 Bytes, 1 Megabyte = 1048576 Bytes
  2520. */
  2521. static function display_simple_quota($course_quota, $already_consumed_space)
  2522. {
  2523. $course_quota_m = round($course_quota / 1048576);
  2524. $already_consumed_space_m = round($already_consumed_space / 1048576, 2);
  2525. $percentage = $already_consumed_space / $course_quota * 100;
  2526. $percentage = round($percentage, 1);
  2527. $message = get_lang('YouAreCurrentlyUsingXOfYourX');
  2528. $message = sprintf($message, $already_consumed_space_m, $percentage . '%', $course_quota_m . ' ');
  2529. echo Display::div($message, array('id' => 'document_quota'));
  2530. }
  2531. /**
  2532. * Checks if there is enough place to add a file on a directory
  2533. * on the base of a maximum directory size allowed
  2534. *
  2535. * @author Bert Vanderkimpen
  2536. * @param int file_size size of the file in byte
  2537. * @param int max_dir_space maximum size
  2538. * @return boolean true if there is enough space, false otherwise
  2539. *
  2540. * @see enough_space() uses documents_total_space() function
  2541. */
  2542. static function enough_space($file_size, $max_dir_space) {
  2543. if ($max_dir_space) {
  2544. $already_filled_space = self::documents_total_space();
  2545. if (($file_size + $already_filled_space) > $max_dir_space) {
  2546. return false;
  2547. }
  2548. }
  2549. return true;
  2550. }
  2551. /**
  2552. * @param array parameters: count, url, extension
  2553. * @return string
  2554. */
  2555. static function generate_jplayer_jquery($params = array())
  2556. {
  2557. $js_path = api_get_path(WEB_LIBRARY_PATH) . 'javascript/';
  2558. $js = ' $("#jquery_jplayer_' . $params['count'] . '").jPlayer({
  2559. ready: function() {
  2560. $(this).jPlayer("setMedia", {
  2561. ' . $params['extension'] . ' : "' . $params['url'] . '"
  2562. });
  2563. },
  2564. play: function() { // To avoid both jPlayers playing together.
  2565. $(this).jPlayer("pauseOthers");
  2566. },
  2567. //errorAlerts: true,
  2568. //warningAlerts: true,
  2569. swfPath: "' . $js_path . 'jquery-jplayer",
  2570. //supplied: "m4a, oga, mp3, ogg, wav",
  2571. supplied: "' . $params['extension'] . '",
  2572. wmode: "window",
  2573. solution: "flash, html", // Do not change this setting
  2574. cssSelectorAncestor: "#jp_container_' . $params['count'] . '",
  2575. }); ' . "\n\n";
  2576. return $js;
  2577. }
  2578. /**
  2579. *
  2580. * Shows a play icon next to the document title in the document list
  2581. * @param int
  2582. * @param string
  2583. * @return string html content
  2584. */
  2585. static function generate_media_preview($i, $type = 'simple')
  2586. {
  2587. $i = intval($i);
  2588. $extra_controls = $progress = '';
  2589. if ($type == 'advanced') {
  2590. $extra_controls = ' <li><a href="javascript:;" class="jp-stop" tabindex="1">stop</a></li>
  2591. <li><a href="#" class="jp-mute" tabindex="1">mute</a></li>
  2592. <li><a href="#" class="jp-unmute" tabindex="1">unmute</a></li>';
  2593. $progress = '<div class="jp-progress">
  2594. <div class="jp-seek-bar">
  2595. <div class="jp-play-bar"></div>
  2596. </div>
  2597. </div>';
  2598. }
  2599. //Shows only the play button
  2600. $html = '<div id="jquery_jplayer_' . $i . '" class="jp-jplayer"></div>
  2601. <div id="jp_container_' . $i . '" class="jp-audio">
  2602. <div class="jp-type-single">
  2603. <div class="jp-gui jp-interface">
  2604. <ul class="jp-controls">
  2605. <li><a href="javascript:;" class="jp-play" tabindex="1">play</a></li>
  2606. <li><a href="javascript:;" class="jp-pause" tabindex="1">pause</a></li>
  2607. ' . $extra_controls . '
  2608. </ul>
  2609. ' . $progress . '
  2610. </div>
  2611. </div>
  2612. </div>';
  2613. //<div id="jplayer_inspector_'.$i.'"></div>
  2614. return $html;
  2615. }
  2616. /**
  2617. * @param array $document_data
  2618. * @return string
  2619. */
  2620. static function generate_video_preview($document_data = array())
  2621. {
  2622. $html = '
  2623. <div id="jp_container_1" class="jp-video">
  2624. <div class="jp-type-single">
  2625. <div id="jquery_jplayer_1" class="jp-jplayer"></div>
  2626. <div class="jp-gui">
  2627. <div class="jp-video-play">
  2628. <a href="javascript:;" class="jp-video-play-icon" tabindex="1">play</a>
  2629. </div>
  2630. <div class="jp-interface">
  2631. <div class="jp-progress">
  2632. <div class="jp-seek-bar">
  2633. <div class="jp-play-bar"></div>
  2634. </div>
  2635. </div>
  2636. <div class="jp-current-time"></div>
  2637. <div class="jp-controls-holder">
  2638. <ul class="jp-controls">
  2639. <li><a href="javascript:;" class="jp-play" tabindex="1">play</a></li>
  2640. <li><a href="javascript:;" class="jp-pause" tabindex="1">pause</a></li>
  2641. <li><a href="javascript:;" class="jp-stop" tabindex="1">stop</a></li>
  2642. <li><a href="javascript:;" class="jp-mute" tabindex="1" title="mute">mute</a></li>
  2643. <li><a href="javascript:;" class="jp-unmute" tabindex="1" title="unmute">unmute</a></li>
  2644. <li><a href="javascript:;" class="jp-volume-max" tabindex="1" title="max volume">max volume</a></li>
  2645. </ul>
  2646. <div class="jp-volume-bar">
  2647. <div class="jp-volume-bar-value"></div>
  2648. </div>
  2649. <ul class="jp-toggles">
  2650. <li><a href="javascript:;" class="jp-full-screen" tabindex="1" title="full screen">full screen</a></li>
  2651. <li><a href="javascript:;" class="jp-restore-screen" tabindex="1" title="restore screen">restore screen</a></li>
  2652. <li><a href="javascript:;" class="jp-repeat" tabindex="1" title="repeat">repeat</a></li>
  2653. <li><a href="javascript:;" class="jp-repeat-off" tabindex="1" title="repeat off">repeat off</a></li>
  2654. </ul>
  2655. </div>
  2656. <div class="jp-title">
  2657. <ul>
  2658. <li>' . $document_data['title'] . '</li>
  2659. </ul>
  2660. </div>
  2661. </div>
  2662. </div>
  2663. <div class="jp-no-solution">
  2664. <span>' . get_lang('UpdateRequire') . '</span>
  2665. ' . get_lang("ToPlayTheMediaYouWillNeedToUpdateYourBrowserToARecentVersionYouCanAlsoDownloadTheFile") . '
  2666. </div>
  2667. </div>
  2668. </div>';
  2669. return $html;
  2670. }
  2671. /**
  2672. * @param array $course_info
  2673. * @param bool $lp_id
  2674. * @param string $target
  2675. * @param int $session_id
  2676. * @param bool $add_move_button
  2677. * @param string $filter_by_folder
  2678. * @param string $overwrite_url
  2679. * @param bool $showInvisibleFiles
  2680. * @param bool $showOnlyFolders
  2681. * @param int $folderId
  2682. *
  2683. * @return string
  2684. */
  2685. public static function get_document_preview(
  2686. $course_info,
  2687. $lp_id = false,
  2688. $target = '',
  2689. $session_id = 0,
  2690. $add_move_button = false,
  2691. $filter_by_folder = null,
  2692. $overwrite_url = null,
  2693. $showInvisibleFiles = false,
  2694. $showOnlyFolders = false,
  2695. $folderId = false
  2696. ) {
  2697. if (empty($course_info['real_id']) || empty($course_info['code']) || !is_array($course_info)) {
  2698. return '';
  2699. }
  2700. $overwrite_url = Security::remove_XSS($overwrite_url);
  2701. $user_id = api_get_user_id();
  2702. $user_in_course = false;
  2703. if (api_is_platform_admin()) {
  2704. $user_in_course = true;
  2705. }
  2706. if (!$user_in_course) {
  2707. if (CourseManager::is_course_teacher($user_id, $course_info['code'])) {
  2708. $user_in_course = true;
  2709. }
  2710. }
  2711. // Condition for the session
  2712. $session_id = intval($session_id);
  2713. if (!$user_in_course) {
  2714. if (empty($session_id)) {
  2715. if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
  2716. $user_in_course = true;
  2717. }
  2718. //Check if course is open then we can consider that the student is regitered to the course
  2719. if (isset($course_info) && in_array($course_info['visibility'], array(2, 3))) {
  2720. $user_in_course = true;
  2721. }
  2722. } else {
  2723. $user_status = SessionManager::get_user_status_in_course_session($user_id, $course_info['code'], $session_id);
  2724. //is true if is an student, course session teacher or coach
  2725. if (in_array($user_status, array('0', '2', '6'))) {
  2726. $user_in_course = true;
  2727. }
  2728. }
  2729. }
  2730. $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
  2731. $tbl_item_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
  2732. $path = '/';
  2733. $path = Database::escape_string(str_replace('_', '\_', $path));
  2734. $added_slash = ($path == '/') ? '' : '/';
  2735. $condition_session = " AND (id_session = '$session_id' OR id_session = '0' )";
  2736. $add_folder_filter = null;
  2737. if (!empty($filter_by_folder)) {
  2738. $add_folder_filter = " AND docs.path LIKE '" . Database::escape_string($filter_by_folder) . "%'";
  2739. }
  2740. // If we are in LP display hidden folder https://support.chamilo.org/issues/6679
  2741. $lp_visibility_condition = null;
  2742. if ($lp_id) {
  2743. // $lp_visibility_condition = " OR filetype='folder'";
  2744. if ($showInvisibleFiles) {
  2745. $lp_visibility_condition .= ' OR last.visibility = 0';
  2746. }
  2747. }
  2748. $showOnlyFoldersCondition = null;
  2749. if ($showOnlyFolders) {
  2750. //$showOnlyFoldersCondition = " AND docs.filetype = 'folder' ";
  2751. }
  2752. $folderCondition = " AND docs.path LIKE '" . $path . $added_slash . "%' ";
  2753. if ($folderId !== false) {
  2754. $parentData = self::get_document_data_by_id($folderId, $course_info['code']);
  2755. if (!empty($parentData)) {
  2756. $cleanedPath = Database::escape_string($parentData['path']);
  2757. $num = substr_count($cleanedPath, '/');
  2758. $notLikeCondition = null;
  2759. for ($i = 1; $i <= $num; $i++) {
  2760. $repeat = str_repeat('/%', $i+1);
  2761. $notLikeCondition .= " AND docs.path NOT LIKE '".$cleanedPath.$repeat."' ";
  2762. }
  2763. $folderCondition = " AND
  2764. docs.id <> $folderId AND
  2765. docs.path LIKE '".$cleanedPath."/%'
  2766. $notLikeCondition
  2767. ";
  2768. } else {
  2769. $folderCondition = " AND
  2770. docs.filetype = 'file' ";
  2771. }
  2772. }
  2773. $levelCondition = null;
  2774. if ($folderId === false) {
  2775. $levelCondition = " AND docs.path NOT LIKE'/%/%'";
  2776. }
  2777. $sql = "SELECT last.visibility, docs.*
  2778. FROM $tbl_item_prop AS last INNER JOIN $tbl_doc AS docs
  2779. ON (docs.id = last.ref AND docs.c_id = last.c_id)
  2780. WHERE
  2781. docs.path NOT LIKE '%_DELETED_%' AND
  2782. last.tool = '" . TOOL_DOCUMENT . "' $condition_session AND
  2783. (last.visibility = '1' $lp_visibility_condition) AND
  2784. last.visibility <> 2 AND
  2785. docs.c_id = {$course_info['real_id']} AND
  2786. last.c_id = {$course_info['real_id']}
  2787. $showOnlyFoldersCondition
  2788. $folderCondition
  2789. $levelCondition
  2790. $add_folder_filter
  2791. ORDER BY docs.filetype DESC, docs.title ASC";
  2792. $res_doc = Database::query($sql);
  2793. $resources = Database::store_result($res_doc, 'ASSOC');
  2794. $return = '';
  2795. if ($lp_id) {
  2796. if ($folderId === false) {
  2797. $return .= '<div class="lp_resource_element">';
  2798. $return .= Display::return_icon('new_doc.gif', '', array(), ICON_SIZE_SMALL);
  2799. $return .= Display::url(
  2800. get_lang('NewDocument'),
  2801. api_get_self().'?'.api_get_cidreq().'&action=add_item&type='.TOOL_DOCUMENT.'&lp_id='.$_SESSION['oLP']->lp_id
  2802. );
  2803. $return .= '</div>';
  2804. }
  2805. } else {
  2806. $return .= Display::div(
  2807. Display::url(
  2808. Display::return_icon('close.png', get_lang('Close'), array(), ICON_SIZE_SMALL),
  2809. ' javascript:void(0);',
  2810. array('id' => 'close_div_' . $course_info['real_id'] . '_' . $session_id, 'class' => 'close_div')
  2811. ),
  2812. array('style' => 'position:absolute;right:10px')
  2813. );
  2814. }
  2815. // If you want to debug it, I advise you to do "echo" on the eval statements.
  2816. $newResources = array();
  2817. if (!empty($resources) && $user_in_course) {
  2818. foreach ($resources as $resource) {
  2819. $is_visible = self::is_visible_by_id(
  2820. $resource['id'],
  2821. $course_info,
  2822. $session_id,
  2823. api_get_user_id()
  2824. );
  2825. if (!$is_visible) {
  2826. continue;
  2827. }
  2828. $newResources[] = $resource;
  2829. }
  2830. }
  2831. $label = get_lang('Documents');
  2832. if ($folderId === false) {
  2833. $documents[$label] = array(
  2834. 'id' => 0,
  2835. 'files' => $newResources
  2836. );
  2837. } else {
  2838. $documents[$parentData['title']] = array(
  2839. 'id' => intval($folderId),
  2840. 'files' => $newResources
  2841. );
  2842. }
  2843. $write_result = self::write_resources_tree(
  2844. $course_info,
  2845. $session_id,
  2846. $documents,
  2847. $lp_id,
  2848. $target,
  2849. $add_move_button,
  2850. $overwrite_url,
  2851. $folderId
  2852. );
  2853. $return .= $write_result;
  2854. $img_path = api_get_path(WEB_IMG_PATH);
  2855. if ($lp_id == false) {
  2856. $url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?a=get_documents&url='.$overwrite_url.'&lp_id='.$lp_id.'&cidReq='.$course_info['code'];
  2857. $return .= "<script>
  2858. $('.doc_folder').click(function() {
  2859. var realId = this.id;
  2860. var my_id = this.id.split('_')[2];
  2861. var tempId = 'temp_'+my_id;
  2862. $('#res_'+my_id).show();
  2863. var tempDiv = $('#'+realId).find('#'+tempId);
  2864. if (tempDiv.length == 0) {
  2865. $.ajax({
  2866. async: false,
  2867. type: 'GET',
  2868. url: '".$url."',
  2869. data: 'folder_id='+my_id,
  2870. success: function(data) {
  2871. $('#'+realId).append('<div id='+tempId+'>'+data+'</div>');
  2872. }
  2873. });
  2874. }
  2875. });
  2876. $('.close_div').click(function() {
  2877. var course_id = this.id.split('_')[2];
  2878. var session_id = this.id.split('_')[3];
  2879. $('#document_result_'+course_id+'_'+session_id).hide();
  2880. $('.lp_resource').remove();
  2881. $('.document_preview_container').html('');
  2882. });
  2883. </script>";
  2884. } else {
  2885. //For LPs
  2886. $url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?a=get_documents&lp_id='.$lp_id.'&'.api_get_cidreq();
  2887. $return .= "<script>
  2888. function testResources(id, img) {
  2889. var numericId = id.split('_')[1];
  2890. var parentId = 'doc_id_'+numericId;
  2891. var tempId = 'temp_'+numericId;
  2892. var image = $('#'+img);
  2893. if (image.hasClass('open')) {
  2894. image.removeClass('open');
  2895. image.attr('src', '" . $img_path . "nolines_plus.gif');
  2896. $('#'+id).show();
  2897. $('#'+tempId).hide();
  2898. } else {
  2899. image.addClass('open');
  2900. image.attr('src', '" . $img_path . "nolines_minus.gif');
  2901. $('#'+id).hide();
  2902. $('#'+tempId).show();
  2903. var tempDiv = $('#'+parentId).find('#'+tempId);
  2904. if (tempDiv.length == 0) {
  2905. $.ajax({
  2906. type: 'GET',
  2907. async: false,
  2908. url: '".$url."',
  2909. data: 'folder_id='+numericId,
  2910. success: function(data) {
  2911. tempDiv = $('#doc_id_'+numericId).append('<div id='+tempId+'>'+data+'</div>');
  2912. }
  2913. });
  2914. }
  2915. }
  2916. }
  2917. </script>";
  2918. }
  2919. if (!$user_in_course) {
  2920. $return = '';
  2921. }
  2922. return $return;
  2923. }
  2924. private static function parseFile(
  2925. $course_info,
  2926. $session_id,
  2927. $resource,
  2928. $lp_id,
  2929. $add_move_button,
  2930. $target,
  2931. $overwrite_url
  2932. ) {
  2933. $img_path = api_get_path(WEB_IMG_PATH);
  2934. $img_sys_path = api_get_path(SYS_CODE_PATH) . 'img/';
  2935. $web_code_path = api_get_path(WEB_CODE_PATH);
  2936. $documentId = $resource['id'];
  2937. $path = $resource['path'];
  2938. if (empty($path)) {
  2939. $num = 0;
  2940. } else {
  2941. $num = substr_count($path, '/') - 1;
  2942. }
  2943. // It's a file.
  2944. $icon = choose_image($path);
  2945. $position = strrpos($icon, '.');
  2946. $icon = substr($icon, 0, $position) . '_small.gif';
  2947. $my_file_title = $resource['title'];
  2948. $visibility = $resource['visibility'];
  2949. // If title is empty we try to use the path
  2950. if (empty($my_file_title)) {
  2951. $my_file_title = basename($path);
  2952. }
  2953. // Show the "image name" not the filename of the image.
  2954. if ($lp_id) {
  2955. //LP URL
  2956. $url = api_get_path(WEB_CODE_PATH).'newscorm/lp_controller.php?'.api_get_cidreq().'&amp;action=add_item&amp;type=' . TOOL_DOCUMENT . '&amp;file=' . $documentId . '&amp;lp_id=' . $lp_id;
  2957. if (!empty($overwrite_url)) {
  2958. $url = $overwrite_url . '&cidReq=' . $course_info['code'] . '&id_session=' . $session_id . '&document_id=' . $documentId.'';
  2959. }
  2960. } else {
  2961. // Direct document URL
  2962. $url = $web_code_path . 'document/document.php?cidReq=' . $course_info['code'] . '&id_session=' . $session_id . '&id=' . $documentId;
  2963. if (!empty($overwrite_url)) {
  2964. $url = $overwrite_url . '&cidReq=' . $course_info['code'] . '&id_session=' . $session_id . '&document_id=' . $documentId;
  2965. }
  2966. }
  2967. $img = $img_path . $icon;
  2968. if (!file_exists($img_sys_path . $icon)) {
  2969. $img = $img_path . 'icons/16/default_small.gif';
  2970. }
  2971. $link = Display::url(
  2972. '<img alt="" src="' . $img . '" title="" />&nbsp;' . $my_file_title, $url,
  2973. array('target' => $target)
  2974. );
  2975. $visibilityClass = null;
  2976. if ($visibility == 0) {
  2977. $visibilityClass = ' invisible ';
  2978. }
  2979. $return = null;
  2980. if ($lp_id == false) {
  2981. $return .= '<li class="doc_resource '.$visibilityClass.' " data_id="' . $documentId . '" data_type="document" title="' . $my_file_title . '" >';
  2982. } else {
  2983. $return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="' . $documentId . '" data_type="document" title="' . $my_file_title . '" >';
  2984. }
  2985. $return .= '<div class="item_data" style="margin-left:' . ($num * 18) . 'px;margin-right:5px;">';
  2986. if ($add_move_button) {
  2987. $return .= '<a class="moved" href="#">';
  2988. $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), array(), ICON_SIZE_TINY);
  2989. $return .= '</a> ';
  2990. }
  2991. $return .= $link;
  2992. $return .= '</div></li>';
  2993. return $return;
  2994. }
  2995. private static function parseFolder($folderId, $resource, $lp_id)
  2996. {
  2997. $title = isset($resource['title']) ? $resource['title'] : null;
  2998. $path = isset($resource['path']) ? $resource['path'] : null;
  2999. $img_path = api_get_path(WEB_IMG_PATH);
  3000. if (empty($path)) {
  3001. $num = 0;
  3002. } else {
  3003. $num = substr_count($path, '/');
  3004. }
  3005. // It's a folder.
  3006. //hide some folders
  3007. if (in_array($path,
  3008. array('shared_folder', 'chat_files', 'HotPotatoes_files', 'css', 'certificates'))) {
  3009. return null;
  3010. } elseif (preg_match('/_groupdocs/', $path)) {
  3011. return null;
  3012. } elseif (preg_match('/sf_user_/', $path)) {
  3013. return null;
  3014. } elseif (preg_match('/shared_folder_session_/', $path)) {
  3015. return null;
  3016. }
  3017. //trad some titles
  3018. /*
  3019. if ($key == 'images') {
  3020. $key = get_lang('Images');
  3021. } elseif ($key == 'gallery') {
  3022. $key = get_lang('Gallery');
  3023. } elseif ($key == 'flash') {
  3024. $key = get_lang('Flash');
  3025. } elseif ($key == 'audio') {
  3026. $key = get_lang('Audio');
  3027. } elseif ($key == 'video') {
  3028. $key = get_lang('Video');
  3029. }*/
  3030. $onclick = '';
  3031. // if in LP, hidden folder are displayed in grey
  3032. $folder_class_hidden = "";
  3033. if ($lp_id) {
  3034. if (isset($resource['visible']) && $resource['visible'] == 0) {
  3035. $folder_class_hidden = "doc_folder_hidden"; // in base.css
  3036. }
  3037. $onclick = 'onclick="javascript: testResources(\'res_' . $resource['id'] . '\',\'img_' . $resource['id'] . '\')"';
  3038. }
  3039. $return = null;
  3040. if (empty($path)) {
  3041. $return = '<ul class="lp_resource">';
  3042. }
  3043. $return .= '<li class="doc_folder '.$folder_class_hidden.'" id="doc_id_' . $resource['id'] . '" style="margin-left:' . ($num * 18) . 'px; ">';
  3044. $image = $img_path.'nolines_plus.gif';
  3045. if (empty($path)) {
  3046. $image = $img_path.'nolines_minus.gif';
  3047. }
  3048. $return .= '<img style="cursor: pointer;" src="'.$image.'" align="absmiddle" id="img_'.$resource['id'] . '" '.$onclick.'>';
  3049. $return .= '<img alt="" src="' . $img_path . 'lp_folder.gif" title="" align="absmiddle" />&nbsp;';
  3050. $return .= '<span '.$onclick.' style="cursor: pointer;" >'.$title.'</span>';
  3051. $return .= '</li>';
  3052. if (empty($path)) {
  3053. if ($folderId == false) {
  3054. $return .= '<div id="res_' . $resource['id'] . '" >';
  3055. } else {
  3056. $return .= '<div id="res_' . $resource['id'] . '" style="display: none;" >';
  3057. }
  3058. }
  3059. return $return;
  3060. }
  3061. /**
  3062. * Generate and return an HTML list of resources based on a given array.
  3063. * This list is used to show the course creator a list of available resources to choose from
  3064. * when creating a learning path.
  3065. * @param array $course_info
  3066. * @param int $session_id
  3067. * @param array $documents
  3068. * @param bool $lp_id
  3069. * @param string $target
  3070. * @param bool $add_move_button
  3071. * @param string $overwrite_url
  3072. * @param int $folderId
  3073. *
  3074. * @return string
  3075. */
  3076. public static function write_resources_tree(
  3077. $course_info,
  3078. $session_id,
  3079. $documents,
  3080. $lp_id = false,
  3081. $target = '',
  3082. $add_move_button = false,
  3083. $overwrite_url = null,
  3084. $folderId = false
  3085. ) {
  3086. require_once api_get_path(LIBRARY_PATH) . 'fileDisplay.lib.php';
  3087. $return = '';
  3088. if (!empty($documents)) {
  3089. foreach ($documents as $key => $resource) {
  3090. if (isset($resource['id']) && is_int($resource['id'])) {
  3091. $mainFolderResource = array(
  3092. 'id' => $resource['id'],
  3093. 'title' => $key,
  3094. );
  3095. if ($folderId === false) {
  3096. $return .= self::parseFolder($folderId, $mainFolderResource, $lp_id);
  3097. }
  3098. if (isset($resource['files'])) {
  3099. $return .= self::write_resources_tree(
  3100. $course_info,
  3101. $session_id,
  3102. $resource['files'],
  3103. $lp_id,
  3104. $target,
  3105. $add_move_button,
  3106. $overwrite_url
  3107. );
  3108. }
  3109. $return .= '</div>';
  3110. $return .= '</ul>';
  3111. } else {
  3112. if ($resource['filetype'] == 'folder') {
  3113. $return .= self::parseFolder($folderId, $resource, $lp_id);
  3114. } else {
  3115. $return .= self::parseFile(
  3116. $course_info,
  3117. $session_id,
  3118. $resource,
  3119. $lp_id,
  3120. $add_move_button,
  3121. $target,
  3122. $overwrite_url
  3123. );
  3124. }
  3125. }
  3126. }
  3127. }
  3128. return $return;
  3129. }
  3130. /**
  3131. * @param int $doc_id
  3132. * @param string $course_code
  3133. * @param int $session_id
  3134. * @param int $user_id
  3135. * @param int $groupId
  3136. * @return bool
  3137. */
  3138. public static function check_visibility_tree($doc_id, $course_code, $session_id, $user_id, $groupId = 0)
  3139. {
  3140. $document_data = self::get_document_data_by_id($doc_id, $course_code, null, $session_id);
  3141. if ($session_id != 0 && !$document_data) {
  3142. $document_data = self::get_document_data_by_id($doc_id, $course_code, null, 0);
  3143. }
  3144. if (!empty($document_data)) {
  3145. // If admin or course teacher, allow anyway
  3146. if (api_is_platform_admin() || CourseManager::is_course_teacher($user_id, $course_code)) {
  3147. return true;
  3148. }
  3149. $course_info = api_get_course_info($course_code);
  3150. if ($document_data['parent_id'] == false || empty($document_data['parent_id'])) {
  3151. if (!empty($groupId)) {
  3152. return true;
  3153. }
  3154. $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
  3155. return $visible;
  3156. } else {
  3157. $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
  3158. if (!$visible) {
  3159. return false;
  3160. } else {
  3161. return self::check_visibility_tree($document_data['parent_id'], $course_code, $session_id, $user_id, $groupId);
  3162. }
  3163. }
  3164. } else {
  3165. return false;
  3166. }
  3167. }
  3168. /**
  3169. * Index a given document.
  3170. * @param int Document ID inside its corresponding course
  3171. * @param string Course code
  3172. * @param int Session ID (not used yet)
  3173. * @param string Language of document's content (defaults to course language)
  3174. * @param array Array of specific fields (['code'=>'value',...])
  3175. * @param string What to do if the file already exists (default or overwrite)
  3176. * @param bool When set to true, this runs the indexer without actually saving anything to any database
  3177. * @return bool Returns true on presumed success, false on failure
  3178. */
  3179. public static function index_document(
  3180. $docid,
  3181. $course_code,
  3182. $session_id = 0,
  3183. $lang = 'english',
  3184. $specific_fields_values = array(),
  3185. $if_exists = '',
  3186. $simulation = false
  3187. ) {
  3188. if (api_get_setting('search_enabled') !== 'true') {
  3189. return false;
  3190. }
  3191. if (empty($docid) or $docid != intval($docid)) {
  3192. return false;
  3193. }
  3194. if (empty($session_id)) {
  3195. $session_id = api_get_session_id();
  3196. }
  3197. $course_info = api_get_course_info($course_code);
  3198. $course_dir = $course_info['path'] . '/document';
  3199. $sys_course_path = api_get_path(SYS_COURSE_PATH);
  3200. $base_work_dir = $sys_course_path . $course_dir;
  3201. $course_id = $course_info['real_id'];
  3202. $table_document = Database::get_course_table(TABLE_DOCUMENT);
  3203. $qry = "SELECT path, title FROM $table_document WHERE c_id = $course_id AND id = '$docid' LIMIT 1";
  3204. $result = Database::query($qry);
  3205. if (Database::num_rows($result) == 1) {
  3206. $row = Database::fetch_array($result);
  3207. $doc_path = api_get_path(SYS_COURSE_PATH) . $course_dir . $row['path'];
  3208. //TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
  3209. // now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
  3210. $doc_mime = mime_content_type($doc_path);
  3211. $allowed_mime_types = self::file_get_mime_type(true);
  3212. // mime_content_type does not detect correctly some formats that are going to be supported for index, so an extensions array is used for the moment
  3213. if (empty($doc_mime)) {
  3214. $allowed_extensions = array('doc', 'docx', 'ppt', 'pptx', 'pps', 'ppsx', 'xls', 'xlsx', 'odt', 'odp', 'ods', 'pdf', 'txt', 'rtf', 'msg', 'csv', 'html', 'htm');
  3215. $extensions = preg_split("/[\/\\.]/", $doc_path);
  3216. $doc_ext = strtolower($extensions[count($extensions) - 1]);
  3217. if (in_array($doc_ext, $allowed_extensions)) {
  3218. switch ($doc_ext) {
  3219. case 'ppt':
  3220. case 'pps':
  3221. $doc_mime = 'application/vnd.ms-powerpoint';
  3222. break;
  3223. case 'xls':
  3224. $doc_mime = 'application/vnd.ms-excel';
  3225. break;
  3226. }
  3227. }
  3228. }
  3229. //@todo move this nightmare in a search controller or something like that!!! J.M
  3230. if (in_array($doc_mime, $allowed_mime_types)) {
  3231. $file_title = $row['title'];
  3232. $file_content = self::get_text_content($doc_path, $doc_mime);
  3233. $course_code = Database::escape_string($course_code);
  3234. require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
  3235. require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
  3236. $ic_slide = new IndexableChunk();
  3237. $ic_slide->addValue('title', $file_title);
  3238. $ic_slide->addCourseId($course_code);
  3239. $ic_slide->addToolId(TOOL_DOCUMENT);
  3240. $xapian_data = array(
  3241. SE_COURSE_ID => $course_code,
  3242. SE_TOOL_ID => TOOL_DOCUMENT,
  3243. SE_DATA => array('doc_id' => $docid),
  3244. SE_USER => api_get_user_id(),
  3245. );
  3246. $ic_slide->xapian_data = serialize($xapian_data);
  3247. $di = new ChamiloIndexer();
  3248. $return = $di->connectDb(null, null, $lang);
  3249. require_once api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php';
  3250. $specific_fields = get_specific_field_list();
  3251. // process different depending on what to do if file exists
  3252. /**
  3253. * @TODO Find a way to really verify if the file had been
  3254. * overwriten. Now all work is done at
  3255. * handle_uploaded_document() and it's difficult to verify it
  3256. */
  3257. if (!empty($if_exists) && $if_exists == 'overwrite') {
  3258. // Overwrite the file on search engine
  3259. // Actually, it consists on a delete of terms from db,
  3260. // insert new ones, create a new search engine document,
  3261. // and remove the old one
  3262. // Get search_did
  3263. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  3264. $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
  3265. $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid);
  3266. $res = Database::query($sql);
  3267. if (Database::num_rows($res) > 0) {
  3268. $se_ref = Database::fetch_array($res);
  3269. if (!$simulation) {
  3270. $di->remove_document($se_ref['search_did']);
  3271. }
  3272. $all_specific_terms = '';
  3273. foreach ($specific_fields as $specific_field) {
  3274. if (!$simulation) {
  3275. delete_all_specific_field_value($course_code, $specific_field['id'], TOOL_DOCUMENT, $docid);
  3276. }
  3277. // Update search engine
  3278. if (isset($specific_fields_values[$specific_field['code']])) {
  3279. $sterms = trim($specific_fields_values[$specific_field['code']]);
  3280. } else { //if the specific field is not defined, force an empty one
  3281. $sterms = '';
  3282. }
  3283. $all_specific_terms .= ' ' . $sterms;
  3284. $sterms = explode(',', $sterms);
  3285. foreach ($sterms as $sterm) {
  3286. $sterm = trim($sterm);
  3287. if (!empty($sterm)) {
  3288. $ic_slide->addTerm($sterm, $specific_field['code']);
  3289. // updated the last param here from $value to $sterm without being sure - see commit15464
  3290. if (!$simulation) {
  3291. add_specific_field_value($specific_field['id'], $course_code, TOOL_DOCUMENT, $docid, $sterm);
  3292. }
  3293. }
  3294. }
  3295. }
  3296. // Add terms also to content to make terms findable by probabilistic search
  3297. $file_content = $all_specific_terms . ' ' . $file_content;
  3298. if (!$simulation) {
  3299. $ic_slide->addValue('content', $file_content);
  3300. $di->addChunk($ic_slide);
  3301. // Index and return a new search engine document id
  3302. $did = $di->index();
  3303. if ($did) {
  3304. // update the search_did on db
  3305. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  3306. $sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
  3307. $sql = sprintf($sql, $tbl_se_ref, (int) $did, (int) $se_ref['id']);
  3308. Database::query($sql);
  3309. }
  3310. }
  3311. }
  3312. } else {
  3313. // Add all terms
  3314. $all_specific_terms = '';
  3315. foreach ($specific_fields as $specific_field) {
  3316. if (isset($specific_fields_values[$specific_field['code']])) {
  3317. $sterms = trim($specific_fields_values[$specific_field['code']]);
  3318. } else { //if the specific field is not defined, force an empty one
  3319. $sterms = '';
  3320. }
  3321. $all_specific_terms .= ' ' . $sterms;
  3322. if (!empty($sterms)) {
  3323. $sterms = explode(',', $sterms);
  3324. foreach ($sterms as $sterm) {
  3325. if (!$simulation) {
  3326. $ic_slide->addTerm(trim($sterm), $specific_field['code']);
  3327. add_specific_field_value($specific_field['id'], $course_code, TOOL_DOCUMENT, $docid, $sterm);
  3328. }
  3329. }
  3330. }
  3331. }
  3332. // Add terms also to content to make terms findable by probabilistic search
  3333. $file_content = $all_specific_terms . ' ' . $file_content;
  3334. if (!$simulation) {
  3335. $ic_slide->addValue('content', $file_content);
  3336. $di->addChunk($ic_slide);
  3337. // Index and return search engine document id
  3338. $did = $di->index();
  3339. if ($did) {
  3340. // Save it to db
  3341. $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
  3342. $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
  3343. VALUES (NULL , \'%s\', \'%s\', %s, %s)';
  3344. $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid, $did);
  3345. Database::query($sql);
  3346. } else {
  3347. return false;
  3348. }
  3349. }
  3350. }
  3351. } else {
  3352. return false;
  3353. }
  3354. }
  3355. return true;
  3356. }
  3357. /**
  3358. * @return array
  3359. */
  3360. public static function get_web_odf_extension_list()
  3361. {
  3362. return array('ods', 'odt');
  3363. }
  3364. /**
  3365. * @param string $path
  3366. * @param bool $is_certificate_mode
  3367. * @return bool
  3368. */
  3369. public static function is_folder_to_avoid($path, $is_certificate_mode = false)
  3370. {
  3371. $foldersToAvoid = array(
  3372. '/HotPotatoes_files',
  3373. '/certificates',
  3374. );
  3375. $systemFolder = api_get_course_setting('show_system_folders');
  3376. if ($systemFolder == 1) {
  3377. $foldersToAvoid = array();
  3378. }
  3379. if (basename($path) == 'css') {
  3380. return true;
  3381. }
  3382. if ($is_certificate_mode == false) {
  3383. //Certificate results
  3384. if (strstr($path, 'certificates')) {
  3385. return true;
  3386. }
  3387. }
  3388. // Admin setting for Hide/Show the folders of all users
  3389. if (api_get_setting('show_users_folders') == 'false') {
  3390. $foldersToAvoid[] = '/shared_folder';
  3391. if (strstr($path, 'shared_folder_session_')) {
  3392. return true;
  3393. }
  3394. }
  3395. // Admin setting for Hide/Show Default folders to all users
  3396. if (api_get_setting('show_default_folders') == 'false') {
  3397. $foldersToAvoid[] = '/images';
  3398. $foldersToAvoid[] = '/flash';
  3399. $foldersToAvoid[] = '/audio';
  3400. $foldersToAvoid[] = '/video';
  3401. }
  3402. // Admin setting for Hide/Show chat history folder
  3403. if (api_get_setting('show_chat_folder') == 'false') {
  3404. $foldersToAvoid[] = '/chat_files';
  3405. }
  3406. return in_array($path, $foldersToAvoid);
  3407. }
  3408. /**
  3409. * @return array
  3410. */
  3411. static function get_system_folders()
  3412. {
  3413. $system_folders = array(
  3414. '/certificates',
  3415. '/HotPotatoes_files',
  3416. '/chat_files',
  3417. '/images',
  3418. '/flash',
  3419. '/audio',
  3420. '/video',
  3421. '/shared_folder',
  3422. '/learning_path'
  3423. );
  3424. return $system_folders;
  3425. }
  3426. /**
  3427. * @param string $courseCode
  3428. * @return string 'visible' or 'invisible' string
  3429. */
  3430. public static function getDocumentDefaultVisibility($courseCode)
  3431. {
  3432. $settings = api_get_setting('tool_visible_by_default_at_creation');
  3433. $defaultVisibility = 'visible';
  3434. if (isset($settings['documents'])) {
  3435. $portalDefaultVisibility = 'invisible';
  3436. if ($settings['documents'] == 'true') {
  3437. $portalDefaultVisibility = 'visible';
  3438. }
  3439. $defaultVisibility = $portalDefaultVisibility;
  3440. }
  3441. if (api_get_setting('documents_default_visibility_defined_in_course') == 'true') {
  3442. $courseVisibility = api_get_course_setting('documents_default_visibility', $courseCode);
  3443. if (!empty($courseVisibility) && in_array($courseVisibility, array('visible', 'invisible'))) {
  3444. $defaultVisibility = $courseVisibility;
  3445. }
  3446. }
  3447. return $defaultVisibility;
  3448. }
  3449. /**
  3450. * @param array $courseInfo
  3451. * @param int $id doc id
  3452. * @param string $visibility visible/invisible
  3453. * @param int $userId
  3454. */
  3455. public static function updateVisibilityFromAllSessions($courseInfo, $id, $visibility, $userId)
  3456. {
  3457. $sessionList = SessionManager::get_session_by_course($courseInfo['code']);
  3458. if (!empty($sessionList)) {
  3459. foreach ($sessionList as $session) {
  3460. $sessionId = $session['id'];
  3461. api_item_property_update(
  3462. $courseInfo,
  3463. TOOL_DOCUMENT,
  3464. $id,
  3465. $visibility,
  3466. $userId,
  3467. null,
  3468. null,
  3469. null,
  3470. null,
  3471. $sessionId
  3472. );
  3473. }
  3474. }
  3475. }
  3476. /**
  3477. * @param string $file
  3478. * @return string
  3479. */
  3480. public static function readNanogongFile($file)
  3481. {
  3482. $nanoGongJarFile = api_get_path(WEB_LIBRARY_PATH).'nanogong/nanogong.jar';
  3483. $html = '<applet id="applet" archive="'.$nanoGongJarFile.'" code="gong.NanoGong" width="160" height="95">';
  3484. $html .= '<param name="SoundFileURL" value="'.$file.'" />';
  3485. $html .= '<param name="ShowSaveButton" value="false" />';
  3486. $html .= '<param name="ShowTime" value="true" />';
  3487. $html .= '<param name="ShowRecordButton" value="false" />';
  3488. $html .= '</applet>';
  3489. return $html;
  3490. }
  3491. /**
  3492. * @param string $filePath
  3493. * @param string $path
  3494. * @param $courseInfo
  3495. * @param string $whatIfFileExists overwrite|rename
  3496. * @param null $userId
  3497. * @param null $groupId
  3498. * @param null $toUserId
  3499. * @return bool|path
  3500. */
  3501. public static function addFileToDocumentTool(
  3502. $filePath,
  3503. $path,
  3504. $courseInfo,
  3505. $userId,
  3506. $whatIfFileExists = 'overwrite',
  3507. $groupId = null,
  3508. $toUserId = null
  3509. ) {
  3510. if (!file_exists($filePath)) {
  3511. return false;
  3512. }
  3513. $fileInfo = pathinfo($filePath);
  3514. $file = array(
  3515. 'name' => $fileInfo['basename'],
  3516. 'tmp_name' => $filePath,
  3517. 'size' => filesize($filePath),
  3518. 'from_file' => true
  3519. );
  3520. $course_dir = $courseInfo['path'].'/document';
  3521. $baseWorkDir = api_get_path(SYS_COURSE_PATH).$course_dir;
  3522. $filePath = handle_uploaded_document(
  3523. $courseInfo,
  3524. $file,
  3525. $baseWorkDir,
  3526. $path,
  3527. $userId,
  3528. $groupId,
  3529. $toUserId,
  3530. false,
  3531. $whatIfFileExists,
  3532. false
  3533. );
  3534. if ($filePath) {
  3535. return DocumentManager::get_document_id($courseInfo, $filePath);
  3536. }
  3537. return false;
  3538. }
  3539. /**
  3540. * Converts wav to mp3 file.
  3541. * Requires the ffmpeg lib. In ubuntu: sudo apt-get install ffmpeg
  3542. * @param string $wavFile
  3543. * @param bool $removeWavFileIfSuccess
  3544. * @return bool
  3545. */
  3546. public static function convertWavToMp3($wavFile, $removeWavFileIfSuccess = false)
  3547. {
  3548. require_once '../../../../vendor/autoload.php';
  3549. if (file_exists($wavFile)) {
  3550. try {
  3551. $ffmpeg = \FFMpeg\FFMpeg::create();
  3552. $video = $ffmpeg->open($wavFile);
  3553. $mp3File = str_replace('wav', 'mp3', $wavFile);
  3554. $result = $video->save(new FFMpeg\Format\Audio\Mp3(), $mp3File);
  3555. if ($result && $removeWavFileIfSuccess) {
  3556. unlink($wavFile);
  3557. }
  3558. if (file_exists($mp3File)) {
  3559. return $mp3File;
  3560. }
  3561. } catch (Exception $e) {
  3562. }
  3563. }
  3564. return false;
  3565. }
  3566. /**
  3567. * @param string $documentData
  3568. * @param array $courseInfo
  3569. * @param string $whatIfFileExists
  3570. * @return bool|path
  3571. */
  3572. public static function addAndConvertWavToMp3($documentData, $courseInfo, $userId, $whatIfFileExists = 'overwrite')
  3573. {
  3574. if (empty($documentData)) {
  3575. return false;
  3576. }
  3577. if (isset($documentData['absolute_path']) && file_exists($documentData['absolute_path'])) {
  3578. $mp3FilePath = self::convertWavToMp3($documentData['absolute_path']);
  3579. //$mp3FilePath = str_replace('wav', 'mp3', $documentData['absolute_path']);
  3580. if (!empty($mp3FilePath)) {
  3581. $documentId = self::addFileToDocumentTool(
  3582. $mp3FilePath,
  3583. dirname($documentData['path']),
  3584. $courseInfo,
  3585. $userId,
  3586. $whatIfFileExists
  3587. );
  3588. if (!empty($documentId)) {
  3589. return $documentId;
  3590. }
  3591. }
  3592. }
  3593. return false;
  3594. }
  3595. }