Rev Author Line No. Line
228 kaklik 1 <?php
2  
3 /**
4 * Class providing admin functions.
5 *
6 * @package singapore
7 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License
8 * @copyright (c)2003-2006 Tamlyn Rhodes
9 * @version $Id: admin.class.php,v 1.65 2006/09/08 15:29:22 tamlyn Exp $
10 */
11  
12 define("SG_ADMIN", 1024);
13 define("SG_SUSPENDED", 2048);
14  
15 //include the base IO class
16 require_once dirname(__FILE__)."/singapore.class.php";
17  
18  
19 /**
20 * Provides gallery, image and user administration functions.
21 *
22 * @uses Singapore
23 * @package singapore
24 * @author Tamlyn Rhodes <tam at zenology dot co dot uk>
25 */
26 class sgAdmin extends Singapore
27 {
28 /**
29 * Array of error messages raised by the script
30 * @var array
31 */
32 var $errors = array();
33  
34 /**
35 * Array of informational messages raised by the script
36 * @var array
37 */
38 var $messages = array();
39  
40 /**
41 * Base name of admin template file to include
42 * @var string
43 */
44 var $includeFile = "login";
45  
46 /**
47 * Admin constructor. Doesn't call {@link Singapore} constructor.
48 * @param string the path to the base singapore directory
49 */
50 function sgAdmin($basePath = "")
51 {
52 //import class definitions
53 //io handler class included once config is loaded
54 require_once $basePath."includes/translator.class.php";
55 require_once $basePath."includes/thumbnail.class.php";
56 require_once $basePath."includes/gallery.class.php";
57 require_once $basePath."includes/config.class.php";
58 require_once $basePath."includes/image.class.php";
59 require_once $basePath."includes/user.class.php";
60  
61 //start execution timer
62 $this->scriptStartTime = microtime();
63  
64 //remove slashes
65 if(get_magic_quotes_gpc()) {
66 $_REQUEST = array_map(array("Singapore","arraystripslashes"), $_REQUEST);
67  
68 //as if magic_quotes_gpc wasn't insane enough, php doesn't add slashes
69 //to the tmp_name variable so I have to add them manually. Grrrr.
70 foreach($_FILES as $key => $nothing)
71 $_FILES[$key]["tmp_name"] = addslashes($_FILES[$key]["tmp_name"]);
72 $_FILES = array_map(array("Singapore","arraystripslashes"), $_FILES);
73 }
74  
75 $galleryId = isset($_REQUEST["gallery"]) ? $_REQUEST["gallery"] : ".";
76  
77 //load config from singapore root directory
78 $this->config =& sgConfig::getInstance();
79 $this->config->loadConfig($basePath."singapore.ini");
80 $this->config->loadConfig($basePath."secret.ini.php");
81  
82 //set runtime values
83 $this->config->pathto_logs = $this->config->pathto_data_dir."logs/";
84 $this->config->pathto_cache = $this->config->pathto_data_dir."cache/";
85 $this->config->pathto_current_template = $this->config->pathto_templates.$this->config->default_template."/";
86 $this->config->pathto_admin_template = $this->config->pathto_templates.$this->config->admin_template_name."/";
87  
88 //load config from admin template ini file (admin.ini) if present
89 $this->config->loadConfig($basePath.$this->config->pathto_admin_template."admin.ini");
90  
91 $this->template = $this->config->default_template;
92  
93 //do not load gallery-specific ini files
94  
95 //set current language from request vars or config
96 $this->language = isset($_REQUEST["lang"]) ? $_REQUEST["lang"] : $this->config->default_language;
97 //read the language file
98 $this->translator =& Translator::getInstance($this->language);
99 $this->translator->readLanguageFile($this->config->base_path.$this->config->pathto_locale."singapore.".$this->language.".pmo");
100 $this->translator->readLanguageFile($this->config->base_path.$this->config->pathto_locale."singapore.admin.".$this->language.".pmo");
101  
102 //include IO handler class and create instance
103 require_once $basePath."includes/io_".$this->config->io_handler.".class.php";
104 $ioClassName = "sgIO_".$this->config->io_handler;
105 $this->io = new $ioClassName($this->config);
106  
107 //set character set
108 if(!empty($this->translator->languageStrings[0]["charset"]))
109 $this->character_set = $this->translator->languageStrings[0]["charset"];
110 else
111 $this->character_set = $this->config->default_charset;
112  
113 //set action to perform
114 if(empty($_REQUEST["action"])) $this->action = "menu";
115 else $this->action = $_REQUEST["action"];
116  
117 //set page title
118 $this->pageTitle = $this->config->gallery_name;
119  
120 //set root node of crumb line
121 $holder = new sgGallery("", new stdClass);
122 $holder->name = $this->config->gallery_name;
123 $this->ancestors = array($holder);
124 }
125  
126 /**
127 * Push an error message onto the error stack
128 * @param string Error message
129 * @param string true if error is fatal; false otherwise (optional)
130 * @return false
131 */
132 function pushError($error, $fatal = false)
133 {
134 if($fatal) die($error);
135 $this->errors[] = $error;
136 return false;
137 }
138  
139 /**
140 * Push a message onto the message stack
141 * @return true
142 */
143 function pushMessage($message)
144 {
145 $this->messages[] = $message;
146 return true;
147 }
148  
149 function showMessages()
150 {
151 if(empty($this->errors) && empty($this->messages)) return '';
152  
153 $errorText = $this->translator->_g("ERROR");
154 $ret = '<ul id="sgAdminMessages">';
155 foreach($this->errors as $error)
156 $ret .= '<li class="adminError">'.$errorText.': '.$error.'</li>'."\n";
157 foreach($this->messages as $message)
158 $ret .= '<li class="adminMessage">'.$message.'</li>'."\n";
159 $ret .= '</ul>';
160  
161 return $ret;
162 }
163  
164 /**
165 * Returns a link to the image or gallery with the correct formatting and path
166 * NOTE: This takes its arguments in a different order to {@link Singapore::formatURL()}
167 *
168 * @author Adam Sissman <adam at bluebinary dot com>
169 */
170 function formatAdminURL($action, $gallery = null, $image = null, $startat = null, $extra = null)
171 {
172 $ret = $this->config->base_url."admin.php?";
173 $ret .= "action=".$action;
174 if($gallery != null) $ret .= "&amp;gallery=".$gallery;
175 if($image != null) $ret .= "&amp;image=".$image;
176 if($startat != null) $ret .= "&amp;startat=".$startat;
177 if($extra != null) $ret .= $extra;
178 if($this->language != $this->config->default_language) $ret .= '&amp;'.$this->config->url_lang.'='.$this->language;
179 if($this->template != $this->config->default_template) $ret .= '&amp;'.$this->config->url_template.'='.$this->template;
180  
181 return $ret;
182 }
183  
184 /**
185 * Tries to find temporary storage space
186 */
187 function findTempDirectory()
188 {
189 if(isset($_ENV["TMP"]) && is_writable($_ENV["TMP"])) return $_ENV["TMP"];
190 elseif(isset($_ENV["TEMP"]) && is_writable($_ENV["TEMP"])) return $_ENV["TEMP"];
191 elseif(is_writable("/tmp")) return "/tmp";
192 elseif(is_writable("/windows/temp")) return "/windows/temp";
193 elseif(is_writable("/winnt/temp")) return "/winnt/temp";
194 else return null;
195 }
196  
197 function getMaxHits($array)
198 {
199 $max = 0;
200 foreach($array as $obj)
201 if($obj->hits > $max)
202 $max = $obj->hits;
203 return $max;
204 }
205  
206 /**
207 * Returns true if the current admin action has been confirmed (i.e. by clicking OK)
208 */
209 function actionConfirmed()
210 {
211 return isset($_REQUEST["confirmed"]) && $_REQUEST["confirmed"] == $this->translator->_g("confirm|OK");
212 }
213  
214 /**
215 * Returns true if the current admin action has been cancelled (i.e. by clicking Cancel)
216 */
217 function actionCancelled()
218 {
219 return isset($_REQUEST["confirmed"]) && $_REQUEST["confirmed"] == $this->translator->_g("confirm|Cancel");
220 }
221  
222 /**
223 * Checks request variables for action to perform, checks user permissions,
224 * performs action and sets file to include.
225 */
226 function doAction()
227 {
228 //check if user is logged in
229 if(!$this->isLoggedIn() && $this->action != "login")
230 return;
231  
232 //choose which file to include and/or perform admin actions
233 switch($this->action) {
234 case "addgallery" :
235 $this->selectGallery();
236 if(!$this->checkPermissions($this->gallery,"add")) {
237 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
238 $this->includeFile = "view";
239 } elseif($this->addGallery()) {
240 $this->selectGallery($this->gallery->id."/".$_REQUEST["newgallery"]);
241 $this->pushMessage($this->translator->_g("Gallery added"));
242 $this->includeFile = "editgallery";
243 } else {
244 $this->includeFile = "newgallery";
245 }
246 break;
247 case "addimage" :
248 $this->selectGallery();
249 if(!$this->checkPermissions($this->gallery,"add")) {
250 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
251 $this->includeFile = "view";
252 break;
253 }
254 switch($_REQUEST["sgLocationChoice"]) {
255 case "remote" :
256 case "single" :
257 if($this->addImage())
258 $this->includeFile = "editimage";
259 else
260 $this->includeFile = "newimage";
261 break;
262 case "multi" :
263 if($this->addMultipleImages())
264 $this->includeFile = "view";
265 else
266 $this->includeFile = "newimage";
267 break;
268 default :
269 $this->includeFile = "newimage";
270 break;
271 }
272 break;
273 case "changethumbnail" :
274 $this->selectGallery();
275 if(!$this->checkPermissions($this->gallery,"edit")) {
276 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
277 $this->includeFile = "view";
278 } elseif($this->actionConfirmed()) {
279 $this->saveGalleryThumbnail();
280 $this->includeFile = "editgallery";
281 } elseif($this->actionCancelled()) {
282 $this->includeFile = "editgallery";
283 } else {
284 $this->includeFile = "changethumbnail";
285 }
286 break;
287 case "deletegallery" :
288 $this->selectGallery();
289 if(!$this->checkPermissions($this->gallery,"delete")) {
290 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
291 $this->includeFile = "view";
292 } elseif($this->actionConfirmed() || ($this->gallery->galleryCount()==0 && $this->gallery->imageCount()==0)) {
293 if($this->deleteGallery())
294 $this->selectGallery($this->gallery->parent->id);
295 $this->includeFile = "view";
296 } elseif($this->actionCancelled()) {
297 $this->includeFile = "view";
298 } else {
299 $GLOBALS["confirmTitle"] = $this->translator->_g("Delete Gallery");
300 $GLOBALS["confirmMessage"] = $this->translator->_g("Gallery %s is not empty.\nAre you sure you want to irretrievably delete it and all subgalleries and images it contains?", "<em>".$this->gallery->name."</em>");
301 $this->includeFile = "confirm";
302 }
303 break;
304 case "deleteimage" :
305 $this->selectGallery();
306 if(!$this->checkPermissions($this->gallery,"delete")) {
307 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
308 $this->includeFile = "view";
309 } elseif($this->actionConfirmed()) {
310 $this->deleteImage();
311 $this->includeFile = "view";
312 } elseif($this->actionCancelled()) {
313 $this->includeFile = "view";
314 } else {
315 $GLOBALS["confirmTitle"] = $this->translator->_g("delete image");
316 $GLOBALS["confirmMessage"] = $this->translator->_g("Are you sure you want to irretrievably delete image %s from gallery %s?","<em>".$this->image->name().$this->image->byArtistText()."</em>","<em>".$this->gallery->name()."</em>");
317 $this->includeFile = "confirm";
318 }
319 break;
320 case "deleteuser" :
321 if(!$this->user->isAdmin()) {
322 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
323 $this->includeFile = "menu";
324 } elseif($this->actionConfirmed()) {
325 if($this->deleteUser())
326 $this->pushMessage($this->translator->_g("User deleted"));
327 $this->includeFile = "manageusers";
328 } elseif($this->actionCancelled()) {
329 $this->includeFile = "manageusers";
330 } else {
331 $GLOBALS["confirmTitle"] = $this->translator->_g("delete user");
332 $GLOBALS["confirmMessage"] = $this->translator->_g("Are you sure you want to permanently delete user %s?","<em>".$_REQUEST["user"]."</em>");
333 $this->includeFile = "confirm";
334 }
335 break;
336 case "editgallery" :
337 $this->selectGallery();
338 if(!$this->checkPermissions($this->gallery,"edit")) {
339 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
340 $this->includeFile = "view";
341 } else
342 $this->includeFile = "editgallery";
343 break;
344 case "editimage" :
345 $this->selectGallery();
346 if(!$this->checkPermissions($this->gallery,"edit")) {
347 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
348 $this->includeFile = "view";
349 } else
350 $this->includeFile = "editimage";
351 break;
352 case "editpass" :
353 if($this->user->isGuest()) {
354 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
355 $this->includeFile = "menu";
356 } else
357 $this->includeFile = "editpass";
358 break;
359 case "editpermissions" :
360 $this->selectGallery();
361 if(!$this->user->isAdmin() && !$this->user->isOwner($this->gallery)) {
362 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
363 $this->includeFile = "view";
364 } else
365 $this->includeFile = "editpermissions";
366 break;
367 case "editprofile" :
368 if($this->user->isGuest()) {
369 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
370 $this->includeFile = "menu";
371 } else
372 $this->includeFile = "editprofile";
373 break;
374 case "edituser" :
375 if(!$this->user->isAdmin() && $_REQUEST["user"] != $this->user->username || $this->user->isGuest()) {
376 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
377 $this->includeFile = "menu";
378 } else
379 $this->includeFile = "edituser";
380 break;
381 case "login" :
382 if($this->doLogin())
383 $this->includeFile = "menu";
384 else
385 $this->includeFile = "login";
386 break;
387 case "logout" :
388 $this->logout();
389 $this->includeFile = "login";
390 break;
391 case "manageusers" :
392 if(!$this->user->isAdmin()) {
393 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
394 $this->includeFile = "menu";
395 } else
396 $this->includeFile = "manageusers";
397 break;
398 case "multi" :
399 $this->selectGallery();
400 if(!isset($_REQUEST["sgGalleries"]) && !isset($_REQUEST["sgImages"])) {
401 $this->pushMessage($this->translator->_g("Please select one or more items."));
402 $this->includeFile = "view";
403 } elseif($_REQUEST["subaction"]==$this->translator->_g("Copy or move")) {
404 $this->includeFile = "multimove";
405 } elseif($_REQUEST["subaction"]==$this->translator->_g("Delete")) {
406 if(!$this->checkPermissions($this->gallery,"delete")) {
407 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
408 $this->includeFile = "view";
409 } elseif($this->actionConfirmed()) {
410 if(isset($_REQUEST["sgImages"])) {
411 $success = $this->deleteMultipleImages();
412 $this->pushMessage($this->translator->_g("%s images deleted.", $success));
413 } else {
414 $success = $this->deleteMultipleGalleries();
415 $this->pushMessage($this->translator->_g("%s galleries deleted.", $success));
416 }
417 $this->includeFile = "view";
418 } elseif($this->actionCancelled()) {
419 $this->includeFile = "view";
420 } else {
421 if(isset($_REQUEST["sgImages"])) {
422 $GLOBALS["confirmTitle"] = $this->translator->_g("Delete Images");
423 $GLOBALS["confirmMessage"] = $this->translator->_g("Are you sure you want to permanently delete %s images?",count($_REQUEST["sgImages"]));
424 } else{
425 $GLOBALS["confirmTitle"] = $this->translator->_g("Delete Galleries");
426 $GLOBALS["confirmMessage"] = $this->translator->_g("Are you sure you want to permanently delete %s galleries?",count($_REQUEST["sgGalleries"]));
427 }
428 $this->includeFile = "confirm";
429 }
430 } elseif($_REQUEST["subaction"]==$this->translator->_g("Re-index")) {
431 if(is_int($success = $this->reindexMultipleGalleries()))
432 $this->pushMessage($this->translator->_g("Galleries re-indexed. %s total images added.", $success));
433 $this->includeFile = "view";
434 }
435 break;
436 case "multimove" :
437 $this->selectGallery();
438 if($this->actionConfirmed()) {
439 if(isset($_REQUEST["sgImages"])) {
440 //$success = $this->moveMultipleImages();
441 //$this->adminMessage = $this->translator->_g("%s images moved.", $success);
442 $success=true;
443 $this->pushMessage("not yet implemented");
444 } else {
445 $success = $this->moveMultipleGalleries();
446 $this->pushMessage($this->translator->_g("%s galleries moved.", $success));
447 }
448 }
449 $this->includeFile = "view";
450 break;
451 case "newgallery" :
452 $this->selectGallery();
453 if(!$this->checkPermissions($this->gallery,"add")) {
454 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
455 $this->includeFile = "view";
456 } else
457 $this->includeFile = "newgallery";
458 break;
459 case "newimage" :
460 $this->selectGallery();
461 if(!$this->checkPermissions($this->gallery,"add")) {
462 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
463 $this->includeFile = "view";
464 } else
465 $this->includeFile = "newimage";
466 break;
467 case "newuser" :
468 if(!$this->user->isAdmin()) {
469 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
470 $this->includeFile = "menu";
471 } elseif($this->addUser())
472 $this->includeFile = "edituser";
473 else
474 $this->includeFile = "manageusers";
475 break;
476 case "purgecache" :
477 if(!$this->user->isAdmin()) {
478 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
479 $this->includeFile = "menu";
480 } elseif($this->actionConfirmed()) {
481 if($this->purgeCache())
482 $this->pushMessage($this->translator->_g("Thumbnail cache purged"));
483 $this->includeFile = "menu";
484 } elseif($this->actionCancelled()) {
485 $this->includeFile = "menu";
486 } else {
487 $dir = $this->getListing($this->config->pathto_cache,$this->config->recognised_extensions);
488 $GLOBALS["confirmTitle"] = $this->translator->_g("purge cached thumbnails");
489 $GLOBALS["confirmMessage"] = $this->translator->_g("Are you sure you want to delete all %s cached thumbnails?",count($dir->files));
490 $this->includeFile = "confirm";
491 }
492 break;
493 case "reindex" :
494 $this->selectGallery();
495 if(!$this->checkPermissions($this->gallery,"edit"))
496 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
497 else {
498 $imagesAdded = $this->reindexGallery();
499 if(is_int($imagesAdded))
500 $this->pushMessage($this->translator->_g("Gallery re-indexed. %s images added.",$imagesAdded));
501 }
502 $this->includeFile = "view";
503 break;
504 case "savegallery" :
505 $this->selectGallery();
506 if(!$this->checkPermissions($this->gallery,"edit")) {
507 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
508 $this->includeFile = "view";
509 } elseif($this->saveGallery()) {
510 $this->includeFile = "view";
511 } else {
512 $this->includeFile = "editgallery";
513 }
514 break;
515 case "saveimage" :
516 $this->selectGallery();
517 if(!$this->checkPermissions($this->gallery,"edit")) {
518 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
519 $this->includeFile = "view";
520 } elseif($this->saveImage()) {
521 $this->pushMessage($this->translator->_g("Image info saved"));
522 $this->includeFile = "view";
523 } else {
524 $this->includeFile = "view";
525 }
526 break;
527 case "savepass" :
528 if($this->user->isGuest()) {
529 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
530 $this->includeFile = "menu";
531 } elseif($this->savePass()) {
532 $this->pushMessage($this->translator->_g("Password saved"));
533 $this->includeFile = "menu";
534 } else {
535 $this->includeFile = "editpass";
536 }
537 break;
538 case "savepermissions" :
539 $this->selectGallery();
540 if(!$this->user->isAdmin() && !$this->user->isOwner($this->gallery)) {
541 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
542 $this->includeFile = "view";
543 } elseif($this->savePermissions()) {
544 $this->pushMessage($this->translator->_g("Permissions saved"));
545 $this->includeFile = "view";
546 } else {
547 $this->includeFile = "editpermissions";
548 }
549 break;
550 case "saveprofile" :
551 if($_REQUEST["user"] != $this->user->username || $this->user->isGuest()) {
552 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
553 $this->includeFile = "menu";
554 } elseif($this->saveUser()) {
555 $this->pushMessage($this->translator->_g("User info saved"));
556 $this->includeFile = "menu";
557 } else {
558 $this->includeFile = "editprofile";
559 }
560 break;
561 case "saveuser" :
562 if(!$this->user->isAdmin()) {
563 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
564 $this->includeFile = "menu";
565 } elseif($this->saveUser())
566 $this->includeFile = "manageusers";
567 else
568 $this->includeFile = "edituser";
569 break;
570 case "showgalleryhits" :
571 $this->selectGallery();
572 //load hit data for child galleries
573 foreach(array_keys($this->gallery->galleries) as $index)
574 $this->io->getHits($this->gallery->galleries[$index]);
575 /*if(!$this->checkPermissions($this->gallery,"read")) {
576 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
577 $this->includeFile = "menu";
578 } else {*/
579 $this->includeFile = "galleryhits";
580 //}
581 break;
582 case "showimagehits" :
583 $this->selectGallery();
584 /*if(!$this->checkPermissions($this->gallery,"read")) {
585 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
586 $this->includeFile = "menu";
587 } else {*/
588 $this->includeFile = "imagehits";
589 //}
590 break;
591 case "suspenduser" :
592 if(!$this->user->isAdmin()) {
593 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
594 $this->includeFile = "menu";
595 } elseif($this->suspendUser())
596 $this->pushMessage($this->translator->_g("User info saved"));
597 $this->includeFile = "manageusers";
598 break;
599 case "view" :
600 $this->selectGallery();
601 /*if(!$this->checkPermissions($this->gallery,"read")) {
602 $this->pushMessage($this->translator->_g("You do not have permission to perform this operation."));
603 $this->includeFile = "menu";
604 } else*/
605 $this->includeFile = "view";
606 break;
607 case "menu" :
608 default :
609 $this->includeFile = "menu";
610 }
611 }
612  
613 function &allGalleriesArray()
614 {
615 $root =& $this->io->getGallery(".", new stdClass, 100);
616 return $this->allGalleriesRecurse($root);
617 }
618  
619 function &allGalleriesRecurse(&$gal)
620 {
621 if($gal->hasChildGalleries()) {
622 $galArray = array();
623 foreach($gal->galleries as $child)
624 $galArray = array_merge($galArray, $this->allGalleriesRecurse($child));
625 array_unshift($galArray, $gal);
626 return $galArray;
627 } else
628 return array($gal);
629  
630 }
631  
632  
633  
634 /**
635 * Returns a two-dimensional array of links for the admin bar.
636 *
637 * @returns string
638 */
639 function adminLinksArray()
640 {
641 if(!$this->isLoggedIn()) return array(0 => array($this->translator->_g("admin bar|Back to galleries") => "."));
642  
643 $ret[0][$this->translator->_g("admin bar|Admin")] = $this->formatAdminURL("menu");
644 $ret[0][$this->translator->_g("admin bar|Galleries")] = $this->formatAdminURL("view", isset($this->gallery) ? $this->gallery->idEncoded() : null);
645 $ret[0][$this->translator->_g("admin bar|Log out")] = $this->formatAdminURL("logout");
646 if($this->isGalleryPage() || $this->isAlbumPage() || $this->isImagePage()) {
647 $ret[1][$this->translator->_g("admin bar|Edit gallery")] = $this->formatAdminURL("editgallery",$this->gallery->idEncoded());
648 $ret[1][$this->translator->_g("admin bar|Access control")] = $this->formatAdminURL("editpermissions",$this->gallery->idEncoded());
649 $ret[1][$this->translator->_g("admin bar|Delete gallery")] = $this->formatAdminURL("deletegallery",$this->gallery->idEncoded());
650 $ret[1][$this->translator->_g("admin bar|New subgallery")] = $this->formatAdminURL("newgallery",$this->gallery->idEncoded());
651 $ret[1][$this->translator->_g("admin bar|Re-index gallery")] = $this->formatAdminURL("reindex",$this->gallery->idEncoded());
652 if($this->isImagePage()) {
653 $ret[2][$this->translator->_g("admin bar|Edit image")] = $this->formatAdminURL("editimage",$this->gallery->idEncoded(),$this->image->id);
654 $ret[2][$this->translator->_g("admin bar|Delete image")] = $this->formatAdminURL("deleteimage",$this->gallery->idEncoded(),$this->image->id);
655 }
656 $ret[2][$this->translator->_g("admin bar|New image")] = $this->formatAdminURL("newimage",$this->gallery->idEncoded());
657 }
658 return $ret;
659 }
660  
661  
662 /**
663 * Saves the new password if it is correctly specified.
664 *
665 * @return boolean true on success; false otherwise
666 */
667 function savePass()
668 {
669 $users = $this->io->getUsers();
670  
671 $found = false;
672 for($i=0;$i < count($users);$i++)
673 if($_POST["sgUsername"] == $users[$i]->username) {
674 $found = true;
675 if(md5($_POST["sgOldPass"]) == $users[$i]->userpass)
676 if($_POST["sgNewPass1"]==$_POST["sgNewPass2"])
677 if(strlen($_POST["sgNewPass1"]) >= 6 && strlen($_POST["sgNewPass1"]) <= 16) {
678 $users[$i]->userpass = md5($_POST["sgNewPass1"]);
679 if($this->io->putUsers($users)) return true;
680 else $this->pushError($this->translator->_g("Could not save user info"));
681 }
682 else
683 $this->pushError($this->translator->_g("New password must be between 6 and 16 characters long."));
684 else
685 $this->pushError($this->translator->_g("The new passwords you entered do not match."));
686 else
687 $this->pushError($this->translator->_g("The current password you entered does not match the one in the database."));
688 }
689  
690 if(!$found) $this->pushError($this->translator->_g("The username specified was not found in the database."));
691  
692 //some sort of error occurred so:
693 return false;
694 }
695  
696  
697 /**
698 * Attempts to log a registered user into admin.
699 *
700 * @return boolean true on success; false otherwise
701 */
702 function doLogin()
703 {
704 if(!empty($_POST["sgUsername"]) && !empty($_POST["sgPassword"])) {
705 if($this->loadUser($_POST["sgUsername"]) && md5($_POST["sgPassword"]) == $this->user->userpass){
706 if($this->user->permissions & SG_SUSPENDED) {
707 $this->logout();
708 return $this->pushError($this->translator->_g("Your account has been suspended"));
709 } else {
710 $_SESSION["sgUser"]["username"] = $this->user->username;
711 $_SESSION["sgUser"]["ip"] = $_SERVER["REMOTE_ADDR"];
712 $_SESSION["sgUser"]["loginTime"] = time();
713 return $this->pushMessage($this->translator->_g("Welcome to singapore admin!"));
714 }
715 }
716 $this->logout();
717 return $this->pushError($this->translator->_g("Username and/or password incorrect"));
718 }
719 return $this->pushError($this->translator->_g("You must enter a username and password"));
720 }
721  
722 /**
723 * Cancels a user's admin session.
724 *
725 * @return true
726 */
727 function logout()
728 {
729 $_SESSION["sgUser"] = null;
730 return $this->pushMessage($this->translator->_g("Thank you and goodbye!"));
731 }
732  
733 /**
734 * Checks if the specified operation is permitted on the specified object
735 *
736 * @param sgImage|sgGallery the object to be operated on
737 * @param string the action to perform (either 'read', 'edit', 'add' or 'delete')
738 * @return bool true if permissions are satisfied; false otherwise
739 */
740 function checkPermissions($obj, $action, $gallery = null, $image = null)
741 {
742 //admins and object owners automatically have full permissions
743 if($this->user->isAdmin() || $this->user->isOwner($obj))// || (!$this->user->isGuest() && $obj->owner == "__nobody__"))
744 return true;
745  
746 //get the appropriate permission bitmask depending on action
747 switch($action) {
748 case "read" :
749 $inheritPerm = SG_IHR_READ;
750 $worldPerm = SG_WLD_READ;
751 $groupPerm = SG_GRP_READ;
752 break;
753 case "edit" :
754 $inheritPerm = SG_IHR_EDIT;
755 $worldPerm = SG_WLD_EDIT;
756 $groupPerm = SG_GRP_EDIT;
757 break;
758 case "add" :
759 $inheritPerm = SG_IHR_ADD;
760 $worldPerm = SG_WLD_ADD;
761 $groupPerm = SG_GRP_ADD;
762 break;
763 case "delete" :
764 $inheritPerm = SG_IHR_DELETE;
765 $worldPerm = SG_WLD_DELETE;
766 $groupPerm = SG_GRP_DELETE;
767 break;
768 default :
769 //unrecognised action so disallow it
770 return false;
771 }
772  
773 //check if the permission is inherited
774 if(($obj->permissions & $inheritPerm) == $inheritPerm)
775 if($obj->isRoot())
776 //shouldn't happen, but just in case
777 return false;
778 else
779 //check permissions of parent
780 return $this->checkPermissions($obj->parent, $action, $gallery, $image);
781 else
782 //not inherited so check world and group permissions of current object
783 return $obj->permissions & $worldPerm
784 || ($this->isInGroup($this->user->groups, $obj->groups) && $obj->permissions & $groupPerm);
785 }
786  
787 function savePermissions()
788 {
789 $obj =& $this->gallery;
790  
791 $perms = 0;
792  
793 switch($_POST["sgRead"]) {
794 case "inherit" : $perms |= SG_IHR_READ; break;
795 case "group" : $perms |= SG_GRP_READ; break;
796 case "world" : $perms |= SG_WLD_READ; break;
797 case "owner" : break;
798 }
799  
800 switch($_POST["sgEdit"]) {
801 case "inherit" : $perms |= SG_IHR_EDIT; break;
802 case "group" : $perms |= SG_GRP_EDIT; break;
803 case "world" : $perms |= SG_WLD_EDIT; break;
804 case "owner" : break;
805 }
806  
807 switch($_POST["sgAdd"]) {
808 case "inherit" : $perms |= SG_IHR_ADD; break;
809 case "group" : $perms |= SG_GRP_ADD; break;
810 case "world" : $perms |= SG_WLD_ADD; break;
811 case "owner" : break;
812 }
813  
814 switch($_POST["sgDelete"]) {
815 case "inherit" : $perms |= SG_IHR_DELETE; break;
816 case "group" : $perms |= SG_GRP_DELETE; break;
817 case "world" : $perms |= SG_WLD_DELETE; break;
818 case "owner" : break;
819 }
820  
821 $obj->permissions |= $perms; // isn't this equivalent
822 $obj->permissions &= $perms; // to == assignment?
823  
824 //only the owner or admin can change groups
825 if($this->user->isAdmin() || $this->user->isOwner($obj));
826 $obj->groups = $_POST["sgGroups"];
827  
828 //only the admin can change the owner
829 if($this->user->isAdmin())
830 $obj->owner = $_POST["sgOwner"];
831  
832 if($this->io->putGallery($this->gallery))
833 return $this->pushMessage($this->translator->_g("Gallery info saved"));
834  
835 return $this->pushError($this->translator->_g("Could not save gallery info"));
836 }
837  
838 /**
839 * Creates a new user.
840 *
841 * @return bool true on success; false otherwise
842 */
843 function addUser()
844 {
845 $users = $this->io->getUsers();
846 foreach($users as $usr)
847 if($usr->username == $_REQUEST["user"])
848 return $this->pushError($this->translator->_g("Username already exists"));
849  
850 if(!preg_match("/^[a-zA-Z0-9_]{3,}$/",$_REQUEST["user"]))
851 return $this->pushError($this->translator->_g("Username must be at least 3 characters long and contain only alphanumeric characters"));
852  
853 $users[count($users)] = new sgUser($_REQUEST["user"], md5("password"));
854  
855 if($this->io->putUsers($users))
856 return $this->pushMessage($this->translator->_g("User info saved"));
857  
858 return $this->pushError($this->translator->_g("Could not save user info"));
859 }
860  
861 /**
862 * Deletes a user.
863 *
864 * @return bool true on success; false otherwise
865 */
866 function deleteUser($username = null)
867 {
868 if($username == null)
869 $username = $_REQUEST["user"];
870  
871 if($username == "admin" || $username == "guest")
872 return $this->pushError($this->translator->_g("Cannot delete built in accounts"));
873  
874 $users = $this->io->getUsers();
875 foreach($users as $i => $usr)
876 if($usr->username == $username) {
877  
878 //delete user at offset $i from $users
879 array_splice($users,$i,1);
880  
881 if($this->io->putUsers($users))
882 return true;
883  
884 return $this->pushError($this->translator->_g("Could not save user info"));
885 }
886  
887 return $this->pushError($this->translator->_g("Username not recognised"));
888 }
889  
890 /**
891 * Saves a user's info.
892 *
893 * @return bool true on success; false otherwise
894 */
895 function saveUser() {
896 $users = $this->io->getUsers();
897 for($i=0; $i<count($users); $i++)
898 if($users[$i]->username == $_REQUEST["user"]) {
899 $users[$i]->email = $this->prepareText($_REQUEST["sgEmail"]);
900 $users[$i]->fullname = $this->prepareText($_REQUEST["sgFullname"]);
901 $users[$i]->description = $this->prepareText($_REQUEST["sgDescription"]);
902 if($this->user->isAdmin() && $_REQUEST["action"] == "saveuser") {
903 $users[$i]->groups = $this->prepareText($_REQUEST["sgGroups"]);
904 $users[$i]->permissions = ($_REQUEST["sgType"] == "admin") ? $users[$i]->permissions | SG_ADMIN : $users[$i]->permissions & ~SG_ADMIN;
905 if(isset($_REQUEST["sgPassword"]) && $_REQUEST["sgPassword"] != "**********")
906 $users[$i]->userpass = md5($_REQUEST["sgPassword"]);
907 }
908 if($this->io->putUsers($users))
909 return true;
910 return $this->pushError($this->translator->_g("Could not save user info"));
911 }
912 return $this->pushError($this->translator->_g("Username not recognised"));
913 }
914  
915 /**
916 * Suspend or unsuspend a user's account.
917 *
918 * @return bool true on success; false otherwise
919 */
920 function suspendUser() {
921 $users = $this->io->getUsers();
922 for($i=0; $i<count($users); $i++)
923 if($users[$i]->username == $_REQUEST["user"]) {
924  
925 $users[$i]->permissions = ($users[$i]->permissions & SG_SUSPENDED) ? $users[$i]->permissions & ~SG_SUSPENDED : $users[$i]->permissions | SG_SUSPENDED;
926 if($this->io->putUsers($users))
927 return true;
928 return $this->pushError($this->translator->_g("Could not save user info"));
929 }
930 return $this->pushError($this->translator->_g("Username not recognised"));
931 }
932  
933 /**
934 * Check for images in specified gallery directory which are
935 * not in the metadata and add them. If no gallery is specified,
936 * the current gallery is used.
937 * @param string id of gallery to reindex (optional)
938 * @return int|false the number of images added or false on error
939 */
940 function reindexGallery($galleryId = null)
941 {
942 if($galleryId == null)
943 $gal =& $this->gallery;
944 else
945 $gal =& $this->io->getGallery($galleryId, new stdClass);
946  
947 $imagesAdded = 0;
948 //get list of images
949 $dir = Singapore::getListing($this->config->pathto_galleries.$gal->id, $this->config->recognised_extensions);
950 //cycle through the image files
951 for($i=0; $i<count($dir->files); $i++) {
952 //search for the image file in the database images
953 for($j=0; $j<count($gal->images); $j++)
954 //if we find it
955 if($dir->files[$i] == $gal->images[$j]->id)
956 //skip the rest of this loop
957 continue 2;
958 //otherwise add the image to the database
959 $gal->images[$j] = new sgImage($dir->files[$i], $gal, $this->config);
960 $gal->images[$j]->name = $dir->files[$i];
961 list(
962 $gal->images[$j]->width,
963 $gal->images[$j]->height,
964 $gal->images[$j]->type
965 ) = GetImageSize($this->config->pathto_galleries.$gal->id."/".$gal->images[$j]->id);
966 $imagesAdded++;
967 }
968  
969 if($this->io->putGallery($gal))
970 return $imagesAdded;
971  
972 return $this->pushError($this->translator->_g("Could not save gallery info"));
973 }
974  
975 /**
976 * Reindexes several galleries from the current gallery.
977 *
978 * @return int|false number of images added on success; false otherwise
979 */
980 function reindexMultipleGalleries()
981 {
982 $totalImagesAdded = 0;
983 foreach($_REQUEST["sgGalleries"] as $galleryId) {
984 $current = $this->reindexGallery($galleryId);
985 if($current === false) $this->pushError($this->translator->_g("Gallery '%s' could not be reindexed", $galleryId));
986 else $this->pushMessage($this->translator->_g("Gallery '%s' reindexed: %s images added", $galleryId, $current));
987 $totalImagesAdded += $current;
988 }
989  
990 //reload gallery data if we changed any
991 if($totalImagesAdded)
992 $this->selectGallery();
993  
994 return $totalImagesAdded;
995  
996 }
997  
998 /**
999 * Moves or copies galleries.
1000 *
1001 * @return int|false number of galleries moved; false otherwise
1002 */
1003 function moveMultipleGalleries()
1004 {
1005 $totalGalleriesMoved = 0;
1006 foreach($_REQUEST["sgGalleries"] as $galleryId) {
1007 $source = $this->config->base_path.$this->config->pathto_galleries.$galleryId;
1008 $target = $this->config->base_path.$this->config->pathto_galleries.$_REQUEST['sgMoveTarget'].'/'.basename($galleryId);
1009 if(file_exists($target)) {
1010 $this->pushError($this->translator->_g("Unable to copy/move gallery '%s' because the target gallery already exists.", $galleryId));
1011 } elseif($this->isSubPath($source, $target, false)) {
1012 $this->pushError($this->translator->_g("Unable to copy/move gallery '%s' because the target is a child of the source.", $galleryId));
1013 //} elseif(!is_writable($target)) {
1014 // $this->pushError($this->translator->_g("Unable to copy/move gallery '%s': the target is not writable", $galleryId));
1015 } else {
1016 if($_REQUEST["sgMoveType"] == 'move') { //Move
1017 $current = rename($source, $target);
1018 } else { //Copy
1019 $current = $this->copyDir($source, $target);
1020 }
1021 if($current === false) $this->pushError($this->translator->_g("Unable to copy/move gallery '%s' because the operation failed.", $galleryId));
1022 else $totalGalleriesMoved++;
1023 }
1024 }
1025  
1026 //load target gallery
1027 if($totalGalleriesMoved)
1028 $this->selectGallery($_REQUEST['sgMoveTarget']);
1029  
1030 return $totalGalleriesMoved;
1031 }
1032  
1033 /**
1034 * Copies everything from directory $fromDir to directory $toDir
1035 * and sets up files mode $chmod
1036 * @author Anton Makarenko <makarenkoa at ukrpost dot net>
1037 */
1038 function copyDir($fromDir, $toDir)
1039 {
1040 $success = true;
1041 $handle = opendir($fromDir);
1042  
1043 //ensure target directory exists
1044 if(!file_exists($toDir))
1045 if(mkdir($toDir))
1046 chmod($toDir, octdec($this->config->directory_mode));
1047 else
1048 return false;
1049  
1050 while(false !== ($item = readdir($handle)))
1051 if($item != '.' && $item != '..') {
1052 $from = $fromDir.'/'.$item;
1053 $to = $toDir.'/'.$item;
1054  
1055 if(is_dir($from)) {
1056 if($success &= mkdir($to))
1057 chmod($to, octdec($this->config->directory_mode));
1058 //recurse
1059 $this->copyDir($from, $to);
1060 } else {
1061 if($success &= copy($from, $to))
1062 chmod($to, octdec($this->config->file_mode));
1063 }
1064 }
1065 closedir($handle);
1066  
1067 return $success;
1068 }
1069  
1070 /**
1071 * Creates a gallery.
1072 *
1073 * @return boolean true on success; false otherwise
1074 */
1075 function addGallery()
1076 {
1077 $newGalleryId = $this->gallery->id."/".$_REQUEST["newgallery"];
1078 $path = $this->config->base_path.$this->config->pathto_galleries.$newGalleryId;
1079  
1080 //fail if directory already exists
1081 if(file_exists($path))
1082 return $this->pushError($this->translator->_g("Gallery already exists."));
1083  
1084 //create directory or fail
1085 if(!Singapore::mkdir($path))
1086 return $this->pushError($this->translator->_g("Unable to create directory '%s'", $path));
1087  
1088 //explicitly set permissions on gallery directory
1089 @chmod($path, octdec($this->config->directory_mode));
1090  
1091 $gal =& new sgGallery($newGalleryId, $this->gallery);
1092 $gal->name = $_REQUEST["newgallery"];
1093  
1094 //set object owner
1095 if(!$this->user->isGuest())
1096 $gal->owner = $this->user->username;
1097  
1098 //save gallery metadata
1099 if($this->io->putGallery($gal))
1100 return true;
1101 else
1102 return $this->pushError($this->translator->_g("Unable to save metadata."));
1103 }
1104  
1105 function prepareText($text, $multiline = false)
1106 {
1107 if($multiline) {
1108 $text = strip_tags($text, $this->config->allowed_tags);
1109 $text = str_replace(array("\n","\r"), array("<br />",""), $text);
1110 } else {
1111 $text = htmlspecialchars($text);
1112 }
1113  
1114 return $text;
1115 }
1116  
1117 /**
1118 * Saves gallery info to the database.
1119 *
1120 * @return boolean true on success; false otherwise
1121 */
1122 function saveGallery()
1123 {
1124 $this->gallery->categories = $_REQUEST["sgCategories"];
1125 $this->gallery->name = $this->prepareText($_REQUEST["sgGalleryName"]);
1126 $this->gallery->artist = $this->prepareText($_REQUEST["sgArtistName"]);
1127 $this->gallery->email = $this->prepareText($_REQUEST["sgArtistEmail"]);
1128 $this->gallery->date = $this->prepareText($_REQUEST["sgDate"]);
1129 $this->gallery->copyright = $this->prepareText($_REQUEST["sgCopyright"]);
1130 $this->gallery->summary = $this->prepareText($_REQUEST["sgSummary"],true);
1131 $this->gallery->desc = $this->prepareText($_REQUEST["sgGalleryDesc"],true);
1132  
1133 if($this->config->enable_clickable_urls) {
1134 //recognise URLs and htmlise them
1135 $this->gallery->desc = preg_replace('{(?<!href="|href=)\b('.SG_REGEXP_PROTOCOLURL.')\b(?!</a>)}', '<a href="$1">$1</a>', $this->gallery->desc); //general protocol match
1136 $this->gallery->desc = preg_replace('{(?<!://)\b('.SG_REGEXP_WWWURL.')\b(?!</a>)}', '<a href="http://$1">$1</a>', $this->gallery->desc); //web addresses starting www. without path info
1137 $this->gallery->desc = preg_replace('{(?<!mailto:|\.)\b('.SG_REGEXP_EMAILURL.')\b(?!</a>)}', '<a href="mailto:$1">$1</a>', $this->gallery->desc); //email addresses *@*.*
1138 }
1139  
1140 if($this->io->putGallery($this->gallery))
1141 return true;
1142 else
1143 return $this->pushError($this->translator->_g("Could not save gallery info"));
1144 }
1145  
1146 /**
1147 * Deletes a gallery and everything contained within it.
1148 *
1149 * @return boolean true on success; false otherwise
1150 */
1151 function deleteGallery($galleryId = null)
1152 {
1153 if($galleryId === null)
1154 $galleryId = $_REQUEST['gallery'];
1155  
1156 //calculate the path where the folder actually resides.
1157 $path = $this->config->base_path.$this->config->pathto_galleries.$galleryId;
1158  
1159 //security check: make sure requested file is in galleries directory
1160 if(!$this->isSubPath($this->config->base_path.$this->config->pathto_galleries,$path))
1161 return $this->pushError($this->translator->_g("Requested item '%s' appears to be outside the galleries directory", $galleryId));
1162  
1163 //check that the gallery to delete is not the top level directory
1164 if(realpath($path) == realpath($this->config->base_path.$this->config->pathto_galleries))
1165 return $this->pushError($this->translator->_g("Cannot delete the root gallery."));
1166  
1167 //attempt to remove the offending directory and all contained therein
1168 if($this->rmdir_all($path))
1169 return $this->pushMessage($this->translator->_g("Gallery '%s' deleted.", $galleryId));
1170 else
1171 return $this->pushError($this->translator->_g("Unable to delete gallery '%s'.", $galleryId));
1172 }
1173  
1174 /**
1175 * Deletes several galleries from the current gallery.
1176 *
1177 * @return int number of galleries deleted
1178 */
1179 function deleteMultipleGalleries() {
1180 $totalGalleriesDeleted = 0;
1181 foreach($_REQUEST["sgGalleries"] as $galleryId) {
1182 $this->deleteGallery($galleryId);
1183 $totalGalleriesDeleted++;
1184 }
1185  
1186 //reload gallery data if we deleted any
1187 if($totalGalleriesDeleted)
1188 $this->selectGallery();
1189  
1190 return $totalGalleriesDeleted;
1191 }
1192  
1193 /**
1194 * Saves changes to the gallery thumbnail to the database.
1195 *
1196 * @return boolean true on success; false otherwise
1197 */
1198 function saveGalleryThumbnail()
1199 {
1200 $this->gallery->filename = $_REQUEST['sgThumbName'];
1201 if($this->io->putGallery($this->gallery))
1202 $this->pushMessage($this->translator->_g("Thumbnail changed."));
1203 else
1204 $this->pushError($this->translator->_g("Unable to save metadata."));
1205 }
1206  
1207  
1208 /**
1209 * Adds an image to the database.
1210 *
1211 * @return boolean true on success; false otherwise
1212 */
1213 function addImage()
1214 {
1215 if($_REQUEST["sgLocationChoice"] == "remote") {
1216 $image = $_REQUEST["sgImageURL"];
1217 $path = $image;
1218 } elseif($_REQUEST["sgLocationChoice"] == "single") {
1219 //set filename as requested and strip off any clandestine path info
1220 if($_REQUEST["sgNameChoice"] == "same") $image = basename($_FILES["sgImageFile"]["name"]);
1221 else $image = basename($_REQUEST["sgFileName"]);
1222  
1223 //make sure image is valid
1224 if(!preg_match("/\.(".$this->config->recognised_extensions.")$/i", $image)) {
1225 $imgInfo = GetImageSize($_FILES["sgImageFile"]["tmp_name"]);
1226 switch($imgInfo[2]) {
1227 case 1 : $image .= '.gif'; break;
1228 case 2 : $image .= '.jpg'; break;
1229 case 3 : $image .= '.png'; break;
1230 case 6 : $image .= '.bmp'; break;
1231 case 7 :
1232 case 8 : $image .= '.tif'; break;
1233 default :
1234 return $this->pushError($this->translator->_g("Uploaded image '%s' has unrecognised extension and image type could not be determined from file contents.", $image));
1235 }
1236 }
1237  
1238 $path = $this->config->base_path.$this->config->pathto_galleries.$this->gallery->id."/".$image;
1239 $srcImage = $image;
1240  
1241 if(file_exists($path))
1242 switch($this->config->upload_overwrite) {
1243 case 1 : //overwrite
1244 $this->deleteImage($image);
1245 break;
1246 case 2 : //generate unique
1247 for($i=0;file_exists($path);$i++) {
1248 $pivot = strrpos($srcImage,".");
1249 $image = substr($srcImage, 0, $pivot).'-'.$i.substr($srcImage, $pivot,strlen($srcImage)-$pivot);
1250 $path = $this->config->base_path.$this->config->pathto_galleries.$this->gallery->id."/".$image;
1251 }
1252 break;
1253 case 0 : //raise error
1254 default :
1255 return $this->pushError($this->translator->_g("File already exists."));
1256 }
1257  
1258 if(!move_uploaded_file($_FILES["sgImageFile"]["tmp_name"],$path))
1259 return $this->pushError($this->translator->_g("Could not upload file."));
1260  
1261 // try to change file-permissions
1262 @chmod($path, octdec($this->config->file_mode));
1263  
1264 }
1265  
1266 $img =& new sgImage($image, $this->gallery);
1267  
1268 $img->name = strtr(substr($image, strrpos($image,"/"), strrpos($image,".")-strlen($image)), "_", " ");
1269 list($img->width, $img->height, $img->type) = GetImageSize($path);
1270  
1271 //leave owner of guest-uploaded files as default '__nobody__'
1272 if(!$this->user->isGuest())
1273 $img->owner = $this->user->username;
1274  
1275 $this->gallery->images[] =& $img;
1276  
1277 //set as gallery thumbnail?
1278 if($this->gallery->imageCount()==1)
1279 $this->gallery->filename = $img->id;
1280  
1281 if($this->io->putGallery($this->gallery)) {
1282 $this->selectImage($image);
1283 return $this->pushMessage($this->translator->_g("Image added", $image));
1284 } else {
1285 @unlink($path);
1286 return $this->pushError($this->translator->_g("Unable to save metadata."));
1287 }
1288 }
1289  
1290 /**
1291 * Adds the contents of an uploaded archive to the database.
1292 *
1293 * @return boolean true on success; false otherwise
1294 */
1295 function addMultipleImages()
1296 {
1297 //find system temp directory
1298 if(!($systmpdir = $this->findTempDirectory()))
1299 return $this->pushError($this->translator->_g("Unable to find temporary storage space."));
1300  
1301 //create new temp directory in system temp dir but stop after 100 attempts
1302 while(!Singapore::mkdir($tmpdir = $systmpdir."/".uniqid("sg")) && $tries++<100);
1303  
1304 $archive = $_FILES["sgArchiveFile"]["tmp_name"];
1305  
1306 if(!is_uploaded_file($archive))
1307 return $this->pushError($this->translator->_g("Could not upload file."));
1308  
1309 //decompress archive to temp
1310 $cmd = escapeshellcmd($this->config->pathto_unzip);
1311 $cmd .= ' -d "'.escapeshellcmd(realpath($tmpdir));
1312 $cmd .= '" "'.escapeshellcmd(realpath($archive)).'"';
1313  
1314 if(!exec($cmd))
1315 return $this->pushError($this->translator->_g("Could not decompress archive."));
1316  
1317 //start processing archive contents
1318 $wd = $tmpdir;
1319 $contents = $this->getListing($wd,$this->config->recognised_extensions);
1320  
1321 //cope with archives contained within a directory
1322 if(empty($contents->files) && count($contents->dirs) == 1)
1323 $contents = $this->getListing($wd .= '/'.$contents->dirs[0],$this->config->recognised_extensions);
1324  
1325 $success = true;
1326  
1327 //add any images to current gallery
1328 foreach($contents->files as $image) {
1329  
1330 //check image is valid and ignore it if it isn't
1331 if(!preg_match("/\.(".$this->config->recognised_extensions.")$/i", $image)) {
1332 $imgInfo = GetImageSize($wd.'/'.$image);
1333 switch($imgInfo[2]) {
1334 case 1 : $image .= '.gif'; break;
1335 case 2 : $image .= '.jpg'; break;
1336 case 3 : $image .= '.png'; break;
1337 case 6 : $image .= '.bmp'; break;
1338 case 7 :
1339 case 8 : $image .= '.tif'; break;
1340 default :
1341 $this->pushMessage($this->translator->_g("Uploaded image '%s' has unrecognised extension and image type could not be determined from file contents.", $image));
1342 continue;
1343 }
1344 }
1345  
1346 $path = $this->config->pathto_galleries.$this->gallery->id."/".$image;
1347 $srcImage = $image;
1348  
1349 if(file_exists($path))
1350 switch($this->config->upload_overwrite) {
1351 case 1 : //overwrite
1352 $this->deleteImage($image);
1353 break;
1354 case 2 : //generate unique
1355 for($i=0;file_exists($path);$i++) {
1356 $pivot = strrpos($srcImage,".");
1357 $image = substr($srcImage, 0, $pivot).'-'.$i.substr($srcImage, $pivot,strlen($srcImage)-$pivot);
1358 $path = $this->config->base_path.$this->config->pathto_galleries.$this->gallery->id."/".$image;
1359 }
1360 break;
1361 case 0 : //raise error
1362 default :
1363 $this->pushError($this->translator->_g("File '%s' already exists."));
1364 $success = false;
1365 continue;
1366 }
1367  
1368 copy($wd.'/'.$srcImage,$path);
1369  
1370 // try to change file-permissions
1371 @chmod($path, octdec($this->config->file_mode));
1372  
1373 $img =& new sgImage($image, $this->gallery);
1374  
1375 $img->name = strtr(substr($image, strrpos($image,"/"), strrpos($image,".")-strlen($image)), "_", " ");
1376 list($img->width, $img->height, $img->type) = GetImageSize($path);
1377  
1378 //leave owner of guest-uploaded files as default '__nobody__'
1379 if(!$this->user->isGuest())
1380 $img->owner = $this->user->username;
1381  
1382 $this->gallery->images[] = $img;
1383 }
1384  
1385 //add any directories as subgalleries, if allowed
1386 if($this->config->allow_dir_upload == 1 && !$this->user->isGuest()
1387 || $this->config->allow_dir_upload == 2 && $this->user->isAdmin())
1388 foreach($contents->dirs as $gallery) {
1389 $path = $this->config->pathto_galleries.$this->gallery->id."/".$gallery;
1390  
1391 if(file_exists($path))
1392 switch($this->config->upload_overwrite) {
1393 case 1 : //overwrite
1394 $this->deleteGallery($this->gallery->id.'/'.$gallery);
1395 break;
1396 case 2 : //generate unique
1397 for($i=0;file_exists($path);$i++)
1398 $path = $this->config->pathto_galleries.$this->gallery->id."/".$gallery.'-'.$i;
1399 break;
1400 case 0 : //raise error
1401 default :
1402 $this->pushError($this->translator->_g("File '%s' already exists."));
1403 $success = false;
1404 continue;
1405 }
1406  
1407 //move from temp dir to gallery
1408 rename($wd.'/'.$gallery, $path);
1409  
1410 //change directory permissions (but not contents)
1411 @chmod($path, octdec($this->config->directory_mode));
1412 }
1413  
1414 //if images were added save metadata
1415 if(!empty($contents->files))
1416 $this->io->putGallery($this->gallery)
1417 or $this->pushError($this->translator->_g("Unable to save metadata."));
1418  
1419 //if subgalleries were added reload gallery data
1420 if(!empty($contents->dirs))
1421 $this->selectGallery();
1422  
1423 //remove temporary directory
1424 $this->rmdir_all($tmpdir);
1425  
1426 if($success)
1427 return $this->pushMessage($this->translator->_g("Archive contents added."));
1428 else
1429 return $this->pushError($this->translator->_g("Some archive contents could not be added."));
1430 }
1431  
1432 /**
1433 * Saves image info to the database.
1434 *
1435 * @return boolean true on success; false otherwise
1436 */
1437 function saveImage()
1438 {
1439 $this->image->id = $this->prepareText($_REQUEST['image']);
1440 $this->image->thumbnail = $this->prepareText($_REQUEST["sgThumbnail"]);
1441 $this->image->categories = $this->prepareText($_REQUEST["sgCategories"]);
1442 $this->image->name = $this->prepareText($_REQUEST["sgImageName"]);
1443 $this->image->artist = $this->prepareText($_REQUEST["sgArtistName"]);
1444 $this->image->email = $this->prepareText($_REQUEST["sgArtistEmail"]);
1445 $this->image->location = $this->prepareText($_REQUEST["sgLocation"]);
1446 $this->image->date = $this->prepareText($_REQUEST["sgDate"]);
1447 $this->image->copyright = $this->prepareText($_REQUEST["sgCopyright"]);
1448 $this->image->desc = $this->prepareText($_REQUEST["sgImageDesc"],true);
1449 $this->image->camera = $this->prepareText($_REQUEST["sgField01"]);
1450 $this->image->lens = $this->prepareText($_REQUEST["sgField02"]);
1451 $this->image->film = $this->prepareText($_REQUEST["sgField03"]);
1452 $this->image->darkroom = $this->prepareText($_REQUEST["sgField04"]);
1453 $this->image->digital = $this->prepareText($_REQUEST["sgField05"]);
1454  
1455 if($this->io->putGallery($this->gallery))
1456 return true;
1457 else
1458 return $this->pushError($this->translator->_g("Unable to save metadata."));
1459 }
1460  
1461 /**
1462 * Deletes an image from the current gallery.
1463 *
1464 * @param string the filename of the image to delete (optional)
1465 * @return boolean true on success; false otherwise
1466 */
1467 function deleteImage($image = null)
1468 {
1469 if($image === null)
1470 $image = $this->image->id;
1471  
1472 //if file is remote or doesn't exist then there's no point trying to delete it
1473 if(!sgImage::isRemote($image) && file_exists($this->config->pathto_galleries.$this->gallery->id."/".$image))
1474 //check that we're not being fooled into deleting something we shouldn't
1475 if(!$this->isSubPath($this->config->pathto_galleries, $this->config->pathto_galleries.$this->gallery->id."/".$image))
1476 return $this->pushError($this->translator->_g("Requested item '%s' appears to be outside the galleries directory.", htmlspecialchars($image)));
1477 else
1478 unlink($this->config->pathto_galleries.$this->gallery->id."/".$image);
1479  
1480 //remove the image from the images array
1481 foreach($this->gallery->images as $i => $img)
1482 if($img->id == $image) {
1483 array_splice($this->gallery->images,$i,1);
1484 //image removed from array so save metadata
1485 if($this->io->putGallery($this->gallery)) {
1486 //nulling image reference will select parent gallery
1487 $this->image = null;
1488 return $this->pushMessage($this->translator->_g("Image '%s' deleted", htmlspecialchars($image)));
1489 } else {
1490 return $this->pushError($this->translator->_g("Unable to save metadata."));
1491 }
1492 }
1493  
1494 //image not found in array
1495 return $this->pushError($this->translator->_g("Image not found '%s'", htmlspecialchars($image)));
1496 }
1497  
1498 /**
1499 * Deletes several images from the current gallery.
1500 *
1501 * @return int|false number of images deleted on success; false otherwise
1502 */
1503 function deleteMultipleImages() {
1504 $deleted = 0;
1505 foreach($_REQUEST["sgImages"] as $image)
1506 if($this->deleteImage($image))
1507 $deleted++;
1508  
1509 return $deleted;
1510 }
1511  
1512 /**
1513 * Deletes the contents of the cache directory.
1514 *
1515 * @return boolean true on success; false otherwise
1516 */
1517 function purgeCache()
1518 {
1519 $dir = $this->getListing($this->config->pathto_cache, $this->config->recognised_extensions);
1520  
1521 $success = true;
1522 for($i=0;$i<count($dir->files);$i++) {
1523 $success &= unlink($dir->path.$dir->files[$i]);
1524 }
1525  
1526 return $success;
1527 }
1528  
1529 }
1530  
1531  
1532 ?>