learnpath_functions.inc.php 101 KB

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