learnpath_functions.inc.php 102 KB

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