learnpath_functions.inc.php 97 KB

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