PageRenderTime 26ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/web/system/libraries/Indexing.php

https://github.com/QnapClub/Plugmedia
PHP | 458 lines | 308 code | 125 blank | 25 comment | 28 complexity | c41aaf519b467d7bbcb5ae25a132ca71 MD5 | raw file
  1. <?php if (!defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. *
  4. * @package Plugmedia
  5. * @copyright (c) 2009 Christophe Lemoine
  6. * @license http://creativecommons.org/licenses/by-nc-nd/2.0/be/ Attribution-Noncommercial-No Derivative Works 2.0 Belgium
  7. * QNAP Systems, Inc is authorize to distribute and transmit the work
  8. *
  9. * Minimum Requirement: PHP 5
  10. */
  11. class CORE_Indexing {
  12. private $inserted_directory = 0;
  13. private $skipped_directory = 0;
  14. private $inserted_file = 0;
  15. private $updated_file = 0;
  16. private $skipped_file = 0;
  17. private $usage_mb = 0;
  18. private $root_path;
  19. private $root_id;
  20. private $extract_metadata;
  21. private $metadata;
  22. private $config;
  23. private $DB;
  24. private $config_array;
  25. public function CORE_Indexing()
  26. {
  27. global $DB, $db_config;
  28. $this->DB = $DB;
  29. $this->metadata =& load_class('Metadata');
  30. $this->config =& load_class('ConfigLoader');
  31. $this->config_array = $db_config;
  32. $this->setRoot();
  33. }
  34. // FIRST call of the class (define the root node)
  35. public function setRoot()
  36. {
  37. $this->root_path = STARTING_FOLDER;
  38. // get root path information
  39. $this->root_path = $this->DB->protectString($this->root_path);
  40. $this->DB->query("SELECT * FROM directory WHERE parent = '".$this->root_path."'","setRoot");
  41. $root_info = $this->DB->fetchrow();
  42. if ($root_info==false)
  43. {
  44. if (!is_dir($this->root_path))
  45. {
  46. echo 'error with root path';
  47. exit();
  48. }
  49. // need to index root path...
  50. $this->root_id = $this->insertDirectory($this->root_path, '');
  51. // assign to administrator...
  52. $this->DB->query("INSERT into group_accesspath (group_id, directory_id) VALUES('1','".$this->root_id."');","setRoot");
  53. }else{
  54. $this->root_id = $root_info['id'];
  55. }
  56. }
  57. public function scanDirectories($base='', $last_value='', $recursif=true, $echo_process = false, $extract_metadata = false, $parents_id)
  58. {
  59. $local_insert_directory = 0;
  60. $local_insert_file = 0;
  61. $local_update_file = 0;
  62. $this->extract_metadata = $extract_metadata;
  63. if ($echo_process)
  64. global $i18n;
  65. log_message('debug', "starting scan function with directory".$base.$last_value);
  66. $backup_base =$base;
  67. $backup_last_value = $last_value;
  68. $thumb_find = false;
  69. $base_protected = $this->DB->protectString($base);
  70. $last_value_protected = $this->DB->protectString($last_value);
  71. $this->DB->query("SELECT id FROM directory WHERE parent='$base_protected' AND name='$last_value_protected'","scanDirectories");
  72. $id_dir = $this->DB->fetchrow();
  73. if (!isset($id_dir['id']))
  74. {
  75. $local_insert_directory++;
  76. $id_parent = $this->insertDirectory($base, $last_value);
  77. $file_array = array();
  78. }
  79. else
  80. {
  81. $this->skipped_directory ++;
  82. $this->DB->query("SELECT * FROM files WHERE directory_id='".$id_dir['id']."'","scanDirectories");
  83. $id_parent = $id_dir['id'];
  84. $files_in_dir = $this->DB->fetcharray();
  85. $total_affected = count($files_in_dir);
  86. if ($total_affected>0)
  87. {
  88. foreach ($files_in_dir as $file)
  89. $file_array[$this->DB->protectString($file['filename'])] = $file;
  90. }
  91. else
  92. $file_array = array();
  93. }
  94. // find all directories in the directory $base.$last_value
  95. $this->DB->query("SELECT * FROM directory WHERE parent='".$this->DB->protectString($base).$this->DB->protectString($last_value)."/'","scanDirectories");
  96. $dir_in_dir = $this->DB->fetcharray();
  97. $total_affected = count($dir_in_dir);
  98. if ($total_affected>0)
  99. {
  100. foreach ($dir_in_dir as $dir)
  101. $dirarray[$this->DB->protectString($dir['name'])] = $dir;
  102. }
  103. else
  104. $dirarray = array();
  105. $base = $base.$last_value.'/';
  106. $array = array_diff(scandir($base), array('.', '..', '.@__thumb','.@__comments'));
  107. $count = count($array);
  108. $i=0;
  109. foreach($array as $key=>$value)
  110. {
  111. $i++;
  112. if ($echo_process)
  113. {
  114. echo "<div id='waiting_message'><div id='content_a'>".$i18n->translate('PM_OUTDATED', '')."<br /><br />".$i18n->translate('PERFORMING', $i, $count, $value)."</div></div>";
  115. ob_flush();
  116. flush();
  117. }
  118. if (isset($parents_id) && is_array($parents_id) && !in_array($id_parent,$parents_id))
  119. $parents_id[] = $id_parent;
  120. if (is_dir($base.$value))
  121. {
  122. $value_protected = $this->DB->protectString( $this->encodetoUTF8($value));
  123. unset ($dirarray[$value_protected]);
  124. if ($recursif)
  125. {
  126. $data = $this->scanDirectories($base,$value, true, $echo_process, $this->extract_metadata, $parents_id);
  127. }
  128. else
  129. {
  130. $local_insert_directory++;
  131. $this->insertDirectory($base, $value);
  132. }
  133. }
  134. else
  135. {
  136. $value_protected = $this->DB->protectString( $this->encodetoUTF8($value));
  137. if (!$last_update_time_file = @filemtime($base.$value))
  138. $last_update_time_file = 0;
  139. if (!$file_size = filesize($base.$value))
  140. $file_size = 0;
  141. $file_extension = $this->getExtension($value);
  142. if (!array_key_exists($value_protected, $file_array))
  143. {
  144. $original_date = $last_update_time_file;
  145. $exif_info = "";
  146. loadHelper ('filesys');
  147. $footprint = get_footprint($base.$value);
  148. $local_insert_file++;
  149. $this->insertFileInDatabase($id_parent, $value_protected, $last_update_time_file,$original_date, $file_size, strtolower($file_extension), '', $footprint, $base);
  150. $this->inserted_file ++;
  151. $this->usage_mb += $file_size;
  152. }
  153. else
  154. {
  155. if ($last_update_time_file > $file_array[$value_protected]['timestamp_modification'])
  156. {
  157. // Need update
  158. loadHelper ('filesys');
  159. $footprint = get_footprint($base.$file_array[$value_protected]['filename']);
  160. $local_update_file++;
  161. log_message('debug', "Update of a file in database for id : ".$file_array[$value_protected]['id']);
  162. $this->updateFileInDatabase($file_size, $last_update_time_file, $file_array[$value_protected]['id'], $footprint);
  163. }else
  164. $this->skipped_file ++;
  165. }
  166. }
  167. unset($file_array[$value_protected]);
  168. }
  169. if (isset($parents_id))
  170. {
  171. $monitoring =& load_class('Directory_monitoring');
  172. // add all directory with changes in the table queue_news
  173. $monitoring->addChangedDirectories($parents_id, $local_insert_directory, $local_insert_file, $local_update_file);
  174. }
  175. // CLEAN THE DB with obsolete files
  176. $this->deleteFileInDirectory($file_array);
  177. $this->deleteDirectoryInDirectory($dirarray);
  178. if ($echo_process)
  179. ob_end_flush();
  180. return true;
  181. }
  182. private function deleteFileInDirectory($file_array)
  183. {
  184. foreach ($file_array as $todelete)
  185. $this->DB->query("DELETE FROM files WHERE id = ".$todelete['id'],"");
  186. }
  187. private function deleteDirectoryInDirectory ($dir_array)
  188. {
  189. foreach ($dir_array as $todelete)
  190. $this->DB->query("DELETE FROM directory WHERE id = ".$todelete['id'],"deleteDirectoryInDirectory");
  191. }
  192. private function updateFileInDatabase ($filesize, $timestamp_modification, $id_modification, $footprint)
  193. {
  194. $this->updated_file ++;
  195. $this->DB->query("UPDATE files SET filesize = $filesize, timestamp_modification=$timestamp_modification, file_hash='$footprint', file_thumb_normal='', file_thumb='' WHERE id = $id_modification","updateFileInDatabase");
  196. $this->DB->query("DELETE FROM metadata_exif WHERE files_id = $id_modification","updateFileInDatabase");
  197. }
  198. private function insertFileInDatabase($id_parent, $filename, $timestam_modif, $original_date, $filesize, $extension, $thumb_path, $footprint, $base)
  199. {
  200. log_message('debug', "Insert file with ".$id_parent.$filename);
  201. $thumb_path = $this->DB->protectString( $this->encodetoUTF8($thumb_path));
  202. $extension = $this->DB->protectString( $this->encodetoUTF8($extension));
  203. $string = $this->natConvert( $this->encodetoUTF8($filename));
  204. ($this->extract_metadata)? $metadata_extr = 1:$metadata_extr = 0;
  205. if ($this->DB->query("INSERT INTO files (directory_id,filename, detail_file,timestamp_modification,original_date,filesize,extension,file_thumb,file_hash, formated_name, metadata_extracted) VALUES ('$id_parent','$filename','','$timestam_modif','$original_date','$filesize','$extension','$thumb_path','$footprint','$string',$metadata_extr)","insertFileInDatabase"))
  206. {
  207. $id_inserted = $this->DB->getLastId();
  208. // Extract metadata if needed
  209. if ($this->extract_metadata)
  210. {
  211. $meta =& load_class('Metadata');
  212. $meta->extractMetadata($id_inserted, $filename, $base, $footprint, $extension);
  213. }
  214. }
  215. }
  216. private function insertDirectory($parent, $name)
  217. {
  218. $this->inserted_directory ++ ;
  219. $encoded_parent = $this->DB->protectString($parent);
  220. $encoded_name = $this->DB->protectString( $this->encodetoUTF8($name));
  221. $natural_sorting_name = $this->DB->protectString( $this->encodetoUTF8($this->natConvert($name)));
  222. $original_date = @filemtime($parent.$name);
  223. log_message('debug', "Insert directory with ".$parent.$name);
  224. $this->DB->query("INSERT INTO directory (parent,name,thumbnail,thumbnail_random, original_date, formated_name) VALUES ('$encoded_parent','$encoded_name',NULL,NULL,$original_date,'$natural_sorting_name')","indexDirectory");
  225. $id_parent = $this->DB->getLastId();
  226. $this->inserted_directory ++;
  227. return $id_parent;
  228. }
  229. function updateOutdatedDirectory($directory_id)
  230. {
  231. $this->DB->query("SELECT * FROM directory WHERE id='$directory_id'","updateOutdatedDirectory");
  232. $value = $this->DB->fetchrow();
  233. if (is_array($value))
  234. {
  235. $this->scanDirectories($value['parent'],$value['name'], false,true, false,array());
  236. }
  237. }
  238. private function findMp3CoverInDirectory($extension, $tofind, $directory_start_fullpath, $recursive_lookup=true)
  239. {
  240. $str_extension = "";
  241. if (is_array($extension))
  242. {
  243. foreach ($extension as $ext)
  244. $str_extension .= "'".$ext."',";
  245. $str_extension = substr($str_extension,0,strlen($str_extension)-1);;
  246. }
  247. else
  248. $str_extension = "'".$extension."'";
  249. if (is_array($tofind))
  250. {
  251. $str_tofind = "(";
  252. foreach ($tofind as $fd)
  253. $str_tofind .= " filename like ('%".$fd."%') OR";
  254. $str_tofind = substr($str_tofind,0,strlen($str_tofind)-2);
  255. $str_tofind .= ")";
  256. }
  257. else
  258. $str_tofind = "filename like ('%".$tofind."%')";
  259. if ($recursive_lookup)
  260. $directory_start_fullpath = $directory_start_fullpath."%";
  261. $this->DB->query("SELECT * from files where $str_tofind AND extension IN ($str_extension) AND directory_id IN (SELECT id FROM directory where parent||name LIKE ('$directory_start_fullpath') order by parent,name);","findElement");
  262. return $this->DB->fetcharray();
  263. }
  264. private function encodetoUTF8($string)
  265. {
  266. setlocale(LC_CTYPE, 'en_US.utf8');
  267. return iconv("UTF-8","UTF-8//IGNORE",$string);
  268. }
  269. private function getExtension($fichier)
  270. {
  271. $bouts = explode(".", $fichier);
  272. $extension = array_pop($bouts);
  273. return $extension;
  274. }
  275. private function datetime2timestamp($string) {
  276. list($date, $time) = explode(' ', $string);
  277. list($year, $month, $day) = explode('-', $date);
  278. list($hour, $minute, $second) = explode(':', $time);
  279. $timestamp = mktime($hour, $minute, $second, $month, $day, $year);
  280. return $timestamp;
  281. }
  282. public function natConvert($string)
  283. {
  284. // CREDITS: DRUPAL NATSORT PGSQL function
  285. // Our task is to expand all numbers to have a fixed number of digits.
  286. // 'I want 3.5 potatoes' -> 'I want [0000003500] potatoes'.
  287. // Let's start by delimiting all numbers by the '~' character.
  288. // 'I want 3.5 potatoes' -> 'I want ~3.5~ potatoes'.
  289. $string = str_replace("~", "", $string);
  290. $string = preg_replace('/([0-9]*\.?[0-9]+|[0-9][0-9,]+\.?[0-9,]*[0-9])/i', '~${1}~', $string);
  291. // Now, let's split the string, on the '~' character, and loop over the elements.
  292. // Odd elemenets are numbers. Even ones are texts.
  293. $array_decoupe = explode("~",$string);
  294. $part = "";
  295. foreach ($array_decoupe as $key=>$item)
  296. {
  297. if ($key % 2 == 0)
  298. {
  299. $part.= strtolower($item);
  300. }
  301. else
  302. {
  303. $item = number_format($item, 3, '', '');
  304. $item = str_pad($item, 10, "0", STR_PAD_LEFT);
  305. $part.= "[".$item."]";
  306. }
  307. }
  308. $bad_word = array(",",":",".",";","(",")");
  309. $part = str_replace($bad_word, "", $part);
  310. return $part;
  311. }
  312. public function getInserted_directory()
  313. {
  314. return $this->inserted_directory;
  315. }
  316. public function getSkipped_directory()
  317. {
  318. return $this->skipped_directory;
  319. }
  320. public function getInserted_file()
  321. {
  322. return $this->inserted_file;
  323. }
  324. public function getUpdated_file()
  325. {
  326. return $this->updated_file;
  327. }
  328. public function getSkipped_file()
  329. {
  330. return $this->skipped_file;
  331. }
  332. }
  333. ?>