Source for file admin.php

Documentation is available at admin.php

  1. <?php
  2.  
  3. /**
  4. * @package net.siriux.photos
  5. * @author The Midgard Project, http://www.midgard-project.org
  6. * @version $Id: admin.php,v 1.20.2.4 2005/11/20 17:41:05 rambo Exp $
  7. * @copyright The Midgard Project, http://www.midgard-project.org
  8. * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
  9. */
  10.  
  11. /**
  12. * Photo Gallery Admin Class
  13. *
  14. * @todo document
  15. *
  16. * @package net.siriux.photos
  17. */
  18. class net_siriux_photos_admin {
  19.  
  20. var $_debug_prefix;
  21.  
  22. var $_config;
  23. var $_config_dm;
  24. var $_topic;
  25. var $_photo;
  26. var $_upload_datamanager;
  27.  
  28. var $_view;
  29. var $_view_status;
  30.  
  31. var $_numpics;
  32. var $_startfrom;
  33. var $_scales;
  34. var $_enable_notes;
  35. var $_l10n;
  36. var $_l10n_midcom;
  37.  
  38. var $errcode;
  39. var $errstr;
  40. var $_local_toolbar;
  41. var $_topic_toolbar;
  42. function net_siriux_photos_admin($topic, $config) {
  43. $this->_debug_prefix = "net.siriux.photos admin::";
  44.  
  45. $this->_startfrom = 0;
  46.  
  47. $this->_config = $config;
  48. $this->_config_dm = null;
  49. $this->_topic = $topic;
  50. $this->_photo = false;
  51. $this->_upload_datamanager = null;
  52. /* show 10 pics per page on index */
  53. $this->_numpics = 10;
  54.  
  55. $this->_view = "";
  56. $this->_view_status = "";
  57.  
  58. $this->_scales = Array (
  59. "view_x" => $config->get("view_x"),
  60. "view_y" => $config->get("view_x"),
  61. "thumb_x" => $config->get("thumb_x"),
  62. "thumb_y" => $config->get("thumb_y")
  63. );
  64. $this->_enable_notes = $config->get("enable_flash_notes");
  65. $i18n =& $GLOBALS["midcom"]->get_service("i18n");
  66. $this->_l10n = $i18n->get_l10n("net.siriux.photos");
  67. $this->_l10n_midcom = $i18n->get_l10n("midcom");
  68. $GLOBALS["view_l10n"] = $this->_l10n;
  69. $GLOBALS["view_l10n_midcom"] = $this->_l10n_midcom;
  70. $this->errcode = MIDCOM_ERROK;
  71. $this->errstr = "";
  72. $this->_local_toolbar =& $GLOBALS['midcom_admin_content_toolbar_component'];
  73. $this->_topic_toolbar =& $GLOBALS['midcom_admin_content_toolbar_main'];
  74. }
  75.  
  76.  
  77. /* functions called by the proxy class (contentadmin) */
  78.  
  79.  
  80. function can_handle($argc, $argv)
  81. {
  82. debug_push($this->_debug_prefix."can_handle");
  83. $GLOBALS["midcom"]->set_custom_context_data("configuration", $this->_config);
  84. $GLOBALS["midcom"]->set_custom_context_data("l10n", $this->_l10n);
  85. $GLOBALS["midcom"]->set_custom_context_data("l10n_midcom", $this->_l10n_midcom);
  86. $GLOBALS["midcom"]->set_custom_context_data("errstr", $this->errstr);
  87. debug_pop();
  88. if ($argc == 0)
  89. {
  90. return true;
  91. }
  92. switch ($argv[0])
  93. {
  94. case "upload":
  95. case "config":
  96. case "rereadexif":
  97. case "synccreated":
  98. case 'cleanupnames':
  99. case 'rebuildthumbs':
  100. case 'notes_locale':
  101. return ($argc == 1);
  102. case "edit":
  103. case "delete":
  104. case 'rotate_cw':
  105. case 'rotate_ccw':
  106. case 'notes_save':
  107. case 'notes':
  108. return ($argc == 2);
  109. default:
  110. return false;
  111. }
  112. }
  113.  
  114.  
  115. function handle($argc, $argv)
  116. {
  117. debug_push($this->_debug_prefix . "handle");
  118. /* Add the topic configuration item */
  119. $this->_topic_toolbar->add_item(Array(
  120. MIDCOM_TOOLBAR_URL => 'config.html',
  121. MIDCOM_TOOLBAR_LABEL => $this->_l10n_midcom->get('component configuration'),
  122. MIDCOM_TOOLBAR_HELPTEXT => $this->_l10n_midcom->get('component configuration helptext'),
  123. MIDCOM_TOOLBAR_ICON => 'stock-icons/16x16/stock_folder-properties.png',
  124. MIDCOM_TOOLBAR_ENABLED => true
  125. ));
  126. /* Add the new article link at the beginning*/
  127. $this->_topic_toolbar->add_item(Array(
  128. MIDCOM_TOOLBAR_URL => 'upload.html',
  129. MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('upload photos'),
  130. MIDCOM_TOOLBAR_HELPTEXT => null,
  131. MIDCOM_TOOLBAR_ICON => 'stock-icons/16x16/images.png',
  132. MIDCOM_TOOLBAR_ENABLED => true
  133. ), 0);
  134. // pass startfrom value
  135. if (isset($_REQUEST) && array_key_exists("startfrom", $_REQUEST))
  136. {
  137. $this->_startfrom = $_REQUEST["startfrom"];
  138. }
  139. else
  140. {
  141. $this->_startfrom = 0;
  142. }
  143. if ($this->_startfrom % $this->_numpics > 0)
  144. {
  145. $this->_startfrom -= ($this->_startfrom % $this->_numpics);
  146. }
  147.  
  148. if ($argc == 0)
  149. {
  150. debug_pop();
  151. return $this->_init_index();
  152. }
  153.  
  154. switch ($argv[0]) {
  155. case "upload":
  156. $result = $this->_init_upload();
  157. break;
  158. case "config":
  159. $result = $this->_init_config();
  160. break;
  161. case "rereadexif":
  162. $result = $this->_init_reread_exif_timestamps();
  163. break;
  164. case "synccreated":
  165. $result = $this->_init_sync_article_created();
  166. break;
  167. case 'cleanupnames':
  168. $result = $this->_init_cleanup_names();
  169. break;
  170. case 'rebuildthumbs':
  171. $result = $this->_init_rebuild_thumbs();
  172. break;
  173. case "edit":
  174. $result = $this->_init_edit($argv[1]);
  175. break;
  176. case "delete":
  177. $result = $this->_init_delete($argv[1]);
  178. break;
  179. case 'rotate_cw':
  180. $result = $this->_init_rotate(90, $argv[1]);
  181. break;
  182. case 'rotate_ccw':
  183. $result = $this->_init_rotate(-90, $argv[1]);
  184. break;
  185. case 'notes_locale':
  186. $this->_show_notes_locale();
  187. break;
  188. case 'notes_save':
  189. $result = $this->_init_notes_save($argv[1]);
  190. break;
  191. case 'notes':
  192. $result = $this->_show_notes($argv[1]);
  193. break;
  194. default:
  195. $result = false;
  196. break;
  197. }
  198.  
  199. debug_pop();
  200. return $result;
  201. }
  202. function show() {
  203. global $view_title;
  204.  
  205. // get l10n libraries
  206. $i18n =& $GLOBALS["midcom"]->get_service("i18n");
  207. $GLOBALS["view_l10n"] = $i18n->get_l10n("net.siriux.photos");
  208. $GLOBALS["view_l10n_midcom"] = $i18n->get_l10n("midcom");
  209.  
  210. $view_title = $this->_topic->extra;
  211. eval("\$result = \$this->_show_{$this->_view}();");
  212. return $result;
  213. }
  214.  
  215.  
  216. /* init functions, handle request and prepare output */
  217. /**
  218. * Rotate image init function, relocates to the index by default. Rotation
  219. * is controllable through the callee.
  220. *
  221. * @param int $degrees Number of degrees to rotate the image.
  222. * @param int $id The ID of the image to rotate.
  223. * @return bool false on failure, success relocates back to the AIS index.
  224. * @todo Make relocation target flexible
  225. */
  226. function _init_rotate ($degrees, $id)
  227. {
  228. debug_add("Rotating Photo {$id} {$degrees}° clockwise.", MIDCOM_LOG_DEBUG);
  229. $photo = new siriux_photos_Photo($id);
  230. if ($photo)
  231. {
  232. debug_add('Photo loaded, executing $photo->rotate');
  233. $photo->rotate($degrees);
  234. // Flush MidCOM cache
  235. debug_add("Invalidating MidCOM cache", MIDCOM_LOG_DEBUG);
  236. $GLOBALS['midcom']->cache->invalidate($photo->article->guid());
  237. $GLOBALS['midcom']->relocate($GLOBALS['midcom']->get_context_data(MIDCOM_CONTEXT_ANCHORPREFIX)
  238. . "?startfrom={$this->_startfrom}");
  239. // This will exit
  240. }
  241. else
  242. {
  243. $this->errcode = MIDCOM_ERRCRIT;
  244. $this->errstr = "Could not load Photo {$id}: " . mgd_errstr();
  245. return false;
  246. }
  247. }
  248. function _init_index() {
  249. debug_push($this->_debug_prefix . "_init_index");
  250. $this->_view = "index";
  251.  
  252. // handle approval
  253. if (isset($_REQUEST))
  254. {
  255. if (array_key_exists("approve", $_REQUEST))
  256. {
  257. debug_add("Approving Photo " . $_REQUEST["approve"], MIDCOM_LOG_DEBUG);
  258. $article = mgd_get_article($_REQUEST['approve']);
  259. if ($article)
  260. {
  261. $meta = midcom_helper_metadata::retrieve($article);
  262. $meta->approve();
  263. }
  264. else
  265. {
  266. debug_add("Could not approve Photo " . $_REQUEST["approve"], MIDCOM_LOG_WARN);
  267. $GLOBALS['midcom']->generate_error(MIDCOM_ERRCRIT, "Could not approve Photo {$_REQUEST['approve']}: " . mgd_errstr());
  268. }
  269. }
  270. else if (array_key_exists("unapprove", $_REQUEST))
  271. {
  272. debug_add("Unapproving Photo " . $_REQUEST["unapprove"], MIDCOM_LOG_DEBUG);
  273. $article = mgd_get_article($_REQUEST['unapprove']);
  274. if ($article)
  275. {
  276. $meta = midcom_helper_metadata::retrieve($article);
  277. $meta->unapprove();
  278. }
  279. else
  280. {
  281. debug_add("Could not unapprove Photo " . $_REQUEST["unapprove"], MIDCOM_LOG_WARN);
  282. $GLOBALS['midcom']->generate_error(MIDCOM_ERRCRIT, "Could not unapprove Photo {$_REQUEST['unapprove']}: " . mgd_errstr());
  283. }
  284. }
  285. }
  286. debug_pop();
  287. return true;
  288. }
  289.  
  290. function _show_index() {
  291. global $view_ids;
  292. global $view_prev;
  293. global $view_next;
  294. global $view_startfrom;
  295. $GLOBALS['view_thumbs_x'] = 1;
  296. $GLOBALS['view_thumbs_y'] = $this->_numpics;
  297. $view_ids = false;
  298. $view_prev = -1;
  299. $view_next = -1;
  300. $view_startfrom = $this->_startfrom;
  301.  
  302. $articles = mgd_list_topic_articles($this->_topic->id, $this->_config->get("sort_order"));
  303. if ($articles) {
  304. $GLOBALS['view_total'] = $articles->N;
  305. $count = 0;
  306. while ($articles->fetch())
  307. {
  308. if ( $count >= $this->
  309. _startfrom
  310. && $count < ($this->_startfrom + $this->_numpics))
  311. {
  312. $view_ids[] = $articles->id;
  313. }
  314. $count++;
  315. }
  316. }
  317. midcom_show_style("admin_index");
  318. }
  319.  
  320.  
  321. function _init_upload() {
  322. debug_push($this->_debug_prefix . "_init_upload");
  323. $this->_view = "upload";
  324. $this->_local_toolbar->add_item(Array(
  325. MIDCOM_TOOLBAR_URL => '',
  326. MIDCOM_TOOLBAR_LABEL => $this->_l10n_midcom->get('back to index'),
  327. MIDCOM_TOOLBAR_HELPTEXT => null,
  328. MIDCOM_TOOLBAR_ICON => 'stock-icons/16x16/folder.png',
  329. MIDCOM_TOOLBAR_ENABLED => true
  330. ));
  331. $this->_local_toolbar->disable_view_page();
  332. /* We create a datamanager who's sole purpose is to display an
  333. * uplaod form here. The specificied callback does not exist,
  334. * processing the resulting form is not an option here therefore,
  335. * the upload handler will do some hacks here to do the true
  336. * upload.
  337. */
  338. $GLOBALS["view_l10n"] = $this->_l10n;
  339. $this->_upload_datamanager = new midcom_helper_datamanager($this->_config->get("schemadb"));
  340. if (! $this->_upload_datamanager) {
  341. $this->errstr = "Failed to create the upload datamanager instance. Aborting.";
  342. $this->errcode = MIDCOM_ERRCRIT;
  343. return false;
  344. }
  345. if (! $this->_upload_datamanager->init_creation_mode($this->_config->get("schema_upload"), $this, "xxx")) {
  346. $this->errstr = "Failed to initialize the upload datamanager instance. Aborting.";
  347. $this->errcode = MIDCOM_ERRCRIT;
  348. return false;
  349. }
  350. if (array_key_exists('upload_complete', $_REQUEST))
  351. {
  352. $GLOBALS['view_contentmgr']->msg .= $_REQUEST['upload_complete'];
  353. }
  354. $this->_view_status = $this->_process_upload();
  355. debug_pop();
  356. return true;
  357. }
  358.  
  359.  
  360. function _process_upload() {
  361. debug_push($this->_debug_prefix . "_process_upload");
  362. /* This function handles the upload in a rather hacky way:
  363. *
  364. * The data, that has been submitted using the upload datamanager
  365. * will not be evaluated by that datamanager. Instead, the uploaded file
  366. * will be processed manually, and a new datamanager without the
  367. * upload field but with (at least) all other fields will be used instead.
  368. *
  369. * This is some averagly serious hack of the DM, and should be handled
  370. * with its due respect. If in doubt, ask me (torben@nehmer.net).
  371. *
  372. * If we have mulitple upload files, we display a progress log and redirect
  373. * to the (now empty) upload form. This is neccessary as Apache would kill
  374. * us after 2 mins of no-output-time.
  375. */
  376. /* 1st, we determine if we had a successfully posted request, if not, exit here */
  377. if (! array_key_exists("midcom_helper_datamanager_submit", $_REQUEST)) {
  378. debug_add("No upload form was submitted, exiting");
  379. debug_pop();
  380. return "";
  381. }
  382. /* 2nd, do a sanity check against the uploaded file */
  383. if (! array_key_exists("midcom_helper_datamanager_field_upload_file", $_FILES)) {
  384. debug_add("No file was uploaded.");
  385. debug_pop();
  386. return "No file was uploaded.<br />\n";
  387. }
  388. /* 3rd, check if we need to create a subtopic */
  389. $create_subgallery = FALSE;
  390. if ( array_key_exists("midcom_helper_datamanager_field_create_subgallery", $_REQUEST)
  391. && $_REQUEST["midcom_helper_datamanager_field_create_subgallery"] == "on")
  392. {
  393. $create_subgallery = TRUE;
  394. }
  395. $midgard = $GLOBALS["midcom"]->midgard;
  396. $result = "";
  397. $file = $_FILES["midcom_helper_datamanager_field_upload_file"];
  398. debug_print_r("Processing upload of this file:", $file);
  399. // Ignore client-side aborts for now, to avoid incomplete uploads due to the
  400. // Client Timeouts until the upload sequence is complete.
  401. debug_add('Disabling script abort through client.');
  402. ignore_user_abort(true);
  403. /* Scan for compressed files using the file name extension */
  404. $file_extensions = explode(".",strtolower($file["name"]));
  405. $file_extension = $file_extensions[((count($file_extensions)) - 1)];
  406. $compressed = false;
  407. $uploadtempdir = "/tmp/net.siriux.photos.upload." . time() . "." . getmypid();
  408. switch ($file_extension)
  409. {
  410. case "zip":
  411. $compressed = true;
  412. $unzipcmd =
  413. "{$GLOBALS['midcom_config']['utility_unzip']} "
  414. . escapeshellarg($file['tmp_name'])
  415. . " -d{$uploadtempdir}";
  416. break;
  417. case "gz":
  418. case "tgz":
  419. $compressed = true;
  420. $unzipcmd =
  421. "cd {$uploadtempdir} ; {$GLOBALS['midcom_config']['utility_tar']} -xzf "
  422. . escapeshellarg($file["tmp_name"]);
  423. break;
  424. default:
  425. $compressed = false;
  426. $uncompresscmd = "";
  427. break;
  428. }
  429. /* Depending on wether we have a compressed file, we do now
  430. * create a list of files to process. (So this could very well
  431. * be a single file.
  432. */
  433. $files = Array();
  434. if ($compressed)
  435. {
  436. $GLOBALS['midcom']->cache->content->enable_live_mode();
  437. $title = $this->_l10n->get('processing upload, please wait');
  438. ?>
  439. <html>
  440. <body>
  441. <h1><?php echo $title; ?>...</h1>
  442. <pre>
  443. Extracting archive...<?php
  444. flush();
  445. debug_add("executing upzip command: $unzipcmd");
  446. exec("mkdir {$uploadtempdir}");
  447. exec($unzipcmd);
  448. $find_result = Array();
  449. exec("{$GLOBALS['midcom_config']['utility_find']} {$uploadtempdir} -type f", $find_result);
  450. foreach ($find_result as $fullname)
  451. {
  452. if (! $this->check_uploaded_image($fullname))
  453. {
  454. // Not a valid image recognized by imagemagick.
  455. continue;
  456. }
  457. $lastslash = strrpos($fullname, '/');
  458. // We should always have at least two slashes, see the
  459. // definition of uploadtempdir above.
  460. $file = substr($fullname, $lastslash + 1);
  461. $files[$fullname] = $file;
  462. }
  463. echo " done\n";
  464. flush();
  465. }
  466. else
  467. {
  468. $files[$file["tmp_name"]] = $file["name"];
  469. }
  470. debug_print_r("We have to process these " . count($files) . " files:", $files);
  471. if ($create_subgallery)
  472. {
  473. // Create subgallery as user requested
  474. $subgallery = mgd_get_topic();
  475. $subgallery->up = $this->_topic->id;
  476. // Figure out a title for the topic
  477. if ($_REQUEST["midcom_helper_datamanager_field_title"] != "")
  478. {
  479. $subgallery->extra = $_REQUEST["midcom_helper_datamanager_field_title"];
  480. }
  481. else
  482. {
  483. // No user-supplied title for the gallery, use uploaded file's name
  484. // TODO: Remove file extension from the name
  485. $subgallery->extra = $_FILES["midcom_helper_datamanager_field_upload_file"]["name"];
  486. }
  487. $subgallery->name = midcom_generate_urlname_from_string($subgallery->extra);
  488. $subgallery_created = $subgallery->create();
  489. if (!$subgallery_created)
  490. {
  491. $GLOBALS["midcom"]->generate_error(MIDCOM_ERRCRIT,
  492. "Subgallery creation failed, reason " . mgd_errstr());
  493. // This will exit
  494. }
  495. $subgallery = mgd_get_topic($subgallery_created);
  496. $subgallery->parameter("midcom","component","net.siriux.photos");
  497. // Copy local gallery configuration
  498. $local_configuration = $this->_topic->listparameters("net.siriux.photos");
  499. while ( $local_configuration
  500. && $local_configuration->fetch())
  501. {
  502. $subgallery->parameter("net.siriux.photos", $local_configuration->name, $this->_topic->parameter("net.siriux.photos", $local_configuration->name));
  503. }
  504. }
  505. // Handle the upload, process each file in the array.
  506. $i = 0;
  507. $files_to_do = count($files) + 1;
  508. $file_at_work = 0;
  509. foreach ($files as $filename => $realname)
  510. {
  511. debug_add("Processing image {$realname} from {$filename}", MIDCOM_LOG_INFO);
  512. $file_at_work++;
  513. if ($compressed)
  514. {
  515. echo "Processing image {$realname} ({$file_at_work}/{$files_to_do})...";
  516. flush();
  517. }
  518. // Update script execution time
  519. set_time_limit(30);
  520. // Instantiate the photo object
  521. if ($create_subgallery)
  522. {
  523. // Create the photos into the newly created subgallery
  524. $photo = new siriux_photos_Photo(FALSE, null, $subgallery);
  525. }
  526. else
  527. {
  528. // Create the photos into this gallery
  529. $photo = new siriux_photos_Photo();
  530. }
  531. if ($photo->create_from_datamanager($filename, $realname))
  532. {
  533. $i++;
  534. if ($photo->article->title != "")
  535. {
  536. if (count($files) > 1)
  537. {
  538. $photo->article->title .= " {$i}";
  539. }
  540. }
  541. else
  542. {
  543. $photo->article->title = $photo->article->name;
  544. }
  545. $photo->article->update();
  546. // Recreate URL name from title only if mandated by config.
  547. if ($this->_config->get("create_urlname_from_title"))
  548. {
  549. $photo->article->name = midcom_generate_urlname_from_string($photo->article->title);
  550. $photo->article->update();
  551. }
  552. debug_add("Sucessfully uploaded {$filename} from {$realname}");
  553. if ($compressed)
  554. {
  555. // Report only failures during batch processing
  556. echo " done\n";
  557. flush();
  558. }
  559. else
  560. {
  561. $result .= "Successfully uploaded {$realname}<br\>\n";
  562. }
  563. }
  564. else
  565. {
  566. debug_add("Failed to upload {$filename} from {$realname}: {$this->errstr}", MIDCOM_LOG_WARN);
  567. $result .= "Failed to upload {$realname}: {$this->errstr}<br\>\n";
  568. if ($compressed)
  569. {
  570. echo " <span style='color:red;'>failed: {$this->errstr}</span>\n";
  571. flush();
  572. }
  573. }
  574. $photo->datamanager->destroy();
  575. }
  576. // Reset script execution time limit to some sane value for the rest
  577. // of the script.
  578. set_time_limit(20);
  579. /* Clean up all temporary files we are responsible for. */