md_funcs.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. <?php
  2. /**
  3. * Chamilo metadata/md_funcs.php -->
  4. * 2006/12/15
  5. * Copyright (C) 2006 rene.haentjens@UGent.be - see note at end of text -->
  6. * @package chamilo.metadata
  7. */
  8. /**
  9. * Chamilo Metadata: common functions and mdstore class
  10. *
  11. * This script requires xmd.lib.php and xht.lib.php (Chamilo inc/lib).
  12. *
  13. * Note on the funny characters used in mds_update_xml_and_mdt:
  14. *
  15. * ! and ~ and , are handled by xmd_update, see xmd.lib.php
  16. * ~~ !! ; and = are handled here; note that = excludes newlines in value
  17. *
  18. * path!elem create new element (not for attributes!)
  19. * path=value assign new value to existing element or value to attribute
  20. * path~ delete element (you cannot delete an attribute)
  21. * ~~ delete the whole xmldoc and the DB entry
  22. * !! this (xml) document contains the course keywords
  23. *
  24. * path1,path2,...;subpath=value for all elements in path1, path2, ...
  25. * assign value to subpath (see also xmd_update_many)
  26. *
  27. */
  28. // FETCH GET/POST-DATA; GENERAL FUNCTIONS ------------------------------------->
  29. if (isset($getpostvars) && is_array($getpostvars))
  30. foreach ($getpostvars as $gpvar)
  31. if (is_string($gpvar) && (isset($_POST[$gpvar]) || isset($_GET[$gpvar])))
  32. {
  33. $val = isset($_POST[$gpvar]) ? $_POST[$gpvar] : $_GET[$gpvar];
  34. $GLOBALS[$gpvar] = get_magic_quotes_gpc() ? stripslashes($val) : $val;
  35. }
  36. function fgc($filename)
  37. {
  38. $fp = fopen($filename, 'rb'); $buffer = fread($fp, filesize($filename));
  39. fclose($fp); return $buffer; // file_get_contents: PHP >= 4.3.0
  40. }
  41. function give_up($msg)
  42. {
  43. global $charset;
  44. echo '<p align="center">MetaData:<br /><b>? ',
  45. htmlspecialchars($msg, ENT_QUOTES, $charset), '</b></p>'; exit;
  46. }
  47. function getpar($name, $description, $default = '')
  48. {
  49. $value = isset($_GET[$value = api_strtolower($name)]) ? $_GET[$value] : '';
  50. $value = get_magic_quotes_gpc() ? stripslashes($value) : $value;
  51. if (!$value) $value = $default;
  52. if ($value == '') give_up('URL parameter ' . api_strtoupper($name) . ' - ' .
  53. $description . ' - is required');
  54. define(api_strtoupper($name), $value);
  55. }
  56. function get_course_path()
  57. {
  58. return api_get_path(SYS_COURSE_PATH);
  59. }
  60. function get_course_web()
  61. {
  62. return api_get_path(WEB_COURSE_PATH);
  63. }
  64. function define_htt($htt_file, $urlp, $course_path)
  65. {
  66. global $charset;
  67. ($htt_file_contents = @fgc($htt_file))
  68. or give_up('Templates file "' . $htt_file . '" is missing...');
  69. $xhtDoc = new xhtdoc($htt_file_contents);
  70. if ($xhtDoc->htt_error)
  71. give_up('Templates file "' . $htt_file . '": ' . $xhtDoc->htt_error);
  72. $xhtDoc->xht_param['self'] = api_get_self() . $urlp;
  73. $xhtDoc->xht_param['dateTime'] = date('Y-m-d');
  74. $ckw = $course_path . '/CourseKwds.js';
  75. define('KEYWORDS_CACHE', get_course_path() . $ckw);
  76. if (file_exists(KEYWORDS_CACHE)) $kcdt =
  77. htmlspecialchars(date('Y/m/d H:i:s', filemtime(KEYWORDS_CACHE)), ENT_QUOTES, $charset);
  78. $xhtDoc->xht_param['keywordscache'] = $kcdt ?
  79. '<script type="text/javascript" src="' . get_course_web() . $ckw . '"></script>' .
  80. '<br /><small><i>(CourseKwds cache: ' . $kcdt . ')</i></small>' : '';
  81. return $xhtDoc;
  82. }
  83. function make_uri()
  84. {
  85. $regs = array(); // for use with ereg()
  86. $uri = strtr(ereg_replace(
  87. "[^0-9A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\xFF\*\(\('!_.-]", "_",
  88. api_get_setting('siteName')), "\\", "_"); // allow letdigs, and _-.()'!*
  89. if (($p = strpos($uri, '.')) !== FALSE)
  90. $uri = substr($uri, 0, $p);
  91. if (ereg('^([^/]+//)?([^/\?]+)[/\?]',api_get_path(WEB_PATH).'/',$regs))
  92. if (ereg('([^\.]+)(\.ca)?(\.[^\.]+)?', strrev($regs[2]), $regs))
  93. $uri = str_replace('.', '-',
  94. strrev($regs[1].$regs[2].$regs[3])) . ':' . $uri;
  95. $uri = 'urn:' . strtolower($uri);
  96. while (substr($uri, -1)=='.') $uri = substr($uri,0,-1);
  97. return $uri;
  98. }
  99. // IEEE LOM: DEFAULT XML AND DUBLIN CORE MAPPING ------------------------------>
  100. $ieee_xml = <<<EOD
  101. <!-- {-XML-} -->
  102. <item>
  103. <metadata>
  104. <lom xmlns="http://ltsc.ieee.org/xsd/LOM">
  105. <general>
  106. <identifier><catalog>{-H {-P siteUri-}-}.</catalog><entry>{-H {-P entry-}-}</entry></identifier>
  107. <title><string language="{-H {-P mdlang-}-}">{-H {-P title-}-}</string></title>
  108. <language>{-H {-P lang-}-}</language>
  109. <description><string language="{-H {-P mdlang-}-}">{-H {-P description-}-}</string></description>
  110. <coverage><string language="{-H {-P mdlang-}-}">{-H {-P coverage-}-}</string></coverage>
  111. </general>
  112. <lifeCycle>
  113. <version><string language="xx">0.5</string></version>
  114. <status><source>LOMv1.0</source><value>draft</value></status>
  115. <contribute>
  116. <role><source>LOMv1.0</source><value>author</value></role>
  117. <entity>{-H {-P author-}-}</entity>
  118. <date><dateTime>{-H {-P dateTime-}-}</dateTime></date>
  119. </contribute>
  120. </lifeCycle>
  121. <metaMetadata>
  122. <metadataSchema>ADLv1.3</metadataSchema>
  123. </metaMetadata>
  124. <technical>
  125. <format>{-H {-P format-}-}</format>
  126. <size>{-H {-P size-}-}</size>
  127. <location>{-H {-P location-}-}</location>
  128. </technical>
  129. <educational>
  130. <learningResourceType><source>LOMv1.0</source><value>narrative text</value></learningResourceType>
  131. </educational>
  132. <rights>
  133. <cost><source>LOMv1.0</source><value>yes</value></cost>
  134. <copyrightAndOtherRestrictions><source>LOMv1.0</source><value>yes</value></copyrightAndOtherRestrictions>
  135. <description><string language="{-H {-P mdlang-}-}">{-L MdCopyright-}</string></description>
  136. </rights>
  137. <classification>
  138. <purpose><source>LOMv1.0</source><value>educational objective</value></purpose>
  139. </classification>
  140. </lom>
  141. </metadata>
  142. </item>
  143. <!-- {--} -->
  144. EOD;
  145. $ieee_dcmap_e = array(
  146. 'Identifier'=> 'metadata/lom/general/identifier[1]',
  147. 'Title'=> 'metadata/lom/general/title[1]',
  148. 'Language'=> 'metadata/lom/general/language[1]',
  149. 'Description'=> 'metadata/lom/general/description[1]',
  150. 'Coverage'=> 'metadata/lom/general/coverage[1]',
  151. 'Type'=> 'metadata/lom/educational/learningResourceType[1]',
  152. 'Date'=> 'metadata/lom/lifeCycle/contribute[1]/date',
  153. 'Creator'=> 'metadata/lom/lifeCycle/contribute[1]/entity',
  154. 'Format'=> 'metadata/lom/technical/format[1]',
  155. 'Rights'=> 'metadata/lom/rights/description[1]');
  156. // maps Dublin Core elements to xmd paths for elements (not yet complete)
  157. $ieee_dcmap_v = array(
  158. 'Identifier'=> 'metadata/lom/general/identifier[1]/entry',
  159. 'Title'=> 'metadata/lom/general/title[1]/string',
  160. 'Language'=> 'metadata/lom/general/language[1]',
  161. 'Description'=> 'metadata/lom/general/description[1]/string',
  162. 'Coverage'=> 'metadata/lom/general/coverage[1]/string',
  163. 'Type'=> 'metadata/lom/educational/learningResourceType[1]/value',
  164. 'Date'=> 'metadata/lom/lifeCycle/contribute[1]/date/dateTime',
  165. 'Creator'=> 'metadata/lom/lifeCycle/contribute[1]/entity',
  166. 'Format'=> 'metadata/lom/technical/format[1]',
  167. 'Rights'=> 'metadata/lom/rights/description[1]/string');
  168. // maps Dublin Core elements to xmd paths for values (not yet complete)
  169. // KEYWORD TREE --------------------------------------------------------------->
  170. function define_kwds($mdo)
  171. {
  172. if (!($newtext = trim(@fgc(get_course_path() . $mdo->mdo_course['path'] .
  173. '/document' . $mdo->mdo_path ))))
  174. {
  175. unlink(KEYWORDS_CACHE); return;
  176. }
  177. // templates to define the tree as JScript object
  178. $xhtDocKw = new xhtdoc(<<<EOD
  179. <!-- {-KWTREE_OBJECT-} -->
  180. KWTREE_OBJECT = {n:"", ti:"{-X @title-}"
  181. , c:[{-R * C DOWN_THE_KWTREE-}]};
  182. document.write(traverseKwObj(KWTREE_OBJECT, '', 0)); KWDS_ARRAY.sort();
  183. <!-- {-DOWN_THE_KWTREE-} -->
  184. {-T number > 1 , -}{n:"{-V @.-}"{-D cm {-X @comment-}-}{-T cm != empty , cm:"{-P cm-}"-}{-D pt {-X @postit-}-}{-T pt != empty , pt:"{-P pt-}"-}{-R * P empty-}{-T number >= 1
  185. , c:[-}{-T number >= 1 R * C DOWN_THE_KWTREE-}{-R * P empty-}{-T number >= 1 ]-}}
  186. <!-- {--} -->
  187. EOD
  188. ); // traverseKwObj (md_script) generates clickable tree and populates KWDS_ARRAY
  189. if ($xhtDocKw->htt_error)
  190. give_up('KwdTree template (metadata/md_funcs): ' . $xhtDocKw->htt_error);
  191. $xhtDocKw->xht_xmldoc = new xmddoc(explode("\n", $newtext));
  192. if ($xhtDocKw->xht_xmldoc->error)
  193. give_up('CourseKwds (metadata/md_funcs): XML error: ' .
  194. $xhtDocKw->xht_xmldoc->error);
  195. if (count($xhtDocKw->xht_xmldoc->children[0]) < 2)
  196. {
  197. unlink(KEYWORDS_CACHE); return;
  198. }
  199. $fileHandler = @fopen(KEYWORDS_CACHE, 'w');
  200. @fwrite($fileHandler, $xhtDocKw->xht_fill_template('KWTREE_OBJECT'));
  201. @fclose($fileHandler);
  202. }
  203. // METADATA STORE ------------------------------------------------------------->
  204. /**
  205. * mdstore class
  206. * @package chamilo.metadata
  207. */
  208. class mdstore
  209. {
  210. var $mds_something;
  211. function mds_get($eid, $column = 'mdxmltext', $must_exist = '') // none: FALSE
  212. {
  213. if (($mdt = Database::fetch_array($this->_query("SELECT " . $column .
  214. " FROM " . MDS_TABLE . " WHERE ", $eid)))) return $mdt[$column];
  215. if ($must_exist) give_up($must_exist . $this->_coldat('eid', $eid));
  216. return FALSE;
  217. }
  218. function mds_get_dc_elements($mdo) // no record: FALSE
  219. {
  220. if (!($mdt = $this->mds_get($mdo->mdo_eid))) return FALSE;
  221. $xmlDoc = new xmddoc(explode("\n", $mdt)); if ($xmlDoc->error) return FALSE;
  222. $result = array();
  223. foreach ($mdo->mdo_dcmap_v as $dce => $xp)
  224. {
  225. $result[$dce] = $xmlDoc->xmd_value($xp);
  226. }
  227. return $result;
  228. }
  229. function mds_get_many($columns, $where_clause)
  230. {
  231. $cols = '';
  232. foreach (explode(',', $columns) as $col) $cols .= "," . trim($col);
  233. if (!$cols) return;
  234. return $this->_query("SELECT " . api_substr($cols, 1) .
  235. " FROM " . MDS_TABLE . " WHERE ". $where_clause);
  236. }
  237. function mds_put($eid, $data, $column = 'mdxmltext', $exists = TRUE)
  238. {
  239. if ($exists === TRUE)
  240. return $this->_query("UPDATE " . MDS_TABLE . " SET " .
  241. $this->_coldat($column, $data) . " WHERE ", $eid);
  242. elseif ($exists === FALSE)
  243. return $this->_query("INSERT INTO " . MDS_TABLE . " SET " .
  244. $this->_coldat($column, $data) . ", ", $eid);
  245. else // user doesn't know, check first whether the record exists
  246. return $this->mds_put($eid, $data, $column,
  247. !($this->mds_get($eid) === FALSE));
  248. }
  249. function mds_put_dc_elements($mdo, $dcelem)
  250. {
  251. if (($mdt = $this->mds_get($mdo->mdo_eid)) === FALSE)
  252. {
  253. $mdt = $mdo->mdo_generate_default_xml_metadata(); $exists = FALSE;
  254. }
  255. else $exists = TRUE;
  256. $xmlDoc = new xmddoc(explode("\n", $mdt)); if ($xmlDoc->error) return FALSE;
  257. foreach ($dcelem as $dce => $value)
  258. {
  259. $xmlDoc->xmd_update($mdo->mdo_dcmap_v[$dce], (string) $value);
  260. }
  261. $this->mds_put($mdo->mdo_eid, '', 'md5', $exists);
  262. return $this->mds_put($mdo->mdo_eid, $xmlDoc->xmd_xml());
  263. }
  264. function mds_append($eid, $moredata, $column = 'indexabletext')
  265. {
  266. if (($olddata = $this->mds_get($eid, $column)) === FALSE) return FALSE;
  267. $this->mds_put($eid, $olddata . $moredata, $column); return $olddata;
  268. }
  269. function mds_delete($eid)
  270. {
  271. return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE ", $eid);
  272. }
  273. function mds_delete_offspring($eid, $sep = '.')
  274. {
  275. return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE ", $eid, $sep);
  276. }
  277. function mds_delete_many($idarray)
  278. {
  279. if (!is_array($idarray) || count($idarray) == 0) return FALSE;
  280. return $this->_query("DELETE FROM " . MDS_TABLE . " WHERE eid IN ('" .
  281. implode("','", array_map('addslashes', $idarray)) . "')");
  282. }
  283. function mds_update_xml_and_mdt($mdo, &$xmlDoc, $mda, $eid, &$traceinfo,
  284. $exists = TRUE) // note: $xmlDoc and $traceinfo passed by reference
  285. {
  286. foreach (explode("\n",
  287. str_replace("\r", "\n", str_replace("\r\n", "\n", $mda))) as $update)
  288. {
  289. if (!$update) continue;
  290. if (($nameLth = strpos($update, '='))) // e.g. 'gen/tit/str=new'
  291. {
  292. if (($text = api_substr($update, $nameLth + 1)) === FALSE) $text = '';
  293. if (!($path = trim(api_substr($update, 0, $nameLth)))) continue;
  294. if (($sc = api_strpos($path, ';'))) // e.g. 'gen/tit,gen/des;str@lang'
  295. $xmlDoc->xmd_update_many(api_substr($path, 0, $sc),
  296. api_substr($path, $sc + 1), $text);
  297. else
  298. $xmlDoc->xmd_update($path, $text);
  299. }
  300. elseif ($nameLth === FALSE) // e.g. 'gen/tit/str[-1]~'
  301. {
  302. if ($update == '~~')
  303. {
  304. $update = 'DELETE ' . $eid;
  305. if ($exists === FALSE) $update = '';
  306. else $this->mds_delete($eid);
  307. $mda = ''; $exists = TRUE;
  308. foreach ($xmlDoc->children[0] as $key => $child)
  309. unset($xmlDoc->children[0][$key]);
  310. }
  311. elseif ($update == '!!')
  312. {
  313. define_kwds($mdo);
  314. $update = ''; $mda = ''; $exists = TRUE;
  315. }
  316. else
  317. {
  318. $x = $xmlDoc->xmd_update(trim($update), '');
  319. }
  320. }
  321. if ($update) $traceinfo .= $update . '- ';
  322. }
  323. $mdt = $xmlDoc->xmd_xml();
  324. if ($exists === FALSE)
  325. {
  326. $this->mds_put($eid, $mdt, 'mdxmltext', FALSE);
  327. $traceinfo .= 'INSERT ' . $eid . '- ';
  328. }
  329. elseif($mda)
  330. {
  331. $this->mds_put($eid, $mdt, 'mdxmltext');
  332. $traceinfo .= 'UPDATE ' . $eid . '- ';
  333. }
  334. return $mdt;
  335. }
  336. function mdstore($allow_create)
  337. {
  338. global $_course; if (!isset($_course)) return;
  339. define('MDS_TABLE', Database::get_course_table(TABLE_METADATA));
  340. $this->_query("CREATE TABLE IF NOT EXISTS " . MDS_TABLE . " ( " .
  341. "eid varchar(250) NOT NULL," . // entry-id, e.g. doc.1
  342. "mdxmltext text default ''," . // MD-text, XML-formatted
  343. "md5 char(32) default ''," . // hash-validator
  344. "htmlcache1 text default ''," . // cached HTML, part 1
  345. "htmlcache2 text default ''," . // cached HTML, part 2
  346. "indexabletext text default ''," . // indexable for search
  347. "PRIMARY KEY (eid) )");
  348. }
  349. function _coldatstart($column, $data)
  350. {
  351. return $column . " LIKE '" . addslashes($data) . "%'";
  352. }
  353. function _coldat($column, $data)
  354. {
  355. return $column . "='" . addslashes($data) . "'";
  356. }
  357. function _query($sql, $eid = '', $sep = '')
  358. {
  359. if ($eid) $sql .= $sep ? $this->_coldatstart('eid', $eid . $sep) :
  360. $this->_coldat('eid', $eid);
  361. return Database::query($sql);
  362. }
  363. }
  364. /*
  365. <!--
  366. This program is free software; you can redistribute it and/or
  367. modify it under the terms of the GNU General Public License
  368. as published by the Free Software Foundation; either version 2
  369. of the License, or (at your option) any later version.
  370. This program is distributed in the hope that it will be useful,
  371. but WITHOUT ANY WARRANTY; without even the implied warranty of
  372. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  373. GNU General Public License for more details.
  374. -->
  375. */
  376. ?>