These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /*************************************************************************** |
||
3 | * for license information see LICENSE.md |
||
4 | * |
||
5 | * |
||
6 | * get/set has to be commited with save |
||
7 | * add/remove etc. is executed instantly |
||
8 | ***************************************************************************/ |
||
9 | |||
10 | require_once __DIR__ . '/const.inc.php'; |
||
11 | |||
12 | class picture |
||
13 | { |
||
14 | public $nPictureId = 0; |
||
15 | public $rePicture; |
||
16 | public $sFileExtension = ''; |
||
17 | public $bFilenamesSet = false; |
||
18 | |||
19 | private $originalPosition; |
||
20 | |||
21 | public static function pictureIdFromUUID($uuid) |
||
22 | { |
||
23 | return sql_value("SELECT `id` FROM `pictures` WHERE `uuid`='&1'", 0, $uuid); |
||
24 | } |
||
25 | |||
26 | public static function fromUUID($uuid) |
||
27 | { |
||
28 | $pictureId = self::pictureIdFromUUID($uuid); |
||
29 | if ($pictureId == 0) { |
||
30 | return null; |
||
31 | } |
||
32 | |||
33 | return new self($pictureId); |
||
34 | } |
||
35 | |||
36 | public function __construct($nNewPictureId = ID_NEW) |
||
37 | { |
||
38 | global $opt; |
||
39 | |||
40 | $this->rePicture = new rowEditor('pictures'); |
||
41 | $this->rePicture->addPKInt('id', null, false, RE_INSERT_AUTOINCREMENT); |
||
42 | $this->rePicture->addString('uuid', '', false, RE_INSERT_AUTOUUID); |
||
43 | $this->rePicture->addInt('node', 0, false); |
||
44 | $this->rePicture->addDate('date_created', time(), true, RE_INSERT_IGNORE); |
||
45 | $this->rePicture->addDate('last_modified', time(), true, RE_INSERT_IGNORE); |
||
46 | $this->rePicture->addString('url', '', false); |
||
47 | $this->rePicture->addString('title', '', false); |
||
48 | $this->rePicture->addDate('last_url_check', 0, true); |
||
49 | $this->rePicture->addInt('object_id', null, false); |
||
50 | $this->rePicture->addInt('object_type', null, false); |
||
51 | $this->rePicture->addString('thumb_url', '', false); |
||
52 | $this->rePicture->addDate('thumb_last_generated', 0, false); |
||
53 | $this->rePicture->addInt('spoiler', 0, false); |
||
54 | $this->rePicture->addInt('local', 0, false); |
||
55 | $this->rePicture->addInt('unknown_format', 0, false); |
||
56 | $this->rePicture->addInt('display', 1, false); |
||
57 | $this->rePicture->addInt('mappreview', 0, false); |
||
58 | $this->rePicture->addInt('seq', 0, false); |
||
59 | |||
60 | $this->nPictureId = $nNewPictureId + 0; |
||
61 | |||
62 | if ($nNewPictureId == ID_NEW) { |
||
63 | $this->rePicture->addNew(null); |
||
64 | |||
65 | $sUUID = mb_strtoupper(sql_value('SELECT UUID()', '')); |
||
66 | $this->rePicture->setValue('uuid', $sUUID); |
||
67 | $this->rePicture->setValue('node', $opt['logic']['node']['id']); |
||
68 | $this->originalPosition = false; |
||
69 | } else { |
||
70 | $this->rePicture->load($this->nPictureId); |
||
71 | $this->originalPosition = $this->getPosition(); |
||
72 | |||
73 | $sFilename = $this->getFilename(); |
||
74 | $fna = mb_split('\\.', $sFilename); |
||
75 | $this->sFileExtension = mb_strtolower($fna[count($fna) - 1]); |
||
76 | $this->bFilenamesSet = true; |
||
77 | } |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * @return bool |
||
82 | */ |
||
83 | public function exist() |
||
84 | { |
||
85 | return $this->rePicture->exist(); |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * @param $sFilename |
||
90 | * @return bool |
||
91 | */ |
||
92 | public static function allowedExtension($sFilename) |
||
93 | { |
||
94 | global $opt; |
||
95 | |||
96 | if (strpos($sFilename, ';') !== false) { |
||
97 | return false; |
||
98 | } |
||
99 | if (strpos($sFilename, '.') === false) { |
||
100 | return false; |
||
101 | } |
||
102 | |||
103 | $sExtension = mb_strtolower(substr($sFilename, strrpos($sFilename, '.') + 1)); |
||
104 | |||
105 | if (strpos(';' . $opt['logic']['pictures']['extensions'] . ';', ';' . $sExtension . ';') !== false) { |
||
106 | return true; |
||
107 | } |
||
108 | |||
109 | return false; |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * @param string $sFilename |
||
114 | */ |
||
115 | public function setFilenames($sFilename) |
||
116 | { |
||
117 | global $opt; |
||
118 | |||
119 | if ($this->bFilenamesSet == true) { |
||
120 | return; |
||
121 | } |
||
122 | if (strpos($sFilename, '.') === false) { |
||
123 | return; |
||
124 | } |
||
125 | |||
126 | $sExtension = mb_strtolower(substr($sFilename, strrpos($sFilename, '.') + 1)); |
||
127 | $this->sFileExtension = $sExtension; |
||
128 | |||
129 | $sUUID = $this->getUUID(); |
||
130 | |||
131 | $this->setUrl($opt['logic']['pictures']['url'] . $sUUID . '.' . $sExtension); |
||
132 | |||
133 | $this->bFilenamesSet = true; |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * @return int |
||
138 | */ |
||
139 | public function getPictureId() |
||
140 | { |
||
141 | return $this->nPictureId; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * @param bool $bRestoring |
||
146 | * @param int $original_id |
||
147 | */ |
||
148 | private function setArchiveFlag($bRestoring, $original_id = 0) |
||
149 | { |
||
150 | global $login; |
||
151 | |||
152 | // This function determines if an insert, update oder deletion at pictures table |
||
153 | // ist to be recorded for vandalism recovery, depending on WHO OR WHY the |
||
154 | // operation is done. Other conditions, depending on the data, are handled |
||
155 | // by triggers. |
||
156 | // |
||
157 | // Data is passed by ugly global DB variables, so try call this function as |
||
158 | // close before the targetet DB operation as possible. |
||
159 | |||
160 | if ($this->getObjectType() == 1) { |
||
161 | $logger_id = sql_value( |
||
162 | "SELECT |
||
163 | IFNULL((SELECT `user_id` FROM `cache_logs` WHERE `id`='&1'), |
||
164 | (SELECT `user_id` FROM `cache_logs_archived` WHERE `id`='&1'))", |
||
165 | 0, |
||
166 | $this->getObjectId() |
||
167 | ); |
||
168 | $archive = ($bRestoring || $login->userid != $logger_id); |
||
169 | } else { |
||
170 | $archive = true; |
||
171 | } |
||
172 | |||
173 | sql('SET @archive_picop=' . ($archive ? 'TRUE' : 'FALSE')); |
||
174 | sql_slave('SET @archive_picop=' . ($archive ? 'TRUE' : 'FALSE')); |
||
175 | |||
176 | sql("SET @original_picid='&1'", $original_id); |
||
177 | sql_slave("SET @original_picid='&1'", $original_id); |
||
178 | |||
179 | // @archive_picop and @original_picid are evaluated by trigger functions |
||
180 | } |
||
181 | |||
182 | private function resetArchiveFlag() |
||
183 | { |
||
184 | sql('SET @archive_picop=FALSE'); |
||
185 | sql('SET @original_picid=0'); |
||
186 | sql_slave('SET @archive_picop=FALSE'); |
||
187 | sql_slave('SET @original_picid=0'); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * @return string |
||
192 | */ |
||
193 | public function getUrl() |
||
194 | { |
||
195 | return $this->rePicture->getValue('url'); |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * @param string $value |
||
200 | * @return bool |
||
201 | */ |
||
202 | public function setUrl($value) |
||
203 | { |
||
204 | return $this->rePicture->setValue('url', $value); |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * @return mixed |
||
209 | */ |
||
210 | public function getThumbUrl() |
||
211 | { |
||
212 | return $this->rePicture->getValue('thumb_url'); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * @param $value |
||
217 | * @return bool |
||
218 | */ |
||
219 | public function setThumbUrl($value) |
||
220 | { |
||
221 | return $this->rePicture->setValue('thumb_url', $value); |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * @return mixed |
||
226 | */ |
||
227 | public function getTitle() |
||
228 | { |
||
229 | return $this->rePicture->getValue('title'); |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * @param $value |
||
234 | * @return bool |
||
235 | */ |
||
236 | public function setTitle($value) |
||
237 | { |
||
238 | if ($value != '') { |
||
239 | return $this->rePicture->setValue('title', $value); |
||
240 | } |
||
241 | |||
242 | return false; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * @return bool |
||
247 | */ |
||
248 | public function getSpoiler() |
||
249 | { |
||
250 | return $this->rePicture->getValue('spoiler') != 0; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * @param $value |
||
255 | * @return bool |
||
256 | */ |
||
257 | public function setSpoiler($value) |
||
258 | { |
||
259 | return $this->rePicture->setValue('spoiler', $value ? 1 : 0); |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * @return bool |
||
264 | */ |
||
265 | public function getLocal() |
||
266 | { |
||
267 | return $this->rePicture->getValue('local') != 0; |
||
268 | } |
||
269 | |||
270 | /** |
||
271 | * @param int $value |
||
272 | * @return bool |
||
273 | */ |
||
274 | public function setLocal($value) |
||
275 | { |
||
276 | return $this->rePicture->setValue('local', $value ? 1 : 0); |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * @return bool |
||
281 | */ |
||
282 | public function getUnknownFormat() |
||
283 | { |
||
284 | return $this->rePicture->getValue('unknown_format') != 0; |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * @param $value |
||
289 | * @return bool |
||
290 | */ |
||
291 | public function setUnknownFormat($value) |
||
292 | { |
||
293 | return $this->rePicture->setValue('unknown_format', $value ? 1 : 0); |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * @return bool |
||
298 | */ |
||
299 | public function getDisplay() |
||
300 | { |
||
301 | return $this->rePicture->getValue('display') != 0; |
||
302 | } |
||
303 | |||
304 | /** |
||
305 | * @param $value |
||
306 | * @return bool |
||
307 | */ |
||
308 | public function setDisplay($value) |
||
309 | { |
||
310 | return $this->rePicture->setValue('display', $value ? 1 : 0); |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * @return bool |
||
315 | */ |
||
316 | public function getMapPreview() |
||
317 | { |
||
318 | return $this->rePicture->getValue('mappreview') != 0; |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * @param $value |
||
323 | * @return bool |
||
324 | */ |
||
325 | public function setMapPreview($value) |
||
326 | { |
||
327 | return $this->rePicture->setValue('mappreview', $value ? 1 : 0); |
||
328 | } |
||
329 | |||
330 | /** |
||
331 | * @return string |
||
332 | */ |
||
333 | public function getFilename() |
||
334 | { |
||
335 | // works intendently before bFilenameSet == true ! |
||
336 | global $opt; |
||
337 | |||
338 | View Code Duplication | if (mb_substr($opt['logic']['pictures']['dir'], -1, 1) != '/') { |
|
339 | $opt['logic']['pictures']['dir'] .= '/'; |
||
340 | } |
||
341 | |||
342 | $url = $this->getUrl(); |
||
343 | $fna = mb_split('\\/', $url); |
||
344 | |||
345 | return $opt['logic']['pictures']['dir'] . end($fna); |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * @return string |
||
350 | */ |
||
351 | public function getThumbFilename() |
||
352 | { |
||
353 | global $opt; |
||
354 | |||
355 | View Code Duplication | if (mb_substr($opt['logic']['pictures']['thumb_dir'], -1, 1) != '/') { |
|
356 | $opt['logic']['pictures']['thumb_dir'] .= '/'; |
||
357 | } |
||
358 | |||
359 | $url = $this->getUrl(); |
||
360 | $fna = mb_split('\\/', $url); |
||
361 | $filename = end($fna); |
||
362 | |||
363 | $dir1 = mb_strtoupper(mb_substr($filename, 0, 1)); |
||
364 | $dir2 = mb_strtoupper(mb_substr($filename, 1, 1)); |
||
365 | |||
366 | return $opt['logic']['pictures']['thumb_dir'] . $dir1 . '/' . $dir2 . '/' . $filename; |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * @return string |
||
371 | */ |
||
372 | public function getLogId() |
||
373 | { |
||
374 | if ($this->getObjectType() == OBJECT_CACHELOG) { |
||
375 | return $this->getObjectId(); |
||
376 | } |
||
377 | |||
378 | return false; |
||
0 ignored issues
–
show
|
|||
379 | } |
||
380 | |||
381 | /** |
||
382 | * @return bool|null |
||
383 | */ |
||
384 | public function isVisibleOnCachePage() |
||
385 | { |
||
386 | if ($this->getObjectType() != OBJECT_CACHELOG) { |
||
387 | return null; |
||
388 | } |
||
389 | $rs = sql( |
||
390 | "SELECT `id` |
||
391 | FROM `cache_logs` |
||
392 | WHERE `cache_id`='&1' |
||
393 | ORDER BY `date`, `id` DESC |
||
394 | LIMIT &2", |
||
395 | $this->getCacheId(), |
||
396 | MAX_LOGENTRIES_ON_CACHEPAGE |
||
397 | ); |
||
398 | |||
399 | $firstlogs = false; |
||
400 | while ($r = sql_fetch_assoc($rs)) { |
||
401 | if ($r['id'] == $this->getLogId()) { |
||
402 | $firstlogs = true; |
||
403 | } |
||
404 | } |
||
405 | |||
406 | sql_free_result($rs); |
||
407 | |||
408 | return $firstlogs; |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * @return string |
||
413 | */ |
||
414 | View Code Duplication | public function getCacheId() |
|
415 | { |
||
416 | if ($this->getObjectType() == OBJECT_CACHELOG) { |
||
417 | return sql_value("SELECT `cache_id` FROM `cache_logs` WHERE `id`='&1'", false, $this->getObjectId()); |
||
418 | } elseif ($this->getObjectType() == OBJECT_CACHE) { |
||
419 | return $this->getObjectId(); |
||
420 | } |
||
421 | |||
422 | return false; |
||
0 ignored issues
–
show
The return type of
return false; (false ) is incompatible with the return type documented by picture::getCacheId of type string .
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design. Let’s take a look at an example: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
423 | } |
||
424 | |||
425 | /** |
||
426 | * @return mixed |
||
427 | */ |
||
428 | public function getObjectId() |
||
429 | { |
||
430 | return $this->rePicture->getValue('object_id'); |
||
431 | } |
||
432 | |||
433 | /** |
||
434 | * @param $value |
||
435 | * @return bool |
||
436 | */ |
||
437 | public function setObjectId($value) |
||
438 | { |
||
439 | return $this->rePicture->setValue('object_id', $value + 0); |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * @return mixed |
||
444 | */ |
||
445 | public function getObjectType() |
||
446 | { |
||
447 | return $this->rePicture->getValue('object_type'); |
||
448 | } |
||
449 | |||
450 | /** |
||
451 | * @param $value |
||
452 | * @return bool |
||
453 | */ |
||
454 | public function setObjectType($value) |
||
455 | { |
||
456 | return $this->rePicture->setValue('object_type', $value + 0); |
||
457 | } |
||
458 | |||
459 | /** |
||
460 | * @return bool|mixed |
||
461 | */ |
||
462 | View Code Duplication | public function getUserId() |
|
463 | { |
||
464 | if ($this->getObjectType() == OBJECT_CACHE) { |
||
465 | return sql_value( |
||
466 | "SELECT `caches`.`user_id` FROM `caches` WHERE `caches`.`cache_id`='&1'", |
||
467 | false, |
||
468 | $this->getObjectId() |
||
469 | ); |
||
470 | } elseif ($this->getObjectType() == OBJECT_CACHELOG) { |
||
471 | return sql_value( |
||
472 | "SELECT `cache_logs`.`user_id` FROM `cache_logs` WHERE `cache_logs`.`id`='&1'", |
||
473 | false, |
||
474 | $this->getObjectId() |
||
475 | ); |
||
476 | } |
||
477 | |||
478 | return false; |
||
479 | } |
||
480 | |||
481 | /** |
||
482 | * @return mixed |
||
483 | */ |
||
484 | public function getNode() |
||
485 | { |
||
486 | return $this->rePicture->getValue('node'); |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * @param $value |
||
491 | * @return bool |
||
492 | */ |
||
493 | public function setNode($value) |
||
494 | { |
||
495 | return $this->rePicture->setValue('node', $value); |
||
496 | } |
||
497 | |||
498 | /** |
||
499 | * @return mixed |
||
500 | */ |
||
501 | public function getUUID() |
||
502 | { |
||
503 | return $this->rePicture->getValue('uuid'); |
||
504 | } |
||
505 | |||
506 | /** |
||
507 | * @return mixed |
||
508 | */ |
||
509 | public function getLastModified() |
||
510 | { |
||
511 | return $this->rePicture->getValue('last_modified'); |
||
512 | } |
||
513 | |||
514 | /** |
||
515 | * @return mixed |
||
516 | */ |
||
517 | public function getDateCreated() |
||
518 | { |
||
519 | return $this->rePicture->getValue('date_created'); |
||
520 | } |
||
521 | |||
522 | /** |
||
523 | * @return mixed |
||
524 | */ |
||
525 | public function getPosition() |
||
526 | { |
||
527 | return $this->rePicture->getValue('seq'); |
||
528 | } |
||
529 | |||
530 | /** |
||
531 | * @param int $position |
||
532 | */ |
||
533 | public function setPosition($position) |
||
534 | { |
||
535 | if ($this->originalPosition === false) { |
||
536 | // position numbers are always >= 1 |
||
537 | $this->rePicture->setValue('seq', max(1, $position)); |
||
538 | } |
||
539 | // repositioning existing pictures is not implemented yet |
||
540 | } |
||
541 | |||
542 | /** |
||
543 | * @return bool|null |
||
544 | */ |
||
545 | public function getAnyChanged() |
||
546 | { |
||
547 | return $this->rePicture->getAnyChanged(); |
||
548 | } |
||
549 | |||
550 | // Test if the picture can be discarded as duplicate. |
||
551 | // This is a quick test for Ocprop dups and may be extended for any |
||
552 | // picture uploads by comparing the file sizes and contents. |
||
553 | |||
554 | /** |
||
555 | * @return bool |
||
556 | */ |
||
557 | public function is_duplicate() |
||
558 | { |
||
559 | global $ocpropping; |
||
560 | |||
561 | return $ocpropping && |
||
562 | sql_value( |
||
563 | " |
||
564 | SELECT COUNT(*) FROM `pictures` |
||
565 | WHERE `object_type`='&1' AND `object_id`='&2' AND `title`='&3'", |
||
566 | 0, |
||
567 | $this->getObjectType(), |
||
568 | $this->getObjectId(), |
||
569 | $this->getTitle() |
||
570 | ) > 0; |
||
571 | } |
||
572 | |||
573 | /** |
||
574 | * return true if successful (with insert) |
||
575 | * |
||
576 | * @param bool $restore |
||
577 | * @param int $original_id |
||
578 | * @param string $original_url |
||
579 | * @return bool |
||
580 | */ |
||
581 | public function save($restore = false, $original_id = 0, $original_url = '') |
||
582 | { |
||
583 | $undelete = ($original_id != 0); |
||
584 | |||
585 | if ($undelete) { |
||
586 | if ($this->bFilenamesSet == true) { |
||
587 | return false; |
||
588 | } |
||
589 | // restore picture file |
||
590 | $this->setUrl($original_url); // set the url, so that we can |
||
591 | $filename = $this->getFilename(); // .. retrieve the file path+name |
||
592 | $this->setFilenames($filename); // now set url(s) from the new uuid |
||
593 | try { |
||
594 | rename($this->deletedFilename($filename), $this->getFilename()); |
||
595 | } catch (Exception $e) { |
||
596 | // @todo implement logging |
||
597 | } |
||
598 | } |
||
599 | |||
600 | if ($this->bFilenamesSet == false) { |
||
601 | return false; |
||
602 | } |
||
603 | |||
604 | // produce a position number gap for inserting |
||
605 | sql( |
||
606 | "UPDATE `pictures` |
||
607 | SET `seq`=`seq`+1 |
||
608 | WHERE `object_type`='&1' AND `object_id`='&2' AND `seq` >= '&3' |
||
609 | ORDER BY `seq` DESC", |
||
610 | $this->getObjectType(), |
||
611 | $this->getObjectId(), |
||
612 | $this->getPosition() |
||
613 | ); |
||
614 | |||
615 | // The seq numbers need not to be consecutive, so it dosen't matter |
||
616 | // if something fails here and leaves the gap open. |
||
617 | |||
618 | $this->setArchiveFlag($restore, $original_id); |
||
619 | $bRetVal = $this->rePicture->save(); |
||
620 | $this->resetArchiveFlag(); |
||
621 | |||
622 | if ($bRetVal) { |
||
623 | $this->nPictureId = $this->rePicture->getValue('id'); |
||
624 | if ($this->getObjectType() == OBJECT_CACHE && $this->getMapPreview()) { |
||
625 | sql( |
||
626 | "UPDATE `pictures` SET `mappreview`= 0 |
||
627 | WHERE `object_type`='&1' AND `object_id`='&2' AND `id`!='&3'", |
||
628 | OBJECT_CACHE, |
||
629 | $this->getObjectId(), |
||
630 | $this->getPictureId() |
||
631 | ); |
||
632 | } |
||
633 | sql_slave_exclude(); |
||
634 | } |
||
635 | |||
636 | return $bRetVal; |
||
637 | } |
||
638 | |||
639 | /** |
||
640 | * @param bool $restore |
||
641 | * @return bool |
||
642 | */ |
||
643 | public function delete($restore = false) |
||
644 | { |
||
645 | // see also removelog.php, 'remove log pictures' |
||
646 | // delete record, image and thumb |
||
647 | $this->setArchiveFlag($restore); |
||
648 | sql("DELETE FROM `pictures` WHERE `id`='&1'", $this->nPictureId); |
||
649 | $this->resetArchiveFlag(); |
||
650 | $filename = $this->getFilename(); |
||
651 | |||
652 | // archive picture if picture record has been archived |
||
653 | if (sql_value("SELECT `id` FROM `pictures_modified` WHERE `id`='&1'", 0, $this->getPictureId()) != 0) { |
||
654 | try { |
||
655 | rename($filename, $this->deletedFilename($filename)); |
||
656 | } catch (Exception $e) { |
||
657 | // @todo implement logging |
||
658 | } |
||
659 | } else { |
||
660 | try { |
||
661 | unlink($filename); |
||
662 | } catch (Exception $e) { |
||
663 | // @todo implement logging |
||
664 | } |
||
665 | } |
||
666 | |||
667 | try { |
||
668 | unlink($this->getThumbFilename()); |
||
669 | } catch (Exception $e) { |
||
670 | // @todo implement logging |
||
671 | } |
||
672 | |||
673 | return true; |
||
674 | } |
||
675 | |||
676 | /** |
||
677 | * @param string $filename |
||
678 | * |
||
679 | * @return string |
||
680 | */ |
||
681 | private function deletedFilename($filename) |
||
682 | { |
||
683 | $fna = mb_split('\\/', $filename); |
||
684 | $fna[] = end($fna); |
||
685 | $fna[count($fna) - 2] = 'deleted'; |
||
686 | $dp = ''; |
||
687 | foreach ($fna as $fp) { |
||
688 | $dp .= '/' . $fp; |
||
689 | } |
||
690 | |||
691 | return substr($dp, 1); |
||
692 | } |
||
693 | |||
694 | View Code Duplication | public function allowEdit() |
|
695 | { |
||
696 | global $login; |
||
697 | |||
698 | $login->verify(); |
||
699 | |||
700 | if (sql_value( |
||
701 | "SELECT COUNT(*) |
||
702 | FROM `caches` |
||
703 | INNER JOIN `cache_status` ON `caches`.`status`=`cache_status`.`id` |
||
704 | WHERE (`cache_status`.`allow_user_view`=1 OR `caches`.`user_id`='&1') |
||
705 | AND `caches`.`cache_id`='&2'", |
||
706 | 0, |
||
707 | $login->userid, |
||
708 | $this->getCacheId() |
||
709 | ) == 0) { |
||
710 | return false; |
||
711 | } elseif ($this->getUserId() == $login->userid) { |
||
712 | return true; |
||
713 | } |
||
714 | |||
715 | return false; |
||
716 | } |
||
717 | |||
718 | /** |
||
719 | * @return bool|string |
||
720 | */ |
||
721 | public function getPageLink() |
||
722 | { |
||
723 | if ($this->getObjectType() == OBJECT_CACHELOG) { |
||
724 | $pl = 'viewcache.php?cacheid=' . urlencode($this->getCacheId()); |
||
725 | if (!$this->isVisibleOnCachePage()) { |
||
726 | $pl .= '&log=A'; |
||
727 | } |
||
728 | $pl .= '#log' . urlencode($this->getLogId()); |
||
729 | } elseif ($this->getObjectType() == OBJECT_CACHE) { |
||
730 | $pl = 'editcache.php?cacheid=' . urlencode($this->getCacheId()) . '#pictures'; |
||
731 | } else { |
||
732 | $pl = false; |
||
733 | } |
||
734 | |||
735 | return $pl; |
||
736 | } |
||
737 | |||
738 | /* |
||
739 | Shrink picture to a specified maximum size. If present Imagemagick extension will be used, if not gd. |
||
740 | Imagick is sharper, faster, need less memory and supports more types. |
||
741 | For gd size is limited to 5000px (memory consumption). |
||
742 | i prefer FILTER_CATROM because its faster but similiar to lanczos see http://de1.php.net/manual/de/imagick.resizeimage.php |
||
743 | parameter: |
||
744 | $tmpfile: full name of uploaded file |
||
745 | $longSideSize: if longer side of picture > $longSideSize, then it will be prop. shrinked to |
||
746 | returns: true if no error occur, otherwise false |
||
747 | |||
748 | * @param $tmpFile |
||
749 | * @param $longSideSize |
||
750 | * @return bool |
||
751 | */ |
||
752 | public function rotate_and_shrink($tmpFile, $longSideSize) |
||
753 | { |
||
754 | global $opt; |
||
755 | if (extension_loaded('imagick')) { |
||
756 | try { |
||
757 | $image = new Imagick(); |
||
758 | $image->readImage($tmpFile); |
||
759 | $this->imagick_rotate($image); |
||
760 | $w = $image->getImageWidth(); |
||
761 | $h = $image->getImageHeight(); |
||
762 | $image->setImageResolution(PICTURE_RESOLUTION, PICTURE_RESOLUTION); |
||
763 | $image->setImageCompression(Imagick::COMPRESSION_JPEG); |
||
764 | $image->setImageCompressionQuality(PICTURE_QUALITY); |
||
765 | $image->stripImage(); //clears exif, private data |
||
766 | //$newSize=$w<$h?array($w*$longSideSize/$h,$longSideSize):array($longSideSize,$h*$longSideSize/$w); |
||
767 | if (max($w, $h) > $longSideSize) { |
||
768 | $image->resizeImage($longSideSize, $longSideSize, imagick::FILTER_CATROM, 1, true); |
||
769 | } |
||
770 | $result = $image->writeImage($this->getFilename()); |
||
771 | $image->clear(); |
||
772 | } catch (Exception $e) { |
||
773 | if ($image) { |
||
774 | $image->clear(); |
||
775 | } |
||
776 | if ($opt['debug'] & DEBUG_DEVELOPER) { |
||
777 | die($e); |
||
778 | } |
||
779 | $result = false; |
||
780 | } |
||
781 | |||
782 | return $result; |
||
783 | } elseif (extension_loaded('gd')) { |
||
784 | $imageNew = null; |
||
785 | try { |
||
786 | $image = imagecreatefromstring(file_get_contents($tmpFile)); |
||
787 | $w = imagesx($image); |
||
788 | $h = imagesy($image); |
||
789 | if (max($w, $h) > 5000) { |
||
790 | throw new Exception('Image too large >5000px'); |
||
791 | } |
||
792 | if (max($w, $h) <= $longSideSize) { |
||
793 | $result = imagejpeg($image, $this->getFilename(), PICTURE_QUALITY); |
||
794 | } else { |
||
795 | $newSize = $w < $h ? [ |
||
796 | $w * $longSideSize / $h, |
||
797 | $longSideSize, |
||
798 | ] : [ |
||
799 | $longSideSize, |
||
800 | $h * $longSideSize / $w, |
||
801 | ]; |
||
802 | $imageNew = imagecreatetruecolor($newSize[0], $newSize[1]); |
||
803 | imagecopyresampled($imageNew, $image, 0, 0, 0, 0, $newSize[0], $newSize[1], $w, $h); |
||
804 | $result = imagejpeg($imageNew, $this->getFilename(), PICTURE_QUALITY); |
||
805 | imagedestroy($imageNew); |
||
806 | } |
||
807 | imagedestroy($image); |
||
808 | } catch (Exception $e) { |
||
809 | if ($image) { |
||
810 | imagedestroy($image); |
||
811 | } |
||
812 | if ($imageNew) { |
||
813 | imagedestroy($imageNew); |
||
814 | } |
||
815 | if ($opt['debug'] & DEBUG_DEVELOPER) { |
||
816 | die($e); |
||
817 | } |
||
818 | $result = false; |
||
819 | } |
||
820 | |||
821 | return $result; |
||
822 | } |
||
823 | |||
824 | return false; |
||
825 | } |
||
826 | |||
827 | /** |
||
828 | * rotate image according to EXIF orientation |
||
829 | * |
||
830 | * @param $tmpFile |
||
831 | * @return bool |
||
832 | */ |
||
833 | public function rotate($tmpFile) |
||
834 | { |
||
835 | if (extension_loaded('imagick')) { |
||
836 | try { |
||
837 | $image = new Imagick(); |
||
838 | $image->readImage($tmpFile); |
||
839 | if ($this->imagick_rotate($image)) { |
||
840 | $image->stripImage(); // clears exif, private data |
||
841 | $image->writeImage($this->getFilename()); |
||
842 | $image->clear(); |
||
843 | |||
844 | return true; |
||
845 | } |
||
846 | $image->clear(); |
||
847 | } catch (Exception $e) { |
||
848 | if ($image) { |
||
849 | $image->clear(); |
||
850 | } |
||
851 | |||
852 | return false; |
||
853 | } |
||
854 | } |
||
855 | |||
856 | return move_uploaded_file($tmpFile, $this->getFilename()); |
||
857 | } |
||
858 | |||
859 | /** |
||
860 | * @param Imagick $image |
||
861 | * |
||
862 | * @return bool |
||
863 | */ |
||
864 | public function imagick_rotate(&$image) |
||
865 | { |
||
866 | $exif = $image->getImageProperties(); |
||
867 | if (isset($exif['exif:Orientation'])) { |
||
868 | switch ($exif['exif:Orientation']) { |
||
869 | case 3: |
||
870 | return $image->rotateImage(new ImagickPixel(), 180); |
||
871 | case 6: |
||
872 | return $image->rotateImage(new ImagickPixel(), 90); |
||
873 | case 8: |
||
874 | return $image->rotateImage(new ImagickPixel(), -90); |
||
875 | } |
||
876 | } |
||
877 | |||
878 | return false; |
||
879 | } |
||
880 | |||
881 | /** |
||
882 | * @return bool |
||
883 | */ |
||
884 | public function up() |
||
885 | { |
||
886 | // TODO: protect the following operations by a transaction |
||
887 | |||
888 | $prevPos = sql_value( |
||
889 | " |
||
890 | SELECT MAX(`seq`) |
||
891 | FROM `pictures` |
||
892 | WHERE `object_type`='&1' AND `object_id`='&2' AND `seq`<'&3'", |
||
893 | 0, |
||
894 | $this->getObjectType(), |
||
895 | $this->getObjectId(), |
||
896 | $this->getPosition() |
||
897 | ); |
||
898 | |||
899 | if ($prevPos) { |
||
900 | $maxPos = sql_value( |
||
901 | " |
||
902 | SELECT MAX(`seq`) |
||
903 | FROM `pictures` |
||
904 | WHERE `object_type`='&1' AND `object_id`='&2'", |
||
905 | 0, |
||
906 | $this->getObjectType(), |
||
907 | $this->getObjectId() |
||
908 | ); |
||
909 | |||
910 | // swap positions with the previous pic |
||
911 | sql( |
||
912 | " |
||
913 | UPDATE `pictures` |
||
914 | SET `seq`='&2' |
||
915 | WHERE `id`='&1'", |
||
916 | $this->getPictureId(), |
||
917 | $maxPos + 1 |
||
918 | ); |
||
919 | // If something goes wrong from here (i.e. DB server failure) and |
||
920 | // we are moving anything else but the last picture, it will |
||
921 | // produce a wrong picture order. No big deal, the user can easily |
||
922 | // correct that, but still a transaction would be nice. |
||
923 | sql( |
||
924 | " |
||
925 | UPDATE `pictures` SET `seq`='&4' |
||
926 | WHERE `object_type`='&1' AND `object_id`='&2' AND `seq`='&3'", |
||
927 | $this->getObjectType(), |
||
928 | $this->getObjectId(), |
||
929 | $prevPos, |
||
930 | $this->getPosition() |
||
931 | ); |
||
932 | sql( |
||
933 | " |
||
934 | UPDATE `pictures` |
||
935 | SET `seq`='&2' |
||
936 | WHERE `id`='&1'", |
||
937 | $this->getPictureId(), |
||
938 | $prevPos |
||
939 | ); |
||
940 | $this->rePicture->setValue('seq', $prevPos); |
||
941 | |||
942 | return true; |
||
943 | } |
||
944 | |||
945 | return false; |
||
946 | } |
||
947 | } |
||
948 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.