learnpath_functions.inc.php 110 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * This is a function library for the learning path.
  5. *
  6. * Due to the face that the learning path has been built upon the resoucelinker,
  7. * naming conventions have changed at least 2 times. You can see here in order the :
  8. * 1. name used in the first version of the resourcelinker
  9. * 2. name used in the first version of the LP
  10. * 3. name used in the second (current) version of the LP
  11. *
  12. * 1. 2. 3.
  13. * Category = Chapter = Module
  14. * Item (?) = Item = Step
  15. *
  16. * @author Denes Nagy <darkden@evk.bke.hu>, main author
  17. * @author Roan Embrechts, some code cleaning
  18. * @author Yannick Warnier <yannick.warnier@beeznest.com>, multi-level learnpath behaviour + new SCORM tool
  19. * @access public
  20. * @package chamilo.learnpath
  21. * @todo rename functions to coding conventions: not deleteitem but delete_item, etc
  22. * @todo rewrite functions to comply with phpDocumentor
  23. * @todo remove code duplication
  24. */
  25. /**
  26. * This function deletes an item
  27. * @param integer $id: the item we want to delete
  28. * @return boolean True if item was deleted, false if not found or error
  29. */
  30. function deleteitem($id) {
  31. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  32. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  33. // Get the display order for this item before it is deleted.
  34. $sql = "SELECT display_order, parent_item_id FROM $tbl_lp_item WHERE id=$id";
  35. $result = Database::query($sql);
  36. if (Database::num_rows($result) == 0) {
  37. return false;
  38. }
  39. $row = Database::fetch_row($result);
  40. $display_order = $row[0];
  41. $parent_item_id = $row[1];
  42. // Delete the item.
  43. $sql = "DELETE FROM $tbl_learnpath_item WHERE id='$id'";
  44. $result = Database::query($sql);
  45. if ($result === false) {
  46. return false;
  47. }
  48. // Update the other items and chapters.
  49. $sql = "UPDATE $tbl_learnpath_item SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_item_id";
  50. $result = Database::query($sql);
  51. $sql = "UPDATE $tbl_learnpath_chapter SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_item_id";
  52. $result = Database::query($sql);
  53. return true;
  54. }
  55. /**
  56. * This function deletes a module(chapter) and all its steps(items).
  57. *
  58. * @param integer id of the chapter we want to delete
  59. * @return boolean True on success and false if not found or error
  60. */
  61. function deletemodule($parent_item_id) {
  62. global $learnpath_id;
  63. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  64. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  65. // Added for multi-level behaviour - slightly recursive.
  66. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id=$learnpath_id";
  67. $result = Database::query($sql);
  68. while ($row = Database::fetch_array($result)) {
  69. if ($row['parent_item_id'] == $parent_item_id) {
  70. // Delete every subchapter.
  71. if (deletemodule($row['id']) === false) {
  72. return false;
  73. }
  74. }
  75. }
  76. // Get this chapter's display order.
  77. $sql = "SELECT display_order, parent_item_id FROM $tbl_learnpath_chapter
  78. WHERE id=$parent_item_id and lp_id=$learnpath_id";
  79. $result = Database::query($sql);
  80. if (Database::num_rows($result) == 0) {
  81. return false;
  82. }
  83. $row = Database::fetch_row($result);
  84. $display_order = $row[0];
  85. $parent_id = $row[1];
  86. // Delete the chapter itself.
  87. $sql = "DELETE FROM $tbl_learnpath_chapter WHERE (id=$parent_item_id and lp_id=$learnpath_id)";
  88. $result = Database::query($sql);
  89. // Delete items from that chapter.
  90. $sql2 = "DELETE FROM $tbl_learnpath_item WHERE parent_item_id=$parent_item_id";
  91. $result = Database::query($sql2);
  92. // Update all other chapters accordingly.
  93. $sql = "UPDATE $tbl_learnpath_item SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_id";
  94. $result = Database::query($sql);
  95. $sql = "UPDATE $tbl_learnpath_chapter SET display_order = display_order-1 WHERE display_order > $display_order AND parent_item_id = $parent_id";
  96. $result = Database::query($sql);
  97. return true;
  98. }
  99. /**
  100. * This function deletes an entire path.
  101. *
  102. * @param integer $id: the path we want to delete
  103. * @return void
  104. */
  105. function deletepath($path_id) {
  106. $tbl_learnpath_main = Database :: get_course_table(TABLE_LEARNPATH_MAIN);
  107. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  108. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  109. $sql = "DELETE FROM $tbl_learnpath_main WHERE lp_id='$path_id'";
  110. $result = Database::query($sql);
  111. //@TODO check how this function is used before uncommenting the following
  112. //also delete all elements inside that path
  113. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id = $path_id";
  114. $result = Database::query($sql);
  115. while ($row = Database::fetch_array($result)) {
  116. deletemodule($row['id']);
  117. }
  118. }
  119. /**
  120. * This function moves an item.
  121. *
  122. * @param string $direction: move the given chapter up or down
  123. * @param integer Item ID
  124. * @param integer $moduleid: the id of the chapter the element resides in
  125. * @return boolean Returns false on error
  126. * @note With this new version, the moveitem deals with items AND directories (not the base-level modules). This is a lot more complicated but is a temporary step towards new database structure as 'everything is an item'
  127. */
  128. function moveitem($direction, $id, $moduleid, $type = 'item') {
  129. global $learnpath_id;
  130. $tbl_learnpath_item = Database::get_course_table(TABLE_LEARNPATH_ITEM);
  131. $tbl_learnpath_chapter = Database::get_course_table(TABLE_LEARNPATH_CHAPTER);
  132. $tree = get_learnpath_tree($learnpath_id);
  133. $orig_order = 0;
  134. $orig_type = '';
  135. $orig_id = $id;
  136. foreach ($tree[$moduleid] as $row) {
  137. // If this is the element we want (be it a chapter or an item), get its data.
  138. if (($row['id'] == $id) && ($row['type'] == $type)) {
  139. $orig_order = $row['display_order'];
  140. $orig_type = $row['type'];
  141. break;
  142. }
  143. }
  144. $dest_order = 0;
  145. $dest_type = '';
  146. $dest_id = 0;
  147. if ($direction == 'up') {
  148. if (!empty ($tree[$moduleid][$orig_order - 1])) {
  149. $dest_order = $orig_order - 1;
  150. $dest_type = $tree[$moduleid][$orig_order - 1]['type'];
  151. $dest_id = $tree[$moduleid][$orig_order - 1]['id'];
  152. } else {
  153. return false;
  154. }
  155. } else {
  156. // Move down.
  157. if (!empty ($tree[$moduleid][$orig_order + 1])) {
  158. $dest_order = $orig_order + 1;
  159. $dest_type = $tree[$moduleid][$orig_order + 1]['type'];
  160. $dest_id = $tree[$moduleid][$orig_order + 1]['id'];
  161. } else {
  162. return false;
  163. }
  164. }
  165. $sql1 = '';
  166. $sql2 = '';
  167. if ($orig_type == 'chapter') {
  168. $sql1 = "UPDATE $tbl_learnpath_chapter SET display_order = ".$dest_order." WHERE (id=$orig_id and parent_item_id=$moduleid)";
  169. } elseif ($orig_type == 'item') {
  170. $sql1 = "UPDATE $tbl_learnpath_item SET display_order = ".$dest_order." WHERE (id=$orig_id and parent_item_id=$moduleid)";
  171. } else {
  172. return false;
  173. }
  174. if ($dest_type == 'chapter') {
  175. $sql2 = "UPDATE $tbl_learnpath_chapter SET display_order = ".$orig_order." WHERE (id='$dest_id' and parent_item_id=$moduleid)";
  176. } elseif ($dest_type == 'item') {
  177. $sql2 = "UPDATE $tbl_learnpath_item SET display_order = ".$orig_order." WHERE (id='$dest_id' and parent_item_id=$moduleid)";
  178. } else {
  179. return false;
  180. }
  181. Database::query($sql1);
  182. Database::query($sql2);
  183. }
  184. /**
  185. * This function moves a module (also called chapter or category).
  186. *
  187. * @param string $direction: move the given chapter up or down
  188. * @param integer $id: the id of the chapter we want to move
  189. * @return void
  190. */
  191. function movemodule($direction, $id) {
  192. global $learnpath_id;
  193. $tbl_learnpath_chapter = Database :: get_course_learnpath_chapter_table();
  194. if ($direction == 'up') {
  195. $sortDirection = 'DESC';
  196. } else {
  197. $sortDirection = 'ASC';
  198. }
  199. // Select all chapters of first level (parent_item_id = 0).
  200. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id=$learnpath_id AND parent_item_id = 0) ORDER BY display_order $sortDirection";
  201. $result = Database::query($sql);
  202. $previousrow = '';
  203. // See similar comment in moveitem() function.
  204. // @TODO: this only works for chapters in multi-level mode. Why not gather
  205. // this function and moveitem to keep only one multi-uses function?
  206. while ($row = Database::fetch_array($result)) {
  207. // Step 2: Performing the move (only happens when passed trhough step 1 at least once).
  208. if (!empty ($this_cat_order)) {
  209. $next_cat_order = $row['display_order'];
  210. $next_cat_id = $row['id'];
  211. $sql1 = "UPDATE $tbl_learnpath_chapter SET display_order = '$next_cat_order' WHERE (id='$this_cat_id' and lp_id=$learnpath_id)";
  212. $sql2 = "UPDATE $tbl_learnpath_chapter SET display_order = '$this_cat_order' WHERE (id='$next_cat_id' and lp_id=$learnpath_id)";
  213. Database::query($sql1);
  214. Database::query($sql2);
  215. unset ($this_cat_order);
  216. unset ($next_cat_order);
  217. unset ($next_cat_id);
  218. break;
  219. }
  220. // Step 1: Looking for the order of the row we want to move.
  221. if ($row['id'] == $id) {
  222. $this_cat_order = $row['display_order'];
  223. $this_cat_id = $id;
  224. }
  225. }
  226. }
  227. /**
  228. * Inserts a new element in a learnpath table (item or chapter)
  229. * @param string Element type ('chapter' or 'item')
  230. * @param string Chapter name
  231. * @param string Chapter description (optional)
  232. * @param integer Parent chapter ID (default: 0)
  233. * @param integer Learnpath ID
  234. * @param mixed If type 'item', then array(prereq_id=>value, prereq_..)
  235. * @return integer The new chapter ID, or false on failure
  236. * @TODO Finish this function before it is used. Currently only chapters can be added using it.
  237. * @note This function is currently never used!
  238. */
  239. function insert_item($type = 'item', $name, $chapter_description = '', $parent_id = 0, $learnpath_id = 0, $params = null) {
  240. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  241. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  242. // Getting the last order number from the chapters table, in this learnpath, for the parent chapter given.
  243. $sql = "SELECT * FROM $tbl_learnpath_chapter
  244. WHERE lp_id=$learnpath_id AND parent_item_id = $parent_id
  245. ORDER BY display_order DESC";
  246. $result = Database::query($sql);
  247. $row = Database::fetch_array($result);
  248. $last_chapter_order = $row['display_order'];
  249. // Getting the last order number of the items.
  250. $sql = "SELECT * FROM $tbl_learnpath_item
  251. WHERE parent_item_id = $parent_id
  252. ORDER BY display_order DESC";
  253. $result = Database::query($sql);
  254. $row = Database::fetch_array($result);
  255. $last_item_order = $row['display_order'];
  256. $new_order = max($last_chapter_order, $last_item_order) + 1;
  257. $course_id = api_get_course_int_id();
  258. if ($type === 'chapter') {
  259. $sql = "INSERT INTO $tbl_learnpath_chapter (c_id, lp_id, chapter_name, chapter_description, display_order)
  260. VALUES ( $course_id,
  261. '".domesticate($learnpath_id)."',
  262. '".domesticate(htmlspecialchars($name))."',
  263. '".domesticate(htmlspecialchars($chapter_description))."',
  264. $new_order )";
  265. $result = Database::query($sql);
  266. if ($result === false) {
  267. return false;
  268. }
  269. $id = Database :: insert_id();
  270. } elseif ($type === 'item') {
  271. $sql = "INSERT INTO $tbl_learnpath_item (c_id, parent_item_id, item_type, display_order) VALUES
  272. ($course_id, '".domesticate($parent_id)."','".domesticate(htmlspecialchars($type))."', $new_order )";
  273. $result = Database::query($sql);
  274. if ($result === false) {
  275. return false;
  276. }
  277. $id = Database :: insert_id();
  278. }
  279. return $id;
  280. }
  281. /**
  282. * This function returns an array with all the learnpath categories/chapters
  283. * @return array List of learnpath chapter titles
  284. */
  285. function array_learnpath_categories() {
  286. //global $tbl_learnpath_chapter;
  287. global $learnpath_id;
  288. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  289. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id=$learnpath_id) ORDER BY display_order ASC";
  290. $result = Database::query($sql);
  291. while ($row = Database::fetch_array($result)) {
  292. $array_learnpath_categories[] = array($row['id'], $row['chapter_name']);
  293. }
  294. //$array_learnpath_categories = array($array_learnpath_categories_name, $array_learnpath_categories_id);
  295. return $array_learnpath_categories;
  296. }
  297. /**
  298. * Displays the learnpath chapters(=modules,categories) and their contents.
  299. * @param integer Chapter ID to display now (enables recursive behaviour)
  300. * @param array The array as returned by get_learnpath_tree, with all the elements of a learnpath compiled and structured into the array, by chapter id
  301. * @param integer Level (the depth of the call - helps in display)
  302. * @todo eliminate all global $lang declarations, use get_lang, improve structure.
  303. * @author Denes Nagy
  304. * @author Roan Embrechts
  305. * @author Yannick Warnier <yannick.warnier@beeznest.com> - complete redesign for multi-level learnpath chapters
  306. */
  307. function display_learnpath_chapters($parent_item_id = 0, $tree = array (), $level = 0) {
  308. //error_log('New LP - In learnpath_functions::display_learnpath_chapters', 0);
  309. global $color2;
  310. global $xml_output;
  311. global $learnpath_id;
  312. $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
  313. // @todo: coding standards: Language variables are CaMMelCaSe, all other variables should use the underscoring method.
  314. $lang_move_down = get_lang('_move_down');
  315. $lang_move_up = get_lang('lang_move_up');
  316. $lang_edit_learnpath_module = get_lang('lang_edit_learnpath_module');
  317. $lang_delete_learnpath_module = get_lang('lang_delete_learnpath_module');
  318. $lang_nochapters = get_lang('lang_nochapters');
  319. $lang_prerequisites = get_lang('lang_prerequisites');
  320. $lang_prerequisites_limit = get_lang('lang_prerequisites_limit');
  321. $lang_add_learnpath_item = get_lang('lang_add_learnpath_item');
  322. $lang_add_item = get_lang('lang_add_item');
  323. $lang_title_and_desc = get_lang('lang_title_and_desc');
  324. $lang_change_order = get_lang('lang_change_order');
  325. $lang_add_prereqi = get_lang('lang_add_prereqi');
  326. $lang_add_title_and_desc = get_lang('lang_add_title_and_desc');
  327. $lang_delete = get_lang('Delete');
  328. if ($parent_item_id === 0) {
  329. // This is the first time we use the function, define the tree and display learnpath name.
  330. $tree = get_learnpath_tree($learnpath_id);
  331. $num_modules = count($tree);
  332. //$num_modules = Database::num_rows($result);
  333. if ($num_modules == 0) {
  334. // do not diplay useless information
  335. //echo "<tr><td>&nbsp;$lang_nochapters</td></tr>";
  336. } else {
  337. echo " <tr align='center' valign='top'>\n"." <td><b>&nbsp;$lang_title_and_desc </b></td>\n"." <td><b>&nbsp;$lang_add_item </b></td>\n";
  338. if (is_prereq($learnpath_id)) {
  339. echo " <td bgcolor='#ddddee'><b>&nbsp;$lang_prerequisites_limit </b></td>\n";
  340. } else {
  341. echo " <td><b>&nbsp;$lang_prerequisites </b></td>\n";
  342. }
  343. echo " <td colspan='2'><b>&nbsp;$lang_change_order </b></td><td><b>&nbsp;$lang_add_prereqi </b></td>\n"." <td><b>&nbsp;$lang_add_title_and_desc </b></td><td><b>&nbsp;$lang_delete </b></td>\n"." </tr>\n";
  344. }
  345. }
  346. $i = 1;
  347. $counter = 0;
  348. $num_modules = count($tree[$parent_item_id]);
  349. //while ($row = Database::fetch_array($result))
  350. if (isset ($tree[$parent_item_id])) {
  351. foreach ($tree[$parent_item_id] as $row) {
  352. if ($row['item_type'] === 'dokeos_chapter') {
  353. $xml_output .= "<chapter>";
  354. $xml_output .= "<chaptertitle>".$row['title']."</chaptertitle>";
  355. $xml_output .= "<chapterdescription>".$row['description']."</chapterdescription>";
  356. $counter ++;
  357. if (($counter % 2) == 0) {
  358. $oddclass = 'row_odd';
  359. } else {
  360. $oddclass = 'row_even';
  361. }
  362. //echo '<tr class="'.$oddclass.'">'."\n".' <td>'.str_repeat("&nbsp;&gt;", $level)."<img src='../img/documents.gif' alt='folder'/><a href='".api_get_self()."?lp_id=$learnpath_id&item_id={$row['id']}&action=add&type=learnpathitem&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9'><b>&nbsp;".$row['title']."</b></a>"."<br /><i><div align='justify'>&nbsp;".str_repeat("&nbsp;&nbsp;&nbsp;", $level)."</i></td>\n".' <td align="center"><a href="'.api_get_self()."?lp_id=$learnpath_id&item_id={$row['id']}&action=add&type=learnpathitem&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9"><img src='../img/0.gif' width='13' height='13' border='0' title='$lang_add_learnpath_item'></a></td>\n"." <td";
  363. echo '<tr class="'.$oddclass.'">'."\n".' <td>'.str_repeat("&nbsp;&gt;", $level)."<img src='../img/documents.gif' alt='folder'/><a href='".api_get_self()."?lp_id=$learnpath_id&parent_item_id=".$row['id']."&action=add_sub_item'><b>&nbsp;".$row['title']."</b></a>"."<br /><i><div align='justify'>&nbsp;".str_repeat("&nbsp;&nbsp;&nbsp;", $level)."</i></td>\n".' <td align="center"><a href="'.api_get_self()."?lp_id=$learnpath_id&parent_item_id=".$row['id']."&action=add_sub_item\"><img src='../img/0.gif' width='13' height='13' border='0' title='$lang_add_learnpath_item'></a></td>\n"." <td";
  364. if (is_prereq($learnpath_id)) {
  365. echo " bgcolor='#ddddee'";
  366. }
  367. echo ">".$row['prerequisite']."</td>\n";
  368. // Showing the edit, delete and move icons.
  369. if (api_is_allowed_to_edit()) {
  370. $myaction = 'move_item';
  371. if ($i < $num_modules) {
  372. // If we are still under the number of chapters in this section, show "move down".
  373. //echo " <td align=center>"."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=".$myaction."&amp;direction=down&amp;moduleid=".$parent_item_id."&amp;id=".$row['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\">"."</a></td>\n";
  374. echo " <td align=center>"."<a href='".api_get_self()."?lp_id=$learnpath_id&action=".$myaction."&direction=down&moduleid=".$parent_item_id."&id=".$row['id']."'>"."<img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\">"."</a></td>\n";
  375. } else {
  376. echo ' <td align="center">&nbsp;</td>'."\n";
  377. }
  378. if ($i > 1) {
  379. //echo ' <td align="center">'."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=".$myaction."&amp;direction=up&amp;moduleid=".$parent_item_id."&amp;id=".$row['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\">"."</a>"."</td>\n";
  380. echo ' <td align="center">'."<a href='".api_get_self()."?lp_id=$learnpath_id&action=".$myaction."&direction=up&moduleid=".$parent_item_id."&id=".$row['id']."'>"."<img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\">"."</a>"."</td>\n";
  381. } else {
  382. echo ' <td align="center">&nbsp;</td>'."\n";
  383. }
  384. echo " <td align='center'>&nbsp;</td>\n";
  385. //echo " <td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=editmodule&amp;id=".$row['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_module\">"."</a>"."</td>\n";
  386. echo " <td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&action=edititem&id=".$row['id']."'>"."<img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_module\">"."</a>"."</td>\n";
  387. //echo " <td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=deletemodule&amp;id=".$row['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9 onclick=\"javascript: return confirmation('".$row['chapter_name']."');\">"."<img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_module\">"."</a>"."</td>\n";
  388. echo " <td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&action=delete_item&id=".$row['id']."' onclick=\"javascript: return confirmation('".$row['title']."');\">"."<img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_module\">"."</a>"."</td>\n";
  389. }
  390. echo "</tr>\n";
  391. $i ++;
  392. $xml_output .= "<items>";
  393. //display_learnpath_items($row['id']);
  394. display_learnpath_chapters($row['id'], $tree, $level + 1);
  395. $xml_output .= "</items>";
  396. $xml_output .= "</chapter>";
  397. } else //if //($row['item_type'] === 'item')
  398. {
  399. $row_items = $row;
  400. echo "<tr>\n <td colspan='2' valign='top'>";
  401. //require 'resourcelinker.inc.php';
  402. display_addedresource_link_in_learnpath($row_items['item_type'], $row_items['ref'], '', $row_items['id'], 'builder', 'icon', $level);
  403. if ($row_items['description']) {
  404. echo "<div align='justify'>&nbsp;&nbsp;&nbsp;{$row_items['description']}";
  405. }
  406. echo "</td>";
  407. if (is_prereq($learnpath_id)) {
  408. echo '<td bgcolor="#EEEEFF">';
  409. } else {
  410. echo "<td>";
  411. }
  412. if (api_is_allowed_to_edit()) {
  413. if ($row_items['prerequisite'] != '') {
  414. $prereq = $row_items['prerequisite'];
  415. //if ($row_items['prereq_type'] == 'i') {
  416. // item
  417. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE id='$prereq'"; // Check if prereq has been deleted.
  418. $result_items2 = Database::query($sql_items2);
  419. $number_items2 = Database::num_rows($result_items2);
  420. if ($number_items2 == 0) {
  421. echo get_lang('PrerequisiteDeletedError');
  422. }
  423. $row_items2 = Database::fetch_array($result_items2);
  424. display_addedresource_link_in_learnpath($row_items2['item_type'], $row_items2['ref'], '', $row_items2['id'], 'builder', '', 0);
  425. if ((($row_items2['item_type'] == TOOL_QUIZ) or ($row_items2['item_type'] == 'HotPotatoes')) and ($row_items['prerequisite'])) {
  426. //echo "&nbsp;({$row_items2['title']})";
  427. }
  428. //}
  429. /*
  430. if ($row_items['prereq_type'] == 'c') {
  431. // chapter
  432. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE id='$prereq' AND item_type='dokeos_chapter'"; // Check if prereq has been deleted.
  433. $result_items2 = Database::query($sql_items2);
  434. $number_items2 = Database::num_rows($result_items2);
  435. if ($number_items2 == 0) {
  436. echo "<font color='red'>$lang_prereq_deleted_error</font>";
  437. }
  438. $row_items2 = Database::fetch_array($result_items2);
  439. echo " {$row_items2['title']}";
  440. }*/
  441. }
  442. echo "</font></td>";
  443. $xml_output .= "<element_type>".$row_items['item_type']."</element_type>";
  444. $xml_output .= "<element_id>".$row_items['item_id']."</element_id>";
  445. // Move
  446. if ($i < $num_modules) {
  447. echo "<td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=moveitem&amp;type=item&amp;direction=down&amp;moduleid=".$parent_item_id."&amp;id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\">"."</a>"."</td>";
  448. } else {
  449. echo "<td width='30' align='center'>&nbsp;</td>";
  450. }
  451. if ($i > 1) {
  452. echo "<td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=moveitem&amp;type=item&amp;direction=up&amp;moduleid=".$parent_item_id."&amp;id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\">"."</a>";
  453. } else {
  454. echo "<td width='30' align='center'>&nbsp;</td>";
  455. }
  456. echo "</td>"."<td align='center'>";
  457. // Edit prereq
  458. echo "<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=edititemprereq&amp;id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/scormpre.gif\" border=\"0\" title=\"$lang_add_prereq\">"."</a>"."</td>";
  459. // Edit
  460. echo "<td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&amp;action=edititem&amp;id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_item\">"."</a>"."</td>";
  461. // Delete
  462. echo "<td align='center'>"."<a href='".api_get_self()."?lp_id=$learnpath_id&action=deleteitem&id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>"."<img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_item\" onclick=\"javascript: return confirmation('".$row_items['item_type']."');\">"."</a>";
  463. }
  464. $i ++;
  465. echo "</td></tr>";
  466. }
  467. }
  468. }
  469. }
  470. /**
  471. * Displays all learning paths.
  472. * @return void
  473. * @todo eliminate all global $lang declarations, use get_lang, improve structure.
  474. */
  475. function display_all_learnpath() {
  476. global $tbl_tool, $color2;
  477. global $xml_output, $lang_edit_learnpath, $lang_delete_learnpath, $lang_publish, $lang_no_publish, $lang_add_learnpath_chapter_to_path;
  478. $tbl_learnpath_main = Database :: get_course_table(TABLE_LEARNPATH_MAIN);
  479. $sql = "SELECT * FROM $tbl_learnpath_main ORDER BY learnpath_name";
  480. $result = Database::query($sql);
  481. $i = 1;
  482. $num_modules = Database::num_rows($result);
  483. while ($row = Database::fetch_array($result)) {
  484. // Other grey color : #E6E6E6
  485. echo "<tr><td bgcolor=\"$color2\" width=400><b>&nbsp;";
  486. echo "<a href='learnpath_handler.php?&lp_id={$row['lp_id']}'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9>{$row['learnpath_name']}</a>";
  487. echo "</b><br /><i><div class=text align=justify>{$row['learnpath_description']}</div></i></td>";
  488. // Showing the edit, delete and publish icons.
  489. if (api_is_allowed_to_edit()) {
  490. echo "<td bgcolor=\"$color2\" align=center><a href='learnpath_handler.php?lp_id={$row['lp_id']}&action=add&type=learnpathcategory'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src='../img/0.gif' width='13' height='13' border='0' title='$lang_add_learnpath_chapter_to_path'></a></td>";
  491. echo "<td bgcolor=\"$color2\" align=center><a href='".api_get_self()."?action=editpath&id=".$row['lp_id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath\"></a></td>";
  492. echo "<td bgcolor=\"$color2\" align=center><a href='".api_get_self()."?action=deletepath&id=".$row['lp_id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath\" onclick=\"javascript: return confirmation('".$row['learnpath_name']."');\"></a></td>";
  493. $id = $row['lp_id'];
  494. $sql2 = "SELECT * FROM $tbl_learnpath_main WHERE lp_id=$id";
  495. $result2 = Database::query($sql2);
  496. $row2 = Database::fetch_array($result2);
  497. $name = $row2['learnpath_name'];
  498. $sql3 = "SELECT * FROM $tbl_tool WHERE (name=\"$name\" AND image='scormbuilder.gif')";
  499. $result3 = Database::query($sql3);
  500. $row3 = Database::fetch_array($result3);
  501. if (($row3['visibility']) == '1') {
  502. echo "<td bgcolor=\"$color2\" align=center><a href='".api_get_self()."?action=publishpath&set=i&id=".$row['lp_id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/visible.gif\" border=\"0\" title=\"$lang_no_publish\"></a></td>";
  503. } else {
  504. echo "<td bgcolor=\"$color2\" align=center><a href='".api_get_self()."?action=publishpath&set=v&id=".$row['lp_id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/invisible.gif\" border=\"0\" title=\"$lang_publish\"></a></td>";
  505. }
  506. }
  507. $i ++;
  508. echo "<tr><td>&nbsp;</td></tr>";
  509. }
  510. }
  511. /**
  512. * Displays the learning path items/steps.
  513. * @param integer Category ID
  514. * @return void
  515. * @todo eliminate all global $lang declarations, use get_lang, improve structure.
  516. */
  517. function display_learnpath_items($categoryid) {
  518. global $xml_output;
  519. global $lang_prerequisites, $lang_move_down, $lang_move_up, $lang_edit_learnpath_item, $lang_delete_learnpath_item, $learnpath_id, $lang_add_prereq, $lang_prereq_deleted_error, $lang_pre_short, $langThisItem;
  520. $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
  521. $sql_items = "SELECT * FROM $tbl_lp_item WHERE parent_item_id='$categoryid' ORDER BY display_order ASC";
  522. $result_items = Database::query($sql_items);
  523. $number_items = Database::num_rows($result_items);
  524. $i = 1;
  525. while ($row_items = Database::fetch_array($result_items)) {
  526. echo "<tr><td colspan='2' valign='top'>";
  527. display_addedresource_link_in_learnpath($row_items['item_type'], $row_items['ref'], '', $row_items['id'], 'builder', 'icon');
  528. if ($row_items['description']) {
  529. echo "<div align='justify'><font color='#999999'>&nbsp;&nbsp;&nbsp;{$row_items['description']}</font>";
  530. }
  531. echo "</td>";
  532. if (is_prereq($learnpath_id)) {
  533. echo '<td bgcolor="#EEEEFF">';
  534. } else {
  535. echo "<td>";
  536. }
  537. if (api_is_allowed_to_edit()) {
  538. //error_log('Is allowed to edit item'.$row_items['id'], 0);
  539. // TODO: Fix by adding true prerequisites parsing (and cycle through).
  540. // Over simplification here, we transform prereq_id field into prerequisite field.
  541. if ($row_items['prerequisite'] != '') {
  542. $prereq = $row_items['prerequisite'];
  543. //if ($row_items['prereq_type'] == 'i') {
  544. // item
  545. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE id='$prereq'"; // Check if prereq has been deleted.
  546. $result_items2 = Database::query($sql_items2);
  547. $number_items2 = Database::num_rows($result_items2);
  548. if ($number_items2 == 0) {
  549. echo "<font color=red>$lang_prereq_deleted_error</font>";
  550. }
  551. $row_items2 = Database::fetch_array($result_items2);
  552. display_addedresource_link_in_learnpath($row_items2['item_type'], $row_items2['ref'], '', $row_items2['id'], 'builder', '');
  553. if ((($row_items2['item_type'] == 'Exercise') or ($row_items2['item_type'] == 'HotPotatoes')) and ($row_items['prerequisites'])) {
  554. echo "&nbsp;({$row_items2['title']})";
  555. }
  556. //}
  557. /*if ($row_items['prereq_type'] == 'c') {
  558. // chapter
  559. $sql_items2 = "SELECT * FROM $tbl_learnpath_chapter WHERE id='$prereq'"; //check if prereq has been deleted
  560. $result_items2 = Database::query($sql_items2);
  561. $number_items2 = Database::num_rows($result_items2);
  562. if ($number_items2 == 0) {
  563. echo "<font color=red>$lang_prereq_deleted_error</font>";
  564. }
  565. $row_items2 = Database::fetch_array($result_items2);
  566. echo " {$row_items2['chapter_name']}";
  567. }*/
  568. }
  569. echo "</font></td>";
  570. $xml_output .= "<element_type>".$row_items['item_type']."</element_type>";
  571. $xml_output .= "<element_id>".$row_items['id']."</element_id>";
  572. // Move
  573. if ($i < $number_items) {
  574. echo "<td align='center'><a href='".api_get_self()."?lp_id=$learnpath_id&action=moveitem&direction=down&moduleid=".$categoryid."&id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/down.gif\" border=\"0\" title=\"$lang_move_down\"></a></td>";
  575. } else {
  576. echo "<td width='30' align='center'>&nbsp;</td>";
  577. }
  578. if ($i > 1) {
  579. echo "<td align='center'><a href='".api_get_self()."?lp_id=$learnpath_id&action=moveitem&direction=up&moduleid=".$categoryid."&id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/up.gif\" border=\"0\" title=\"$lang_move_up\"></a>";
  580. } else {
  581. echo "<td width='30' align='center'>&nbsp;</td>";
  582. }
  583. echo "</td><td align='center'>";
  584. // Edit prereq
  585. echo "<a href='".api_get_self()."?lp_id=$learnpath_id&action=edititemprereq&id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/scormpre.gif\" border=\"0\" title=\"$lang_add_prereq\"></a></td>";
  586. // Edit
  587. echo "<td align='center'><a href='".api_get_self()."?lp_id=$learnpath_id&action=edititem&id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/edit.gif\" border=\"0\" title=\"$lang_edit_learnpath_item\"></a></td>";
  588. // Delete
  589. echo "<td align='center'>";
  590. echo "<a href='".api_get_self()."?lp_id=$learnpath_id&action=deleteitem&id=".$row_items['id']."'&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9><img src=\"../img/delete.gif\" border=\"0\" title=\"$lang_delete_learnpath_item\" onclick=\"javascript: return confirmation('".$langThisItem."');\"></a>";
  591. }
  592. $i ++;
  593. echo "</td></tr>";
  594. }
  595. }
  596. /**
  597. * This function returns the items belonging to the chapter that contains the given item (brother items)
  598. * @param integer Item id
  599. * @return array Table containing the items
  600. */
  601. function learnpath_items($itemid) {
  602. global $xml_output;
  603. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  604. $sql_items = "SELECT parent_item_id FROM $tbl_lp_item WHERE id='$itemid'";
  605. $moduleid_sql = Database::query($sql_items);
  606. $moduleid_array = Database::fetch_array($moduleid_sql); // First row of the results.
  607. $moduleid = $moduleid_array['parent_item_id'];
  608. $sql_items = "SELECT * FROM $tbl_lp_item WHERE parent_item_id='$moduleid' ORDER BY display_order ASC";
  609. $result_items = Database::query($sql_items);
  610. $ar = Database::fetch_array($result_items);
  611. while ($ar != '') {
  612. $result[] = $ar;
  613. $ar = Database::fetch_array($result_items);
  614. }
  615. return $result;
  616. }
  617. /**
  618. * This function returns the chapters belonging to the path that contais the given chapter (brother chapters)
  619. * @param integer Learnpath id
  620. * @return array Table containing the chapters
  621. */
  622. function learnpath_chapters($learnpath_id) {
  623. global $xml_output, $learnpath_id;
  624. //$tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  625. $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
  626. $sql_items = "SELECT * FROM $tbl_lp_item WHERE lp_id='$learnpath_id' AND item_type='dokeos_chapter' ORDER BY display_order ASC";
  627. //$sql_items = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id='$learnpath_id' ORDER BY display_order ASC";
  628. $result_items = Database::query($sql_items);
  629. $ar = Database::fetch_array($result_items);
  630. while ($ar != '') {
  631. $result[] = $ar;
  632. $ar = Database::fetch_array($result_items);
  633. }
  634. return $result;
  635. }
  636. /**
  637. * This function tells if a learnpath contains items which are prerequisite to other items
  638. * @param integer Learnpath id
  639. * @return boolean True if this learnpath contains an item which is a prerequisite to something
  640. */
  641. function is_prereq($learnpath_id) {
  642. global $xml_output;
  643. $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
  644. $prereq = false;
  645. $sql_items = "SELECT * FROM $tbl_lp_item WHERE lp_id='$learnpath_id' AND parent_item_id=0 ORDER BY display_order ASC";
  646. $result_items = Database::query($sql_items);
  647. while ($ar = Database::fetch_array($result_items)) {
  648. $c = $ar['id'];
  649. $sql_items2 = "SELECT * FROM $tbl_lp_item WHERE lp_id = $learnpath_id AND parent_item_id='$c' ORDER BY display_order ASC";
  650. $result_items2 = Database::query($sql_items2);
  651. while ($ar2 = Database::fetch_array($result_items2)) {
  652. if ($ar2['prerequisite'] != '') {
  653. $prereq = true;
  654. }
  655. }
  656. }
  657. return ($prereq);
  658. }
  659. /**
  660. * This function returns the prerequisite sentence
  661. * @param integer Item ID
  662. * @return string Prerequisite warning text
  663. */
  664. function prereqcheck($id_in_path) {
  665. // 1. Initialise and import working vars.
  666. global $learnpath_id, $_user;
  667. global $langPrereqToEnter, $langPrereqTestLimit1, $langPrereqTestLimit2, $langPrereqTestLimitNow, $langPrereqFirstNeedTo, $langPrereqModuleMinimum1, $langPrereqModuleMinimum2;
  668. $tbl_learnpath_user = Database :: get_course_table(TABLE_LEARNPATH_USER);
  669. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  670. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  671. // 2. Initialise return value.
  672. $prereq = false;
  673. // 3. Get item data from the database.
  674. $sql_items = "SELECT * FROM $tbl_learnpath_item WHERE id='$id_in_path'";
  675. $result_items = Database::query($sql_items);
  676. $row = Database::fetch_array($result_items);
  677. // 4. Check prerequisite's type.
  678. if ($row['prereq_type'] == 'i') {
  679. // 4.a If prerequisite is of type 'i' (item):
  680. // 4.a.1 Get data ready for use.
  681. $id_in_path3 = $row['prereq_id'];
  682. $prereq_limit = $row['prereq_completion_limit'];
  683. // 4.a.2 Get data from the user-item relation.
  684. if ($_user['user_id'] == '') {
  685. $user_id = '0';
  686. } else {
  687. $user_id = $_user['user_id'];
  688. }
  689. $sql_items3 = "SELECT * FROM $tbl_learnpath_user WHERE (learnpath_item_id='$id_in_path3' and user_id=$user_id)";
  690. $result_items3 = Database::query($sql_items3);
  691. $row3 = Database::fetch_array($result_items3);
  692. // 4.a.3 Get the link that needs to be shown for the current item (not the prereq)
  693. $stepname = display_addedresource_link_in_learnpath($row['item_type'], $row['ref'], '', $id_in_path, 'builder', 'nolink');
  694. // This is the step we want to open.
  695. $stepname = trim($stepname); // Removing occasional line breaks and white spaces
  696. // 4.a.4 Get the prerequisite item.
  697. $sql6 = "SELECT * FROM $tbl_learnpath_item WHERE (id='$id_in_path3')";
  698. $result6 = Database::query($sql6);
  699. $row6 = Database::fetch_array($result6);
  700. // 4.a.5 Get a link to the prerequisite item.
  701. $prereqname = display_addedresource_link_in_learnpath($row6['item_type'], $row6['ref'], '', $id_in_path3, 'builder', 'nolink'); //this is the prereq of the step we want to open
  702. // 4.a.5 Initialise limit value.
  703. $limitok = true;
  704. // 4.a.6 Get prerequisite limit.
  705. if ($prereq_limit) {
  706. // 4.a.6.a If the completion limit exists.
  707. if ($row3['score'] < $prereq_limit) {
  708. // 4.a.6.a.a If the completion limit hasn't been reached, then display the corresponding message.
  709. $prereq = $langPrereqToEnter.$stepname.$langPrereqTestLimit1."$prereq_limit".$langPrereqTestLimit2.$prereqname.". (".$langPrereqTestLimitNow.$row3['score'].")";
  710. } else {
  711. // 4.a.6.a.b The completion limit has been reached. Prepare to return false (no prereq hanging).
  712. $prereq = false;
  713. }
  714. } else {
  715. // 4.a.6.b If the completion limit doesn't exist.
  716. if ($row3['status'] == 'completed' or $row3['status'] == 'passed') {
  717. // 4.a.6.b.a If the prerequisite status is 'completed'.
  718. $prereq = false;
  719. } else {
  720. // 4.a.6.b.b The prerequisite status is not 'completed', return corresponding message.
  721. $prereq = $langPrereqToEnter.$stepname.$langPrereqFirstNeedTo.$prereqname.'.';
  722. }
  723. }
  724. } elseif ($row['prereq_type'] == 'c') {
  725. // 4.b If prerequisite is of type 'c' (chapter).
  726. // 4.b.1 Get data ready to use.
  727. $id_in_path2 = $row['prereq_id'];
  728. // 4.b.2 Get all items in the prerequisite chapter.
  729. $sql_items3 = "SELECT * FROM $tbl_lp_item WHERE parent_item_id='$id_in_path2'";
  730. $result_items3 = Database::query($sql_items3);
  731. $allcompleted = true;
  732. while ($row3 = Database::fetch_array($result_items3)) {
  733. // 4.b.3 Cycle through items in the prerequisite chapter.
  734. // 4.b.3.1 Get data ready to use.
  735. $id_in_path4 = $row3['id'];
  736. if ($_user['user_id'] == '') {
  737. $user_id = '0';
  738. } else {
  739. $user_id = $_user['user_id'];
  740. }
  741. // 4.b.3.2 Get user-item relation.
  742. $sql_items4 = "SELECT * FROM $tbl_learnpath_user WHERE (learnpath_item_id='$id_in_path4' and user_id=$user_id)";
  743. $result_items4 = Database::query($sql_items4);
  744. $row4 = Database::fetch_array($result_items4);
  745. // 4.b.3.3 If any of these elements is not 'completed', the overall completion status is false.
  746. if ($row4['status'] != 'completed' and $row4['status'] != 'passed') {
  747. $allcompleted = false;
  748. }
  749. }
  750. if ($allcompleted) {
  751. // 4.b.4.a All items were completed, prepare to return that there is no prerequisite blocking the way.
  752. $prereq = false;
  753. } else {
  754. // 4.b.4.b Something was not completed. Return corresponding message.
  755. $sql5 = "SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id='$learnpath_id' and id='$id_in_path2')";
  756. $result5 = Database::query($sql5);
  757. $row5 = Database::fetch_array($result5);
  758. $prereqmodulename = trim($row5['chapter_name']);
  759. $prereq = $langPrereqModuleMinimum1.$prereqmodulename.$langPrereqModuleMinimum2;
  760. }
  761. } else {
  762. // 5. If prerequisite type undefined, no prereq.
  763. $prereq = false;
  764. }
  765. // 6. Return the message (or false if no prerequisite waiting).
  766. return ($prereq);
  767. }
  768. /**
  769. * Constructs the tree that will be used to build the learnpath structure
  770. * @params integer Learnpath_id
  771. * @return array Tree of the learnpath structure
  772. * @author Yannick Warnier <yannick.warnier@beeznest.com>
  773. * @comment This is a temporary function, which exists while the chapters and items
  774. * are still in separate tables in the database. This function gathers the data in a unique tree.
  775. */
  776. function get_learnpath_tree($learnpath_id) {
  777. //error_log('New LP - In learnpath_functions::get_learnpath_tree', 0);
  778. // Init elems
  779. //global $tbl_learnpath_item, $tbl_learnpath_chapter;
  780. /*
  781. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  782. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  783. */
  784. $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
  785. $tree = array();
  786. $chapters = array();
  787. //$chapters = array();
  788. //$chapters_by_parent = array();
  789. //$items = array();
  790. //$items_by_chapter = array();
  791. $all_items_by_chapter = array();
  792. $sql = "SELECT * FROM $tbl_lp_item WHERE lp_id = ".$learnpath_id." AND item_type='dokeos_chapter' ORDER BY display_order";
  793. //error_log('New LP - learnpath_functions - get_learnpath_tree: '.$sql,0);
  794. $res = Database::query($sql);
  795. // Format the $chapters_by_parent array so we have a suitable structure to work with.
  796. while ($row = Database::fetch_array($res)) {
  797. $chapters[] = $row;
  798. // Shouldn't be necessary (check no null value).
  799. if (empty ($row['parent_item_id'])) {
  800. $row['parent_item_id'] = 0;
  801. }
  802. //$chapters_by_parent[$row['parent_item_id']][$row['previous_item_id']] = $row;
  803. $all_items_by_chapter[$row['parent_item_id']][$row['display_order']] = $row;
  804. $all_items_by_chapter[$row['parent_item_id']][$row['display_order']]['type'] = 'dokeos_chapter';
  805. }
  806. // Now for every item in each chapter, get a suitable structure too.
  807. foreach ($chapters as $row) {
  808. // Select items from this chapter.
  809. $sql = "SELECT * FROM $tbl_lp_item WHERE lp_id = $learnpath_id AND parent_item_id = ".$row['id']." ORDER BY display_order";
  810. //error_log('New LP - learnpath_functions - get_learnpath_tree: '.$sql, 0);
  811. $res = Database::query($sql);
  812. //error_log('New LP - learnpath_functions - get_learnpath_tree: Found '.Database::num_rows($res).' results', 0);
  813. while ($myrow = Database::fetch_array($res, 'ASSOC')) {
  814. //$items[] = $myrow;
  815. //$items_by_chapter[$myrow['parent_item_id']][$myrow['display_order']] = $myrow;
  816. $all_items_by_chapter[$row['id']][$myrow['display_order']] = $myrow;
  817. $all_items_by_chapter[$row['id']][$myrow['display_order']]['type'] = 'item';
  818. }
  819. }
  820. //array_multisort($all_items_by_chapter[0], SORT_ASC, SORT_NUMERIC);
  821. foreach ($all_items_by_chapter as $key => $subrow) {
  822. ksort($all_items_by_chapter[$key]);
  823. }
  824. //all items should now be well-ordered
  825. //error_log('New LP - In get_learnpath_tree, returning '.print_r($all_items_by_chapter,true), 0);
  826. return $all_items_by_chapter;
  827. }
  828. /**
  829. * Gives a list of sequencial elements IDs for next/previous actions
  830. * @param array The elements tree as returned by get_learnpath_tree()
  831. * @param integer The chapter id to start from
  832. * @param boolean Whether to include chapters or not
  833. * @return array List of elements in the first to last order
  834. * @author Yannick Warnier <yannick.warnier@beeznest.com>
  835. */
  836. function get_ordered_items_list($tree, $chapter = 0, $include_chapters = false) {
  837. $list = array ();
  838. foreach ($tree[$chapter] as $order => $elem) {
  839. if ($elem['type'] == 'chapter') {
  840. if ($include_chapters === true) {
  841. $list[] = array ('id' => $elem['id'], 'type' => $elem['type']);
  842. }
  843. $res = get_ordered_items_list($tree, $elem['id'], $include_chapters);
  844. foreach ($res as $elem) {
  845. $list[] = $elem;
  846. }
  847. } elseif ($elem['type'] == 'item') {
  848. $list[] = array ('id' => $elem['id'], 'type' => $elem['type'], 'item_type' => $elem['item_type'], 'parent_item_id' => $elem['parent_item_id'], 'item_id' => $elem['item_id']);
  849. }
  850. }
  851. return $list;
  852. }
  853. /**
  854. * Displays the structure of a chapter recursively. Takes the result of get_learnpath_tree as argument
  855. * @param array Chapter structure
  856. * @param integer Chapter ID (start point in the tree)
  857. * @param integer Learnpath ID
  858. * @param integer User ID
  859. * @param boolean Indicates if the style is wrapped (true) or extended (false)
  860. * @param integer Level reached so far in the tree depth (enables recursive behaviour)
  861. * @return array Number of items, Number of items completed
  862. * @author Many changes by Yannick Warnier <yannick.warnier@beeznest.com>
  863. */
  864. function display_toc_chapter_contents($tree, $parent_item_id = 0, $learnpath_id, $uid, $wrap, $level = 0) {
  865. //global $tbl_learnpath_user;
  866. $tbl_learnpath_user = Database :: get_course_table(TABLE_LEARNPATH_USER);
  867. $num = 0;
  868. $num_completed = 0;
  869. foreach ($tree[$parent_item_id] as $order => $elem) {
  870. $bold = false;
  871. if (!empty ($_SESSION['cur_open']) && ($elem['id'] == $_SESSION['cur_open'])) {
  872. $bold = true;
  873. }
  874. if ($elem['type'] === 'chapter') {
  875. if ($wrap) {
  876. echo str_repeat("&nbsp;&nbsp;", $level).shorten(strip_tags($elem['chapter_name']), (35 - 3 * $level))."<br />\n";
  877. } else {
  878. echo "<tr><td colspan='3'>".str_repeat("&nbsp;&nbsp;", $level).shorten($elem['chapter_name'], (35 - 3 * $level))."</td></tr>\n";
  879. }
  880. if ($wrap) {
  881. if ($elem['chapter_description'] != '') {
  882. echo "<div class='description'>".str_repeat("&nbsp;&nbsp;", $level)."&nbsp;".shorten($elem['chapter_description'], (35 - 3 * $level))."</div>\n";
  883. }
  884. } else {
  885. if ($elem['chapter_description'] != '') {
  886. echo "<tr><td colspan='3'><div class='description'>".str_repeat("&nbsp;&nbsp;", $level)."&nbsp;".shorten($elem['chapter_description'], (35 - 3 * $level))."</div></td></tr>\n";
  887. }
  888. }
  889. list ($a, $b) = display_toc_chapter_contents($tree, $elem['id'], $learnpath_id, $uid, $wrap, $level + 1);
  890. $num += $a;
  891. $num_completed += $b;
  892. } elseif ($elem['type'] === 'item') {
  893. // If this element is an item (understand: not a directory/module).
  894. $sql0 = "SELECT * FROM $tbl_learnpath_user WHERE (user_id='".$uid."' and learnpath_item_id='".$elem['id']."' and lp_id='".$learnpath_id."')";
  895. $result0 = Database::query($sql0);
  896. $row0 = Database::fetch_array($result0);
  897. $completed = '';
  898. if (($row0['status'] == 'completed') or ($row0['status'] == 'passed')) {
  899. $completed = 'completed';
  900. $num_completed ++;
  901. }
  902. if ($wrap) {
  903. echo str_repeat("&nbsp;&nbsp;", $level)."<a name='{$elem['id']}' />\n";
  904. } else {
  905. echo "<tr><td>".str_repeat("&nbsp;&nbsp;", $level-1)."<a name='{$elem['id']}' />\n";
  906. }
  907. if ($wrap) {
  908. $icon = 'wrap';
  909. }
  910. if ($bold) {
  911. echo "<b>";
  912. }
  913. display_addedresource_link_in_learnpath($elem['item_type'], $elem['ref'], $completed, $elem['id'], 'player', $icon);
  914. if ($bold) {
  915. echo "</b>";
  916. }
  917. if ($wrap) {
  918. echo "<br />\n";
  919. } else {
  920. echo "</td></tr>\n";
  921. }
  922. $num ++;
  923. }
  924. }
  925. return array ($num, $num_completed);
  926. }
  927. /**
  928. * Returns a string to display in the tracking frame within the contents.php page (for example)
  929. * @param integer Learnpath id
  930. * @param integer Current user id
  931. * @param integer Starting chapter id
  932. * @param array Tree of elements as returned by get_learnpath_tree()
  933. * @param integer Level of recursivity we have reached
  934. * @param integer Counter of elements already displayed
  935. * @author Yannick Warnier <yannick.warnier@beeznest.com>
  936. * @note : forced display because of display_addedresource_link_in_learnpath behaviour (outputing a string would be better)
  937. */
  938. function get_tracking_table($learnpath_id, $user_id, $parent_item_id = 0, $tree = false, $level = 0, $counter = 0) {
  939. $tbl_learnpath_chapter = Database :: get_course_learnpath_chapter_table();
  940. $tbl_learnpath_item = Database :: get_course_learnpath_item_table();
  941. $tbl_learnpath_user = Database :: get_course_learnpath_user_table();
  942. //$mytable = '';
  943. $include_chapters = true;
  944. if (!is_array($tree)) {
  945. // Get a tree of the current learnpath elements.
  946. $tree = get_learnpath_tree($learnpath_id);
  947. }
  948. foreach ($tree[$parent_item_id] as $order => $elem) {
  949. if (($counter % 2) == 0) {
  950. $oddclass = 'row_odd';
  951. } else {
  952. $oddclass = 'row_even';
  953. }
  954. if ($elem['type'] == 'chapter') {
  955. if ($include_chapters === true) {
  956. //$mytable .= "<tr class='$oddclass'><td colspan = '3'>".str_repeat('&nbsp;',$level*2+2).$elem['chapter_name']."</td></tr>\n";
  957. echo "<tr class='$oddclass'><td colspan = '3'>".str_repeat('&nbsp;', $level * 2 + 2).$elem['chapter_name']."</td></tr>\n";
  958. }
  959. $counter ++;
  960. //$mytable .= get_tracking_table($learnpath_id, $user_id, $elem['id'], $tree, $level + 1, $counter );
  961. get_tracking_table($learnpath_id, $user_id, $elem['id'], $tree, $level + 1, $counter);
  962. } elseif ($elem['type'] == 'item') {
  963. $sql = "SELECT * FROM $tbl_learnpath_user "."WHERE user_id = $user_id "."AND lp_id = $learnpath_id "."AND learnpath_item_id = ".$elem['id'];
  964. $res = Database::query($sql);
  965. $myrow = Database::fetch_array($res);
  966. if (($myrow['status'] == 'completed') || ($myrow['status'] == 'passed')) {
  967. $color = 'blue';
  968. $statusmessage = get_lang('Complete');
  969. } else {
  970. $color = 'black';
  971. $statusmessage = get_lang('Incomplete');
  972. }
  973. $link = get_addedresource_link_in_learnpath($elem['item_type'], $elem['id'], $elem['item_id']);
  974. //$link = display_addedresource_link_in_learnpath($elem['item_type'], $elem['id'], $row['status'], $elem['item_id'], 'player', 'none');
  975. //$mytable .= "<tr class='$oddclass'>"
  976. echo "<tr class='$oddclass'>"."<td class='mystatus'>".str_repeat("&nbsp;", $level * 2 + 2);
  977. //."<a href='$link?SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9' target='toc'>hop</a>"
  978. display_addedresource_link_in_learnpath($elem['item_type'], $elem['ref'], $myrow['status'], $elem['id'], 'player', 'wrap');
  979. //we should also add the total score here
  980. echo "<td>"."<font color='$color'><div class='mystatus'>".$statusmessage."</div></font>"."</td>"."<td>"."<div class='mystatus' align='center'>". ($myrow['score'] == 0 ? '-' : $myrow['score'])."</div>"."</td>"."</tr>\n";
  981. $counter ++;
  982. }
  983. }
  984. //return $mytable;
  985. return true;
  986. }
  987. /**
  988. * This function returns false if there is at least one item in the path
  989. * @param Learnpath ID
  990. * @return boolean True if nothing was found, false otherwise
  991. */
  992. function is_empty($id) {
  993. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  994. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  995. $sql = "SELECT * FROM $tbl_learnpath_chapter WHERE lp_id=$id ORDER BY display_order ASC";
  996. $result = Database::query($sql);
  997. $num_modules = Database::num_rows($result);
  998. $empty = true;
  999. if ($num_modules != 0) {
  1000. while ($row = Database::fetch_array($result)) {
  1001. $num_items = 0;
  1002. $parent_item_id = $row['id'];
  1003. $sql2 = "SELECT * FROM $tbl_learnpath_item WHERE (parent_item_id=$parent_item_id) ORDER BY display_order ASC";
  1004. $result2 = Database::query($sql2);
  1005. $num_items = Database::num_rows($result2);
  1006. if ($num_items > 0) {
  1007. $empty = false;
  1008. }
  1009. }
  1010. }
  1011. return ($empty);
  1012. }
  1013. /**
  1014. * This function writes $content to $filename
  1015. * @param string Destination filename
  1016. * @param string Learnpath name
  1017. * @param integer Learnpath ID
  1018. * @param string Content to write
  1019. * @return void
  1020. */
  1021. function exporttofile($filename, $LPname, $LPid, $content) {
  1022. global $circle1_files; // This keeps all the files which are exported [0]:filename [1]:LP name.
  1023. // The $circle1_files variable is going to be used to a deep extent in the imsmanifest.xml.
  1024. global $expdir;
  1025. if (!$handle = fopen($expdir.'/'.$filename, 'w')) {
  1026. echo "Cannot open file ($filename)";
  1027. }
  1028. if (fwrite($handle, $content) === false) {
  1029. echo "Cannot write to file ($filename)";
  1030. exit;
  1031. }
  1032. fclose($handle);
  1033. $circle1_files[0][] = $filename;
  1034. $circle1_files[1][] = $LPname;
  1035. $circle1_files[2][] = $LPid;
  1036. }
  1037. /**
  1038. * This function exports the given Chamilo test
  1039. * @param integer Test ID
  1040. * @return string The test itself as an HTML string
  1041. */
  1042. function export_exercise($item_id) {
  1043. global $expdir, $_course, $_configuration, $_SESSION, $_SERVER, $language_interface, $langExerciseNotFound, $langQuestion, $langOk, $origin, $questionNum;
  1044. $exerciseId = $item_id;
  1045. require_once '../exercice/exercise.class.php';
  1046. require_once '../exercice/question.class.php';
  1047. require_once '../exercice/answer.class.php';
  1048. require_once '../exercice/exercise.lib.php';
  1049. // Answer types
  1050. define('UNIQUE_ANSWER', 1);
  1051. define('MULTIPLE_ANSWER', 2);
  1052. define('FILL_IN_BLANKS', 3);
  1053. define('MATCHING', 4);
  1054. define('FREE_ANSWER', 5);
  1055. $TBL_EXERCISES = Database :: get_course_table(TABLE_QUIZ_TEST);
  1056. /* Clears the exercise session */
  1057. if (isset ($_SESSION['objExercise'])) {
  1058. api_session_unregister('objExercise');
  1059. }
  1060. if (isset ($_SESSION['objQuestion'])) {
  1061. api_session_unregister('objQuestion');
  1062. }
  1063. if (isset ($_SESSION['objAnswer'])) {
  1064. api_session_unregister('objAnswer');
  1065. }
  1066. if (isset ($_SESSION['questionList'])) {
  1067. api_session_unregister('questionList');
  1068. }
  1069. if (isset ($_SESSION['exerciseResult'])) {
  1070. api_session_unregister('exerciseResult');
  1071. }
  1072. // If the object is not in the session:
  1073. if (!isset ($_SESSION['objExercise'])) {
  1074. // Construction of Exercise.
  1075. $objExercise = new Exercise();
  1076. $sql = "SELECT title,description,sound,type,random,active FROM $TBL_EXERCISES WHERE id='$exerciseId'";
  1077. // If the specified exercise doesn't exist or is disabled:
  1078. if (!$objExercise->read($exerciseId) || (!$objExercise->selectStatus() && !api_is_allowed_to_edit() && ($origin != 'learnpath'))) {
  1079. die($langExerciseNotFound);
  1080. }
  1081. // Saves the object into the session.
  1082. api_session_register('objExercise');
  1083. }
  1084. $exerciseTitle = $objExercise->selectTitle();
  1085. $exerciseDescription = $objExercise->selectDescription();
  1086. $exerciseSound = $objExercise->selectSound();
  1087. $randomQuestions = $objExercise->isRandom();
  1088. $exerciseType = $objExercise->selectType();
  1089. if (!isset ($_SESSION['questionList'])) {
  1090. // Selects the list of question ID.
  1091. $questionList = $randomQuestions ? $objExercise->selectRandomList() : $objExercise->selectQuestionList();
  1092. // Saves the question list into the session.
  1093. api_session_register('questionList');
  1094. }
  1095. $nbrQuestions = sizeof($questionList);
  1096. // If questionNum comes from POST and not from GET:
  1097. if (!$questionNum || $_POST['questionNum']) {
  1098. // Only used for sequential exercises (see $exerciseType).
  1099. if (!$questionNum) {
  1100. $questionNum = 1;
  1101. } else {
  1102. $questionNum ++;
  1103. }
  1104. }
  1105. $exerciseTitle = text_filter($exerciseTitle);
  1106. $test .= "<h3>".$exerciseTitle."</h3>";
  1107. if (!empty ($exerciseSound)) {
  1108. $test .= "<a href=\"../document/download.php?doc_url=%2Faudio%2F".$exerciseSound."\"&SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9 target=\"_blank\"><img src=\"../img/sound.gif\" border=\"0\" align=\"absmiddle\" alt=".get_lang("Sound")."\" /></a>";
  1109. }
  1110. $exerciseDescription = text_filter($exerciseDescription);
  1111. // Writing the .js file with to check the correct answers begin.
  1112. $scriptfilename = "Exercice".$item_id.".js";
  1113. $s = "<script type=\"text/javascript\" src='../js/".$scriptfilename."'></script>";
  1114. $test .= $s;
  1115. $content = "function evaluate() {
  1116. alert('Test evaluated.');
  1117. }
  1118. ";
  1119. if (!$handle = fopen($expdir.'/js/'.$scriptfilename, 'w')) {
  1120. echo "Cannot open file ($scriptfilename)";
  1121. }
  1122. if (fwrite($handle, $content) === false) {
  1123. echo "Cannot write to file ($filename)";
  1124. exit;
  1125. }
  1126. fclose($handle);
  1127. // Writing the .js file with to check the correct answers end.
  1128. $s = "
  1129. <p>$exerciseDescription</p>
  1130. <table width='100%' border='0' cellpadding='1' cellspacing='0'>
  1131. <form method='post' action=''><input type=\"hidden\" name=\"SQMSESSID\" value=\"36812c2dea7d8d6e708d5e6a2f09b0b9\" />
  1132. <input type='hidden' name='formSent' value='1' />
  1133. <input type='hidden' name='exerciseType' value='".$exerciseType."' />
  1134. <input type='hidden' name='questionNum' value='".$questionNum."' />
  1135. <input type='hidden' name='nbrQuestions' value='".$nbrQuestions."' />
  1136. <tr>
  1137. <td>
  1138. <table width='100%' cellpadding='4' cellspacing='2' border='0'>";
  1139. $exerciseType = 1; // So to list all questions in one page.
  1140. $test .= $s;
  1141. $i = 0;
  1142. foreach ($questionList as $questionId) {
  1143. $i ++;
  1144. // For sequential exercises.
  1145. if ($exerciseType == 2) {
  1146. // If it is not the right question, goes to the next loop iteration.
  1147. if ($questionNum != $i) {
  1148. continue;
  1149. } else {
  1150. // if the user has already answered this question:
  1151. if (isset ($exerciseResult[$questionId])) {
  1152. // Construction of the Question object.
  1153. $objQuestionTmp = new Question();
  1154. // Reads question informations.
  1155. $objQuestionTmp->read($questionId);
  1156. $questionName = $objQuestionTmp->selectTitle();
  1157. // Destruction of the Question object.
  1158. unset ($objQuestionTmp);
  1159. $test .= '<tr><td>'.get_lang('AlreadyAnswered').' &quot;'.$questionName.'&quot;</td></tr>';
  1160. break;
  1161. }
  1162. }
  1163. }
  1164. echo $s = "<tr bgcolor='#e6e6e6'><td valign='top' colspan='2'>".get_lang('Question')." ";
  1165. // Call the showQuestion() function from exercise.lib.php. This basically displays the question in a table.
  1166. $test .= showQuestion($questionId, false, 'export', $i);
  1167. } // end foreach()
  1168. $s = "</table></td></tr><tr><td><br/><input type='button' value='".$langOk."' onclick=\"javascript: evaluate(); alert('Evaluated.');\">";
  1169. $s .= "</td></tr></form></table>";
  1170. $s .= "<script type='text/javascript'> loadPage(); </script>";
  1171. $b = 2;
  1172. $test .= $s;
  1173. return ($test);
  1174. }
  1175. /**
  1176. * This function exports the given item
  1177. * @param integer Id from learnpath_items table
  1178. * @param integer Item id
  1179. * @param string Itm type
  1180. * @param boolean Shall the SCORM communications features be added? (true). Default: false.
  1181. * @return void (outputs a zip file)
  1182. * @todo Try using the SCORM communications addition (adding a button and several javascript calls to the SCORM API) elsewhere than just in the export feature, so it doesn't look like an incoherent feature
  1183. */
  1184. function exportitem($id, $item_id, $item_type, $add_scorm_communications = false) {
  1185. global $circle1_files, $expdir, $_course, $_SESSION, $GLOBALS;
  1186. global $timeNoSecFormat, $dateFormatLong, $language_interface, $langPubl, $langDone, $langThisCourseDescriptionIsEmpty, $lang_course_description, $lang_introduction_text, $_cid, $langHotPotatoesFinished, $lang_author, $lang_date, $lang_groups, $lang_users, $lang_ass, $lang_dropbox, $test, $langQuestion;
  1187. //$_course = $_SESSION['course'];
  1188. require_once api_get_path(LIBRARY_PATH).'database.lib.php';
  1189. //$tbl_learnpath_item = Database::get_course_learnpath_item_table();
  1190. $libp = api_get_path(SYS_CODE_PAH);
  1191. include_once $libp.'exercice/exercise.class.php';
  1192. include_once $libp.'question.class.php';
  1193. include_once $libp.'answer.class.php';
  1194. include_once $libp.'exercise.lib.php';
  1195. $langLasting = '';//avoid code parser warning
  1196. include_once $libp.'lang/english/announcements.inc.php'; //this line is here only for $langPubl in announcements
  1197. include_once $libp.'lang/'.$language_interface.'/announcements.inc.php'; //this line is here only for $langPubl in announcements
  1198. include_once $libp.'lang/english/agenda.inc.php'; //this line is here only for $langLasting
  1199. include_once $libp.'lang/'.$language_interface.'/agenda.inc.php'; //this line is here only for $langLasting
  1200. include_once $libp.'lang/english/course_description.inc.php'; //this line is here only for $langThisCourseDescriptionIsEmpty
  1201. include_once $libp.'lang/'.$language_interface.'/course_description.inc.php'; // -||-
  1202. include_once $libp.'lang/english/resourcelinker.inc.php';
  1203. include_once $libp.'lang/'.$language_interface.'/resourcelinker.inc.php';
  1204. include_once $libp.'lang/english/learnpath.inc.php';
  1205. include_once $libp.'lang/'.$language_interface.'/learnpath.inc.php';
  1206. include_once $libp.'lang/english/exercice.inc.php';
  1207. include_once $libp.'lang/'.$language_interface.'/exercice.inc.php';
  1208. include_once '../resourcelinker/resourcelinker.inc.php';
  1209. $LPname = display_addedresource_link_in_learnpath($item_type, $item_id, '', $id, 'builder', 'nolink');
  1210. $expcontent = "<!--
  1211. This is an exported file from Chamilo Learning Path belonging to a Scorm compliant content package.
  1212. Do not modify or replace individually.
  1213. Export module author : Denes Nagy <darkden@evk.bke.hu>
  1214. -->
  1215. ";
  1216. // Files needed for communicating with the scos.
  1217. $scocomfiles = "<script type='text/javascript' src='../js/APIWrapper.js'></script>"."<script type='text/javascript' src='../js/SCOFunctions.js'></script>";
  1218. $expcontent .= '<html><head><link rel="stylesheet" href="../css/default.css" type="text/css" media="screen,projection" />'.$scocomfiles.'</head><body>';
  1219. $donebutton .= "<script type='text/javascript'>
  1220. /* <![CDATA[ */
  1221. loadPage();
  1222. var studentName = '!';
  1223. var lmsStudentName = doLMSGetValue( 'cmi.core.student_name' );
  1224. if ( lmsStudentName != '' )
  1225. {
  1226. studentName = ' ' + lmsStudentName + '!';
  1227. }
  1228. /* ]]> */
  1229. </script>
  1230. <br /><br />
  1231. <form><input type=\"hidden\" name=\"SQMSESSID\" value=\"36812c2dea7d8d6e708d5e6a2f09b0b9\" />
  1232. <table cols='3' width='100%' align='center'>
  1233. <tr>
  1234. <td align='middle'><input type = 'button' value = ' ".$langDone." ' onclick = \"javascript: doQuit('completed');\" id='button2' name='button2'></td>
  1235. </tr>
  1236. </table>
  1237. </form>";
  1238. /**
  1239. * Switch between the different element types, namely:
  1240. * - Agenda
  1241. * - Ad_Valvas
  1242. * - Course_description
  1243. * - Document
  1244. * - Introduction_text
  1245. * - HotPotatoes
  1246. * - Exercise
  1247. * - Post
  1248. * - Forum ]
  1249. * - Thread ]
  1250. * - Dropbox ]
  1251. * - Assignments ] These elements are all replaced by a simple message in the exported document.
  1252. * - Groups ]
  1253. * - Users ]
  1254. * - Link _self
  1255. * - Link _blank
  1256. */
  1257. switch ($item_type) {
  1258. // AGENDA BEGIN
  1259. case 'Agenda':
  1260. // 1. Get agenda event data from the database table.
  1261. $TABLEAGENDA = Database :: get_course_table(TABLE_AGENDA);
  1262. $sql = "SELECT * FROM ".$TABLEAGENDA." where (id=$item_id)";
  1263. $result = Database::query($sql);
  1264. // 2. Prepare table output.
  1265. $expcontent .= "<table class=\"data_table\" >";
  1266. $barreMois = '';
  1267. // 3. For each event corresponding to this agenda, do the following:
  1268. while ($myrow = Database::fetch_array($result)) {
  1269. $start_date_local = api_get_local_time($myrow['start_date'], null, date_default_timezone_get());
  1270. //3.1 Make the blue month bar appear only once.
  1271. if ($barreMois != api_format_date($start_date_local, "%m")) {
  1272. // 3.1.1 Update the check value for the month bar.
  1273. $barreMois = api_format_date($start_date_local, "%m");
  1274. // 3.1.2 Display the month bar.
  1275. $expcontent .= "<tr><td id=\"title\" colspan=\"2\" class=\"month\" valign=\"top\">".api_format_date($start_date_local, "%B %Y")."</td></tr>";
  1276. }
  1277. // 3.2 Display the agenda items (of this month): the date, hour and title.
  1278. $db_date = (int) api_format_date($start_date_local, "%d");
  1279. if ($_GET['day'] != $db_date) {
  1280. // 3.2.1.a If the day given in the URL (might not be set) is different from this element's day, use style 'data'.
  1281. $expcontent .= "<tr><td class=\"data\" colspan='2'>";
  1282. } else {
  1283. // 3.2.1.b Else (same day) use style 'datanow'.
  1284. $expcontent .= "<tr><td class=\"datanow\" colspan='2'>";
  1285. }
  1286. // 3.2.2 Mark an anchor for this date.
  1287. $expcontent .= "<a name=\"".$db_date."\"></a>"; // anchoring
  1288. // 3.2.3 Write the date and time of this event to the export string.
  1289. $expcontent .= api_format_date($start_date_local);
  1290. // 3.2.4 If a duration is set, write it, otherwise ignore.
  1291. if ($myrow['duration'] == '') {
  1292. $expcontent .= "<br />";
  1293. } else {
  1294. $expcontent .= " / ".$langLasting." ".$myrow['duration']."<br />"; //langLasting comes from lang/x/agenda.inc.php
  1295. }
  1296. // 3.2.5 Write the title.
  1297. $expcontent .= $myrow['title'];
  1298. $expcontent .= "</td></tr>";
  1299. // 3.2.6 Prepare the content of the agenda item.
  1300. $content = $myrow['content'];
  1301. // 3.2.7 Make clickable???
  1302. $content = make_clickable($content);
  1303. $content = text_filter($content);
  1304. // 3.2.8 Write the prepared content to the export string.
  1305. $expcontent .= "<tr><td class=\"text\" colspan='2'>";
  1306. $expcontent .= $content;
  1307. $expcontent .= "</td></tr>";
  1308. // Displaying the agenda item of this month: the added resources.
  1309. // This part is not included into LP export.
  1310. /*if (check_added_resources("Agenda", $myrow['id'])) {
  1311. $content.= "<tr><td colspan='2'>";
  1312. $content.= "<i>".get_lang('AddedResources')."</i><br />";
  1313. display_added_resources("Agenda", $myrow['id']);
  1314. $content.= "</td></tr>";
  1315. }*/
  1316. }
  1317. // 4. Finish the export string.
  1318. $expcontent .= "<tr></table>";
  1319. break;
  1320. // ANNOUNCEMENT BEGIN
  1321. case 'Ad_Valvas':
  1322. // 1. Get the announcement data from the database
  1323. $tbl_announcement = Database::get_course_table(TABLE_ANNOUNCEMENT);
  1324. $sql = "SELECT * FROM $tbl_announcement where id='$item_id'";
  1325. $result = Database::query($sql);
  1326. // 2. Initialise export string
  1327. $expcontent .= "<table class=\"data_table\">";
  1328. // 3. For each announcement matching the query
  1329. while ($myrow = Database::fetch_array($result)) {
  1330. // 3.1 Get the __ field data.
  1331. $content = $myrow[1];
  1332. //$content = nl2br($content);
  1333. // 3.2 Prepare the data for export.
  1334. $content = make_clickable($content);
  1335. $content = text_filter($content);
  1336. // 3.3 Get a UNIX(?<-mktime) Timestamp of the end_date for this announcement.
  1337. $last_post_datetime = $myrow['end_date']; // post time format datetime de mysql
  1338. list ($last_post_date, $last_post_time) = split(' ', $last_post_datetime);
  1339. list ($year, $month, $day) = explode('-', $last_post_date);
  1340. list ($hour, $min) = explode(':', $last_post_time);
  1341. $announceDate = mktime($hour, $min, 0, $month, $day, $year);
  1342. // 3.4 Compare the end date to the last login date of the user (mark it in red if he has not already read it).
  1343. if ($announceDate > $_SESSION['user_last_login_datetime']) {
  1344. $colorBecauseNew = " color=\"red\" ";
  1345. } else {
  1346. $colorBecauseNew = ' ';
  1347. }
  1348. // 3.5 Write this content to the export string (formatted HTML array).
  1349. $expcontent .= "<tr>\n"."<td class=\"cell_header\">\n"."<font ".$colorBecauseNew.">".$langPubl." : ".api_convert_and_format_date($last_post_datetime, null, date_default_timezone_get())."</font>\n"."</td>\n"."</tr>\n"."<tr>\n"."<td>\n".$content."</td>\n"."</tr>\n";
  1350. } // while loop
  1351. // 4 Finish the export string.
  1352. $expcontent .= "</table>";
  1353. break;
  1354. // Course_description BEGIN
  1355. case 'Course_description':
  1356. // 1. Get course description data from database.
  1357. $tbl_course_description = Database :: get_course_table(TABLE_COURSE_DESCRIPTION);
  1358. $result = Database::query("SELECT id, title, content FROM ".$tbl_course_description." ORDER BY id");
  1359. // 2. Check this element.
  1360. if (Database::num_rows($result)) {
  1361. // 2.a This course has one (or more) description in the database.
  1362. $expcontent .= "<hr noshade=\"noshade\" size=\"1\" />";
  1363. // 2.a.1 For each description available for this course.
  1364. while ($row = Database::fetch_array($result)) {
  1365. // 2.a.1.1 Write title to export string.
  1366. $expcontent .= "<h4>".$row['title']."</h4>";
  1367. // 2.a.1.2 Prepare content.
  1368. $content = make_clickable(nl2br($row['content']));
  1369. $content = text_filter($content);
  1370. // 2.a.1.3 Write content to the export string.
  1371. $expcontent .= $content;
  1372. }
  1373. } else {
  1374. // 2.b This course has no description available.
  1375. $expcontent .= "<br /><h4>$langThisCourseDescriptionIsEmpty</h4>";
  1376. }
  1377. break;
  1378. // DOCUMENT BEGIN
  1379. case 'Document':
  1380. // 1. Get the document data from the database.
  1381. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1382. $sql_query = "SELECT * FROM $tbl_document WHERE id=$item_id";
  1383. $sql_result = Database::query($sql_query);
  1384. $myrow = Database::fetch_array($sql_result);
  1385. // 2. Get the origin path of the document to treat it internally.
  1386. $orig = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.$myrow['path'];
  1387. // 3. Make some kind of strange transformation to get the destination filepath ???
  1388. $pathname = explode('/', $myrow['path']);
  1389. $last = count($pathname) - 1;
  1390. $filename = 'data/'.$filename.$pathname[$last];
  1391. $copyneeded = true;
  1392. // Html files do not need to be copied as the ok button is inserted into them,
  1393. // so don't copy directly.
  1394. $extension = explode('.', $pathname[$last]);
  1395. // This old condition was WRONG for names like design.html.old. Instead, we now get the extension
  1396. // by using preg_match to match case-insensitive (probably faster than 4 conditions).
  1397. //if (($extension[1]=='htm') or ($extension[1]=='html') or ($extension[1]=='HTM') or ($extension[1]=='HTML')) {
  1398. // 4. Check the file extension.
  1399. if (preg_match('/.*(\.htm(l)?)$/i', $pathname[$last])) {
  1400. // 4.a If this file ends with ".htm(l)", we consider it's an HTML file.
  1401. // src tag check begin
  1402. // We now check if there is any src attribute in htm(l) files, if yes, we have to also export
  1403. // the target file (swf, mp3, video,...) of that src tag.
  1404. // In case of absolute links (http://) this is not neccessary, but makes no error.
  1405. // However still missing : relative links case with subdirs -> the necessary dirs are not created in the exported package.
  1406. // 4.a.1 Get the file contents into $file.
  1407. $file = file_get_contents($orig);
  1408. // 4.a.2 Get all the src links in this file.
  1409. //preg_match_all("|((?i)src=\".*\" )|U",$file,$match);
  1410. $match = GetSRCTags($orig);
  1411. // 4.a.3 For each src tag found, do the following:
  1412. for ($i = 0; $i < count($match); $i ++) {
  1413. // 4.a.3.1 Get the tag (split from the key).
  1414. list ($key, $srctag) = each($match);
  1415. $src = $srctag;
  1416. // 4.a.3.2 Check the link kind (web or absolute/relative).
  1417. if (stristr($src, 'http') === false) {
  1418. // 4.a.3.2.a Do something only if relative (otherwise the user will be able to see it too anyway).
  1419. // 4.a.3.2.a.1 Get a proper URL and remove all './'
  1420. $src = urldecode($src); //mp3
  1421. //$src=str_replace('./','',$src);
  1422. $src = preg_replace('/^\.\//', '', $src);
  1423. // 4.a.3.2.a.2 Remove the player link from the URL (only use the mp3 file).
  1424. $src = str_replace('mp3player.swf?son=', '', $src); //mp3
  1425. // 4.a.3.2.a.3 Remove funny link parts.
  1426. $src = str_replace('?0', '', $src); //mp3
  1427. // The previous lines are used when creating docs with Chamilo Document tool's htmlarea
  1428. // Rows marked by 'mp3' are needed because the mp3 plugin inserts the swf-mp3 links in a very strange way
  1429. // and we can decode them with those 3 lines, hoping this will not cause errors in case of other htmls,
  1430. // created by any other software.
  1431. // 4.a.3.2.a.4 Prepare source and destination paths.
  1432. $source = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.dirname($myrow['path']).'/'.$src;
  1433. $dest = $expdir.'/data/'.$src;
  1434. //CopyNCreate($source,$dest);
  1435. rcopy($source, $dest);
  1436. } //else...?
  1437. }
  1438. // src tag check end
  1439. // sco communication insertion begin
  1440. // 4.a.4 If we want to add SCORM actions and a "Done" button, do the following:
  1441. if ($add_scorm_communications === true) {
  1442. if ($bodyclose = strpos($file, '</body>')) {
  1443. $file = substr_replace($file, $scocomfiles.$donebutton, $bodyclose, 7);
  1444. } elseif ($htmlclose = strpos($file, '</html>')) {
  1445. $file = substr_replace($file, $scocomfiles.$donebutton, $htmlclose, 7);
  1446. $file .= '</html>';
  1447. } else {
  1448. $file .= $scocomfiles.$donebutton;
  1449. }
  1450. } //sco communication insertion end
  1451. // 4.a.5 Replace the file's name by adding the element's ID before htm.
  1452. // This will not work with uppercase HTML though. Maybe use the preg_replace syntax proposed...
  1453. $filename = str_replace('.htm', $id.'.htm', $filename);
  1454. //$filename=preg_replace('/.*(\.htm(l)?)$/i',$id.$1,$filename);
  1455. // 4.a.6 Export these contents to a file and set the circle1_files array for later reuse.
  1456. exporttofile($filename, $LPname, $id, $file);
  1457. // The file has been copied, so ask not to copy it again.
  1458. $copyneeded = false;
  1459. } //if (htm(l) files) end
  1460. // 5. If we still need to copy the file (e.g. it was not an HTML file), then copy and set circle1_files for later reuse.
  1461. if ($copyneeded) {
  1462. copy($orig, $expdir.'/'.$filename);
  1463. $circle1_files[0][] = $filename;
  1464. $circle1_files[1][] = $LPname;
  1465. $circle1_files[2][] = $id;
  1466. }
  1467. //echo $orig;
  1468. return;
  1469. // Introduction_text BEGIN
  1470. case 'Introduction_text':
  1471. // 1 Get the introduction text data from the database.
  1472. $TBL_INTRO = Database :: get_course_tool_intro_table();
  1473. // Modified by Ivan Tcholakov, 15-SEP-2008.
  1474. //$result = Database::query("SELECT * FROM ".$TBL_INTRO." WHERE id=1");
  1475. $result = Database::query("SELECT * FROM ".$TBL_INTRO." WHERE id='course_homepage'");
  1476. //
  1477. $myrow = Database::fetch_array($result);
  1478. $intro = $myrow['intro_text'];
  1479. // 2 Write introduction text to the export string.
  1480. $expcontent .= '<br />'.$intro;
  1481. break;
  1482. // HotPotatoes BEGIN
  1483. case 'HotPotatoes':
  1484. // 1. Get HotPotatoes data from the document table.
  1485. $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
  1486. $result = Database::query("SELECT * FROM $tbl_document WHERE id=$item_id");
  1487. $myrow = Database::fetch_array($result);
  1488. // 2. Get the document path.
  1489. $testfile = api_get_path(SYS_COURSE_PATH).$_course['path']."/document".urldecode($myrow['path']);
  1490. // 3. Get the document contents into a string.
  1491. $content = file_get_contents($testfile);
  1492. // 4. Get the document filename (just the file, no path) - would probably be better to use PHP native function.
  1493. $pathname = explode('/', $myrow['path']);
  1494. $last = count($pathname) - 1;
  1495. $filename = 'data/'.$filename.$pathname[$last];
  1496. // 4beta - get all linked files and copy them (procedure copied from documents type).
  1497. // Get all the src links in this file.
  1498. $match = GetSRCTags($testfile);
  1499. // For each src tag found, do the following:
  1500. foreach ($match as $src) {
  1501. //Check the link kind (web or absolute/relative)
  1502. if (stristr($src, 'http') === false) {
  1503. // Do something only if relative (otherwise the user will be able to see it too anyway).
  1504. // Get a proper URL and remove all './'
  1505. $src = urldecode($src); //mp3
  1506. $src = str_replace('./', '', $src);
  1507. // Remove the player link from the URL (only use the mp3 file).
  1508. $src = str_replace('mp3player.swf?son=', '', $src); //mp3
  1509. // Remove funny link parts.
  1510. $src = str_replace('?0', '', $src); //mp3
  1511. // The previous lines are used when creating docs with Chamilo Document tool's htmlarea.
  1512. // Rows marked by 'mp3' are needed because the mp3 plugin inserts the swf-mp3 links in a very strange way
  1513. // and we can decode them with those 3 lines, hoping this will not cause errors in case of other htmls,
  1514. // created by any other software.
  1515. // Prepare source and destination paths.
  1516. $source = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document'.dirname($myrow['path']).'/'.$src;
  1517. $dest = $expdir.'/data/'.$src;
  1518. //CopyNCreate($source,$dest);
  1519. rcopy($source, $dest);
  1520. } //else...?
  1521. }
  1522. // 5. Prepare the special "close window" for this test.
  1523. $closewindow = "<html><head><link rel='stylesheet' type='text/css' href='../css/default.css'></head><body>"."<br /><div class='message'>$langHotPotatoesFinished</div></body></html>";
  1524. // Finish is the function of HP to save scores, we insert our scorm function calls to its beginning
  1525. // 'Score' is the variable that tracks the score in HP tests.
  1526. // 6.
  1527. $mit = "function Finish(){";
  1528. $js_content = "var SaveScoreVariable = 0; // This variable is included by Chamilo LP export\n"."function mySaveScore() // This function is included by Chamilo LP export\n"."{\n"." if (SaveScoreVariable==0)\n"." {\n"." SaveScoreVariable = 1;\n".
  1529. //the following function are implemented in SCOFunctions.js
  1530. " exitPageStatus = true;\n"." computeTime();\n"." doLMSSetValue( 'cmi.core.score.raw', Score );\n"." doLMSSetValue( 'cmi.core.lesson_status', 'completed' );\n"." doLMSCommit();\n"." doLMSFinish();\n".
  1531. // " document.write('".$closewindow."');\n".
  1532. //if you insert the previous row, the test does not appear correctly !!!!
  1533. " }\n"."}\n"."function Finish(){\n"." mySaveScore();";
  1534. $start = "<script type='text/javascript'> loadPage(); </script>";
  1535. // 7. Replace the current MIT function call by our set of functions. In clear, transform HP to SCORM.
  1536. $content = str_replace($mit, $js_content, $content);
  1537. // 8. Finally, add the API loading calls (although that might have been done first).
  1538. $content = str_replace("</script>", "</script>".$scocomfiles.$start, $content);
  1539. // 9. Change the filename to add the database ID and export to a new file,
  1540. // setting the circle1_files array for later reuse.
  1541. $filename = str_replace('.htm', $id.'.htm', $filename);
  1542. exporttofile($filename, $LPname, $id, $content);
  1543. return;
  1544. // Chamilo test BEGIN
  1545. case 'Exercise':
  1546. //1 Use the export_exercise() function to do the job of constructing the question's HTML table
  1547. $expcontent .= export_exercise($item_id);
  1548. break;
  1549. // POST BEGIN
  1550. case 'Post':
  1551. // 1. Get the forum post data from the database.
  1552. $tbl_posts =Database::get_course_table(TABLE_FORUM_POST);
  1553. $tbl_posts_text =Database::get_course_table(TOOL_FORUM_POST_TEXT_TABLE);
  1554. $result = Database::query("SELECT * FROM $tbl_posts where post_id=$item_id");
  1555. $myrow = Database::fetch_array($result);
  1556. // Grabbing the title of the post.
  1557. $sql_titel = "SELECT * FROM $tbl_posts_text WHERE post_id=".$myrow['post_id'];
  1558. $result_titel = Database::query($sql_titel);
  1559. $myrow_titel = Database::fetch_array($result_titel);
  1560. $posternom = $myrow['nom'];
  1561. $posterprenom = $myrow['prenom'];
  1562. $posttime = $myrow['post_time'];
  1563. $posttext = $myrow_titel['post_text'];
  1564. $posttitle = $myrow_titel['post_title'];
  1565. $posttext = str_replace('"', "'", $posttext);
  1566. //2 Export contents as an HTML table
  1567. $expcontent .= "<table border='0' cellpadding='3' cellspacing='1' width='100%'>
  1568. <tr>
  1569. <td colspan='2' bgcolor='#e6e6e6'><b>$posttitle</b><br />$posttext</td>
  1570. </tr>
  1571. <tr>
  1572. <td colspan='2'></td>
  1573. </tr>
  1574. <tr>
  1575. <td bgcolor='#cccccc' align='left'>$lang_author : $posterprenom $posternom</td>
  1576. <td align='right' bgcolor='#cccccc'>$lang_date : $posttime</td>
  1577. </tr>
  1578. <tr><td colspan='2' height='10'></td></tr>
  1579. </table>";
  1580. break;
  1581. // NOT IMPLEMENTED ITEMS BEGIN
  1582. case 'Forum':
  1583. case 'Thread':
  1584. case 'Dropbox':
  1585. case 'Assignments':
  1586. case 'Groups':
  1587. case 'Users':
  1588. // 1. Instead of building something, put an info message.
  1589. $langItemMissing1 = "There was a ";
  1590. $langItemMissing2 = "page (step) here in the original Chamilo Learning Path.";
  1591. $expcontent .= "<div class='message'>$langItemMissing1 $item_type $langItemMissing2</div>";
  1592. break;
  1593. // Link BEGIN
  1594. case 'Link _self':
  1595. case 'Link _blank':
  1596. // 1. Get the link data from the database.
  1597. $TABLETOOLLINK = Database :: get_course_link_table();
  1598. $result = Database::query("SELECT * FROM $TABLETOOLLINK WHERE id=$item_id");
  1599. $myrow = Database::fetch_array($result);
  1600. $thelink = $myrow['url'];
  1601. // 2. Check the link type (open in blank page or in current page).
  1602. if ($item_type == 'Link _blank')
  1603. {
  1604. $target = '_blank';
  1605. }
  1606. // 3. Write the link to the export string.
  1607. $expcontent .= "<a href='$thelink?SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9' target='".$target."'>$LPname</a>";
  1608. // 4. Change the element type for later changes (this is lost, however, so useless here).
  1609. $item_type = 'Link'; // To put this to the filename.
  1610. //$LPname="<a href='$thelink?SQMSESSID=36812c2dea7d8d6e708d5e6a2f09b0b9' target=".$target.">$LPname</a>";
  1611. // I am still not sure about Link export : to export them as files or they can appear in the TOC at once ?
  1612. // To enable the second possibility, unrem the row $LPname=...
  1613. break;
  1614. }
  1615. // Now we add the Done button and the initialize function : loadpage()
  1616. // not in the case of Documents, HotP
  1617. if ($item_type != 'Exercise' and ($add_scorm_communications === true)) {
  1618. $expcontent .= $donebutton;
  1619. }
  1620. // End the export string with valid HTML tags.
  1621. $expcontent .= "</body></html>";
  1622. // Prepare new file name.
  1623. $filename = $item_type.$id.".htm";
  1624. // Write the export content to the new file.
  1625. exporttofile('data/'.$filename, $LPname, $id, $expcontent);
  1626. }
  1627. /**
  1628. * This function exports the given item's description into a separate file
  1629. * @param integer Item id
  1630. * @param string Item type
  1631. * @param string Description
  1632. * @return void
  1633. */
  1634. function exportdescription($id, $item_type, $description) {
  1635. global $expdir;
  1636. $filename = $item_type.$id.'.desc';
  1637. $expcontent = $description;
  1638. exporttofile($expdir.$filename, 'description_of_'.$item_type.$id, 'description_of_item_'.$id, $expcontent);
  1639. }
  1640. /**
  1641. * This function deletes an entire directory
  1642. * @param string The directory path
  1643. * @return boolean True on success, false on failure
  1644. */
  1645. function deldir($dir) {
  1646. $dh = opendir($dir);
  1647. while ($file = readdir($dh)) {
  1648. if ($file != '.' && $file != '..') {
  1649. $fullpath = $dir.'/'.$file;
  1650. if (!is_dir($fullpath)) {
  1651. unlink($fullpath);
  1652. } else {
  1653. deldir($fullpath);
  1654. }
  1655. }
  1656. }
  1657. closedir($dh);
  1658. if (rmdir($dir)) {
  1659. return true;
  1660. }
  1661. return false;
  1662. }
  1663. /**
  1664. * This functions exports the given path. This is the opener function, which is called first
  1665. * @deprecated this function is only called in the newscorm/scorm_admin.php which is deprecated
  1666. * @param integer The path id
  1667. * @return resource A zip file, containing a hopefully Scorm compliant course made from the LP. This might happen when we don't actually exit the function first :-)
  1668. */
  1669. function exportpath($learnpath_id) {
  1670. // 1. Initialise variables.
  1671. global $_course, $circle1_files, $LPnamesafe, $LPname, $expdir;
  1672. //$tbl_learnpath_main, $tbl_learnpath_chapter, $tbl_learnpath_item,
  1673. $tbl_learnpath_main = Database :: get_course_table(TABLE_LEARNPATH_MAIN);
  1674. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  1675. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  1676. // Where applicable, add a scorm "Done" button at the end of all contents.
  1677. $add_scorm_button = true;
  1678. // 2. Get the name of the LP.
  1679. include_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php';
  1680. $sql = "SELECT * FROM $tbl_learnpath_main WHERE (lp_id=$learnpath_id)";
  1681. $result = Database::query($sql);
  1682. $row = Database::fetch_array($result);
  1683. $LPname = $row['learnpath_name'];
  1684. $LPnamesafe = replace_dangerous_char($LPname, 'strict');
  1685. // 3. Get a temporary dir for creating the zip file.
  1686. $expdir = api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/".$LPnamesafe;
  1687. $fromdir = '../scorm/export/'; //this dir contains some standard files
  1688. deldir($expdir); // Make sure the temp dir is cleared.
  1689. mkdir($expdir, api_get_permissions_for_new_directories());
  1690. mkdir($expdir.'/css', api_get_permissions_for_new_directories());
  1691. mkdir($expdir.'/data', api_get_permissions_for_new_directories());
  1692. mkdir($expdir.'/js', api_get_permissions_for_new_directories());
  1693. mkdir($expdir.'/data/images', api_get_permissions_for_new_directories());
  1694. mkdir($expdir.'/data/audio', api_get_permissions_for_new_directories());
  1695. mkdir($expdir.'/data/videos', api_get_permissions_for_new_directories());
  1696. $circle1 = array( // This array contains the types of elements we want to export.
  1697. 'Chapter', 'Agenda', 'Ad_Valvas', 'Course_description', 'Document', 'Introduction_text', 'Link _self', 'Link _blank', 'Forum', 'Thread', 'Post', 'Exercise', 'HotPotatoes', 'Assignments', 'Dropbox', 'Users', 'Groups');
  1698. //$circle2 = array('');
  1699. // 4. Get the first level chapters - YW added parent_item_id condition for multi-level paths.
  1700. $sql = "SELECT * FROM $tbl_learnpath_chapter
  1701. WHERE (lp_id=$learnpath_id and parent_item_id=0)
  1702. ORDER BY display_order ASC";
  1703. // To get all the elements, we should use the function that builds the table of content get_learnpath_tree.
  1704. //WHERE (lp_id=$learnpath_id)
  1705. //ORDER BY parent_item_id, display_order ASC";
  1706. $result = Database::query($sql);
  1707. // 5. export the items listed in Circle I one by one.
  1708. while ($row = Database::fetch_array($result)) {
  1709. // 5.1. Get items data from the database for this chapter.
  1710. $parent_item_id = $row['id'];
  1711. //$sql2a = "SELECT * FROM $tbl_learnpath_chapter WHERE (lp_id=$learnpath_id and parent_item_id=$parent_item_id) ORDER BY display_order ASC";
  1712. //$result2a = Database::query($sql);
  1713. $sql2b = "SELECT * FROM $tbl_learnpath_item WHERE (parent_item_id=$parent_item_id) ORDER BY display_order ASC";
  1714. $result2b = Database::query($sql2b);
  1715. while ($row2 = Database::fetch_array($result2b)) {
  1716. // 5.1.1 Check if the element is in the circle1 array.
  1717. $tobeexported = false;
  1718. for ($i = 0; $i < count($circle1) && !$tobeexported; $i ++) {
  1719. // If the type is found in the circle1 array, ask for export.
  1720. if ($circle1[$i] == $row2['item_type']) {
  1721. $tobeexported = true;
  1722. }
  1723. }
  1724. // 5.1.2 If applicable, export the item to an HTML file (see exportitem function for more details).
  1725. if ($tobeexported) {
  1726. exportitem($row2['id'], $row2['item_id'], $row2['item_type'], $add_scorm_button);
  1727. /*if ($row2['description']) { // Put the description of items to a separate file (.desc).
  1728. exportdescription($row2['id'], $row2['item_type'], $row2['description']);
  1729. }*/
  1730. }
  1731. } //end of items loop
  1732. } //end of first-level chapters loop
  1733. // 6. Export the other necceassary files.
  1734. $filename = 'default.css';
  1735. copy('../css/'.$filename, $expdir.'/css/'.$filename);
  1736. $filename = 'ims_xml.xsd';
  1737. copy($fromdir.$filename, $expdir.'/'.$filename);
  1738. $filename = 'imscp_v1p1.xsd';
  1739. copy($fromdir.$filename, $expdir.'/'.$filename);
  1740. $filename = 'imsmd_v1p2.xsd';
  1741. copy($fromdir.$filename, $expdir.'/'.$filename);
  1742. $filename = 'APIWrapper.js';
  1743. copy($fromdir.$filename, $expdir.'/js/'.$filename);
  1744. $filename = 'SCOFunctions.js';
  1745. copy($fromdir.$filename, $expdir.'/js/'.$filename);
  1746. // In case circle1_files is not defined, build it
  1747. //$circle1_files
  1748. // 7. Create imsmanifest.xml.
  1749. createimsmanifest($circle1_files, $learnpath_id);
  1750. // 8. Put the files in the exportdir into a zip and force download.
  1751. include_once api_get_path(LIBRARY_PATH).'pclzip/pclzip.lib.php';
  1752. // Create zipfile of given directory.
  1753. $zip_folder = new PclZip(api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/".$LPnamesafe.".zip");
  1754. $zip_folder->create(api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/".$LPnamesafe."/", PCLZIP_OPT_REMOVE_PATH, api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/");
  1755. //api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/".$LPnamesafe); // whitout folder
  1756. // Modified by imandak80
  1757. /* copy(api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/".$LPnamesafe.".zip",
  1758. api_get_path(SYS_COURSE_PATH).$_course['path']."/document/".$LPnamesafe.".zip");
  1759. */
  1760. $zipfoldername = api_get_path(SYS_COURSE_PATH).$_course['path']."/temp/".$LPnamesafe;
  1761. $zipfilename = $zipfoldername.".zip";
  1762. DocumentManager :: file_send_for_download($zipfilename, false, basename($LPnamesafe.".zip"));
  1763. // 9. Delete the temporary zip file and directory.
  1764. include_once api_get_path(LIBRARY_PATH).'fileManage.lib.php';
  1765. // in fileManage.lib.php
  1766. my_delete($zipfilename);
  1767. my_delete($zipfoldername);
  1768. //exit;
  1769. // 10. Return the circle_files hash (array).
  1770. return ($circle1_files); //has been used before...
  1771. }
  1772. /**
  1773. * Export SCORM content into a zip file
  1774. *
  1775. * Basically, all this function does is put the scorm directory back into a zip file (like the one
  1776. * that was most probably used to import the course at first)
  1777. * @deprecated this function is only called in the newscorm/scorm_admin.php which is deprecated
  1778. *
  1779. * @param string Name of the SCORM path (or the directory under which it resides)
  1780. * @param array Not used right now. Should replace the use of global $_course
  1781. * @return void
  1782. * @author imandak80
  1783. */
  1784. function exportSCORM($scormname, $course) {
  1785. global $_course;
  1786. // Initialize.
  1787. $tmpname = api_get_path(SYS_COURSE_PATH).$_course['path'].'/scorm';
  1788. $zipfoldername = $tmpname.$scormname;
  1789. $zipfilename = $zipfoldername.'.zip';
  1790. // Create zipfile of given directory.
  1791. include_once api_get_path(LIBRARY_PATH).'pclzip/pclzip.lib.php';
  1792. $zip_folder = new PclZip($zipfilename);
  1793. $list = 1;
  1794. //$list = $zip_folder->create($zipfoldername.'/',PCLZIP_OPT_REMOVE_PATH,$tmpname.$scormname."/"); // whitout folder
  1795. $list = $zip_folder->create($zipfoldername.'/', PCLZIP_OPT_REMOVE_PATH, $tmpname);
  1796. if ($list == 0) {
  1797. //echo "Error : ".$zip_folder->errorInfo(true);
  1798. }
  1799. // Send to client.
  1800. DocumentManager :: file_send_for_download($zipfilename, false, basename($scormname.'.zip'));
  1801. // Clear.
  1802. include_once api_get_path(LIBRARY_PATH).'fileManage.lib.php';
  1803. my_delete($zipfilename);
  1804. }
  1805. /**
  1806. * This function returns an xml tag
  1807. * $data behaves as the content in case of full tags
  1808. * $data is an array of attributes in case of returning an opening tag
  1809. * @param string
  1810. * @param string
  1811. * @param array
  1812. * @param string
  1813. * @return string
  1814. */
  1815. function xmltagwrite($tagname, $which, $data, $linebreak = 'yes') {
  1816. switch ($which) {
  1817. case 'open':
  1818. $tag = '<'.$tagname;
  1819. $i = 0;
  1820. while ($data[0][$i]) {
  1821. $tag .= ' '.$data[0][$i]."=\"".$data[1][$i]."\"";
  1822. $i ++;
  1823. }
  1824. if ($tagname == 'file') {
  1825. $closing = '/';
  1826. }
  1827. $tag .= $closing.'>';
  1828. if ($linebreak != 'no_linebreak') {
  1829. $tag .= "\n";
  1830. }
  1831. break;
  1832. case 'close':
  1833. $tag = '</'.$tagname.'>';
  1834. if ($linebreak != 'no_linebreak') {
  1835. $tag .= "\n";
  1836. }
  1837. break;
  1838. case 'full':
  1839. $tag = '<'.$tagname;
  1840. $tag .= '>'.$data.'</'.$tagname.'>';
  1841. if ($linebreak != 'no_linebreak') {
  1842. $tag .= "\n";
  1843. }
  1844. break;
  1845. }
  1846. return $tag;
  1847. }
  1848. /**
  1849. * This function writes the imsmanifest.xml and exports the chapter names
  1850. * @param array Array containing filenames
  1851. * @param integer Learnpath_id
  1852. * @return void
  1853. */
  1854. function createimsmanifest($circle1_files, $learnpath_id) {
  1855. global $_course, $LPname, $expdir, $LPnamesafe;
  1856. //$tbl_learnpath_main, $tbl_learnpath_chapter, $tbl_learnpath_item,
  1857. $tbl_learnpath_main = Database :: get_course_table(TABLE_LEARNPATH_MAIN);
  1858. $tbl_learnpath_item = Database :: get_course_table(TABLE_LEARNPATH_ITEM);
  1859. $tbl_learnpath_chapter = Database :: get_course_table(TABLE_LEARNPATH_CHAPTER);
  1860. include_once '../metadata/md_funcs.php'; // RH: export metadata
  1861. // Header
  1862. // Charset should be dependent on content.
  1863. $header = '<?xml version="1.0" encoding="'.api_get_system_encoding().'"?>'."\n<manifest identifier='".$LPnamesafe."' version='1.1'\n xmlns='http://www.imsproject.org/xsd/imscp_rootv1p1p2'\n xmlns:adlcp='http://www.adlnet.org/xsd/adlcp_rootv1p2'\n xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n xsi:schemaLocation='http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd\n http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd\n http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd'>\n";
  1864. $org .= xmltagwrite('metadata', 'open');
  1865. $org .= ' '.xmltagwrite('schema', 'full', 'ADL SCORM');
  1866. $org .= ' '.xmltagwrite('schemaversion', 'full', '1.2');
  1867. $org .= xmltagwrite('metadata', 'close');
  1868. $defaultorgname = 'default_org';
  1869. $attributes[0][0] = 'default';
  1870. $attributes[1][0] = $defaultorgname;
  1871. $org .= xmltagwrite('organizations', 'open', $attributes);
  1872. $attributes[0][0] = 'identifier';
  1873. $attributes[1][0] = $defaultorgname;
  1874. $org .= ' '.xmltagwrite('organization', 'open', $attributes);
  1875. $org .= ' '.xmltagwrite('title', 'full', $LPname);
  1876. // Items list.
  1877. $i = 0;
  1878. $previous_item_id = '00';
  1879. while ($circle1_files[0][$i]) {
  1880. // Check whether we are in the border of two chapters.
  1881. //if (!$desc=strpos($circle1_files[2][$i],'scription')) { // This is needed if the descriptions are exported to file.
  1882. $sql = "SELECT * FROM $tbl_learnpath_item WHERE (id=".$circle1_files[2][$i].")";
  1883. $result = Database::query($sql);
  1884. $row = Database::fetch_array($result);
  1885. $parent_item_id = $row['parent_item_id'];
  1886. if ($parent_item_id != $previous_item_id) {
  1887. // We create the item tag for the chapter (without indifierref).
  1888. $sql2 = "SELECT * FROM $tbl_learnpath_chapter WHERE (id=".$parent_item_id.")";
  1889. $result2 = Database::query($sql2);
  1890. $row2 = Database::fetch_array($result2);
  1891. $chapter_name = $row2['chapter_name'];
  1892. $attributes = '';
  1893. $attributes[0][] = 'identifier';
  1894. $attributes[1][] = 'chapter_'.$row2['id'];
  1895. $attributes[0][] = 'isvisible';
  1896. $attributes[1][] = '1';
  1897. if ($previous_item_id != '00') {
  1898. $org .= ' '.xmltagwrite('item', 'close');
  1899. }
  1900. $org .= ' '.xmltagwrite('item', 'open', $attributes);
  1901. $org .= ' '.xmltagwrite('title', 'full', $chapter_name);
  1902. if ($row2['chapter_description'] != '') {
  1903. // Chapter description.
  1904. $attributes = '';
  1905. $attributes[0][] = 'identifier';
  1906. $attributes[1][] = 'chapter_'.$row2['id'].'_desc';
  1907. $attributes[0][] = 'isvisible';
  1908. $attributes[1][] = '1';
  1909. $org .= ' '.xmltagwrite('item', 'open', $attributes);
  1910. $org .= ' '.xmltagwrite('title', 'full', ' '.$row2['chapter_description']);
  1911. $org .= ' '.xmltagwrite('item', 'close');
  1912. }
  1913. }
  1914. $previous_item_id = $parent_item_id;
  1915. //}
  1916. $attributes = ''; // Item output.
  1917. $attributes[0][] = 'identifier';
  1918. $attributes[1][] = 'item_'.$circle1_files[2][$i];
  1919. $attributes[0][] = 'identifierref';
  1920. $attributes[1][] = 'item_ref_'.$circle1_files[2][$i];
  1921. $attributes[0][] = 'isvisible';
  1922. $attributes[1][] = '1';
  1923. $org .= ' '.xmltagwrite('item', 'open', $attributes);
  1924. $org .= ' '.xmltagwrite('title', 'full', $circle1_files[1][$i]);
  1925. if ($row['prereq_id'] != '') {
  1926. // Item prerequisites.
  1927. $attributes = '';
  1928. $attributes[0][] = 'type';
  1929. $attributes[1][] = 'aicc_script';
  1930. $org .= ' '.xmltagwrite('adlcp:prerequisites', 'open', $attributes, 'no_linebreak');
  1931. if ($row['prereq_type'] == 'i') {
  1932. $org .= 'item_'.$row['prereq_id'];
  1933. }
  1934. if ($row['prereq_type'] == 'c') {
  1935. $org .= 'chapter_'.$row['prereq_id'];
  1936. }
  1937. $org .= xmltagwrite('adlcp:prerequisites', 'close', $attributes);
  1938. }
  1939. if ($row['description'] != '') {
  1940. // Item description.
  1941. $attributes = '';
  1942. $attributes[0][] = 'identifier';
  1943. $attributes[1][] = 'item_'.$circle1_files[2][$i].'_desc';
  1944. $attributes[0][] = 'isvisible';
  1945. $attributes[1][] = '1';
  1946. $org .= ' '.xmltagwrite('item', 'open', $attributes);
  1947. $org .= ' '.xmltagwrite('title', 'full', ' '.$row['description']);
  1948. $org .= ' '.xmltagwrite('item', 'close');
  1949. }
  1950. $mds = new mdstore(true); // RH: export metadata; if no table, create it
  1951. if (($mdt = $mds->mds_get($row['item_type'].'.'.$row['item_id'])))
  1952. if (($mdo = api_strpos($mdt, '<metadata>')) && ($mdc = api_strpos($mdt, '</metadata>')))
  1953. $org .= ' '.api_substr($mdt, $mdo, $mdc - $mdo + 11)."\n";
  1954. $org .= ' '.xmltagwrite('item', 'close');
  1955. $i ++;
  1956. }
  1957. if ($circle1_files) {
  1958. $org .= ' '.xmltagwrite('item', 'close');
  1959. } // Not needed in case of a blank path.
  1960. $org .= ' '.xmltagwrite('organization', 'close');
  1961. $org .= xmltagwrite('organizations', 'close');
  1962. $org .= xmltagwrite('resources', 'open');
  1963. // Resources list.
  1964. $i = 0;
  1965. while ($circle1_files[0][$i]) {
  1966. $attributes = '';
  1967. $attributes[0][] = 'identifier';
  1968. $attributes[1][] = 'item_ref_'.$circle1_files[2][$i];
  1969. $attributes[0][] = 'type';
  1970. $attributes[1][] = 'webcontent';
  1971. $attributes[0][] = 'adlcp:scormtype';
  1972. $attributes[1][] = 'sco';
  1973. $attributes[0][] = 'href';
  1974. $attributes[1][] = $circle1_files[0][$i];
  1975. $org .= ' '.xmltagwrite('resource', 'open', $attributes);
  1976. $org .= ' '.xmltagwrite('metadata', 'open');
  1977. $org .= ' '.xmltagwrite('schema', 'full', 'ADL SCORM');
  1978. $org .= ' '.xmltagwrite('schemaversion', 'full', '1.2');
  1979. $org .= ' '.xmltagwrite('metadata', 'close');
  1980. $attributes = '';
  1981. $attributes[0][] = 'href';
  1982. $attributes[1][] = $circle1_files[0][$i];
  1983. $org .= ' '.xmltagwrite('file', 'open', $attributes);
  1984. $org .= ' '.xmltagwrite('resource', 'close');
  1985. $i ++;
  1986. }
  1987. $org .= xmltagwrite('resources', 'close');
  1988. $org .= xmltagwrite('manifest', 'close');
  1989. $manifest = $header.$org;
  1990. exporttofile('imsmanifest.xml', 'Manifest file', '0', $manifest);
  1991. }
  1992. /**
  1993. * Gets the tags of the file given as parameter
  1994. *
  1995. * if $filename is not found, GetSRCTags(filename) will return FALSE
  1996. * @param string File path
  1997. * @return mixed Array of strings on success, false on failure
  1998. * @author unknown
  1999. * @author Included by imandak80
  2000. */
  2001. function GetSRCTags($fileName) {
  2002. if (!($fp = fopen($fileName, 'r'))) {
  2003. // Iif file can't be opened, return false.
  2004. return false;
  2005. }
  2006. // Read file contents.
  2007. $contents = fread($fp, filesize($fileName));
  2008. fclose($fp);
  2009. $matches = array();
  2010. $srcList = array();
  2011. // Get all src tags contents in this file. Use multi-line search.
  2012. preg_match_all('/src(\s)*=(\s)*[\'"]([^\'"]*)[\'"]/mi', $contents, $matches); // Get the img src as contained between " or '
  2013. foreach ($matches[3] as $match) {
  2014. if (!in_array($match, $srcList)) {
  2015. $srcList[] = $match;
  2016. }
  2017. }
  2018. if (count($srcList) == 0) {
  2019. return false;
  2020. }
  2021. return $srcList;
  2022. }
  2023. /**
  2024. * Copy file and create directories in the path if needed.
  2025. *
  2026. * @param string $source Source path
  2027. * @param string $dest Destination path
  2028. * @return boolean true on success, false on failure
  2029. */
  2030. function CopyNCreate($source, $dest) {
  2031. if (strcmp($source, $dest) == 0)
  2032. return false;
  2033. $dir = '';
  2034. $tdest = explode('/', $dest);
  2035. for ($i = 0; $i < sizeof($tdest) - 1; $i ++) {
  2036. $dir = $dir.$tdest[$i].'/';
  2037. if (!is_dir($dir))
  2038. if (!mkdir($dir, api_get_permissions_for_new_directories()))
  2039. return false;
  2040. }
  2041. if (!copy($source, $dest))
  2042. return false;
  2043. return true;
  2044. }
  2045. function rcopy($source, $dest) {
  2046. //error_log($source." -> ".$dest, 0);
  2047. if (!file_exists($source)) {
  2048. //error_log($source." does not exist", 0);
  2049. return false;
  2050. }
  2051. if (is_dir($source)) {
  2052. //error_log($source." is a dir", 0);
  2053. // This is a directory.
  2054. // Remove trailing '/'
  2055. if (strrpos($source, '/') == sizeof($source) - 1) {
  2056. $source = substr($source, 0, size_of($source) - 1);
  2057. }
  2058. if (strrpos($dest, '/') == sizeof($dest) - 1) {
  2059. $dest = substr($dest, 0, size_of($dest) - 1);
  2060. }
  2061. if (!is_dir($dest)) {
  2062. $res = @mkdir($dest, api_get_permissions_for_new_directories());
  2063. if ($res !== false) {
  2064. return true;
  2065. } else {
  2066. // Remove latest part of path and try creating that.
  2067. if (rcopy(substr($source, 0, strrpos($source, '/')), substr($dest, 0, strrpos($dest, '/')))) {
  2068. return @mkdir($dest, api_get_permissions_for_new_directories());
  2069. } else {
  2070. return false;
  2071. }
  2072. }
  2073. }
  2074. return true;
  2075. } else {
  2076. // This is presumably a file.
  2077. //error_log($source." is a file", 0);
  2078. if (!@ copy($source, $dest)) {
  2079. //error_log("Could not simple-copy $source", 0);
  2080. $res = rcopy(dirname($source), dirname($dest));
  2081. if ($res === true) {
  2082. //error_log("Welcome dir created", 0);
  2083. return @ copy($source, $dest);
  2084. } else {
  2085. return false;
  2086. //error_log("Error creating path", 0);
  2087. }
  2088. } else {
  2089. //error_log("Could well simple-copy $source", 0);
  2090. return true;
  2091. }
  2092. }
  2093. }