Completed
Push — master ( 2a7334...2bafa1 )
by Andreas
19:53
created

org/openpsa/documents/elFinderVolumeOpenpsa.php (2 issues)

1
<?php
2
/**
3
 * @package org.openpsa.documents
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
/**
10
 * elFinder driver
11
 *
12
 * @package org.openpsa.documents
13
 */
14
class elFinderVolumeOpenpsa extends elFinderVolumeDriver
15
{
16
    public function __construct()
17
    {
18
        // elfinder tmp detection doesn't work on OS X
19
        $this->tmpPath = midcom::get()->config->get('midcom_tempdir');
20
        // elfinder calls exit(), so we need to make sure we write caches
21
        register_shutdown_function(function () {
22
            midcom::get()->finish();
23
        });
24
    }
25
26
    /**
27
     * Save uploaded file.
28
     * On success return array with new file stat and with removed file hash (if existed file was replaced)
29
     *
30
     * Copied from parent and slightly modified to support attachment versioning
31
     *
32
     * @param  Resource $fp      file pointer
33
     * @param  string   $dst     destination folder hash
34
     * @param  string   $name     file name
35
     * @param  string   $tmpname file tmp name - required to detect mime type
36
     * @return array|false
37
     * @author Dmitry (dio) Levashov
38
     **/
39
    public function upload($fp, $dst, $name, $tmpname, $hashes = [])
40
    {
41
        if ($this->commandDisabled('upload')) {
42
            return $this->setError(elFinder::ERROR_PERM_DENIED);
43
        }
44
45
        if (($dir = $this->dir($dst)) == false) {
46
            return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst);
47
        }
48
49
        if (!$dir['write']) {
50
            return $this->setError(elFinder::ERROR_PERM_DENIED);
51
        }
52
53
        if (!$this->nameAccepted($name)) {
54
            return $this->setError(elFinder::ERROR_INVALID_NAME);
55
        }
56
57
        $mime = $this->mimetype($this->mimeDetect == 'internal' ? $name : $tmpname, $name);
58
        $mimeByName = '';
59
        if ($this->mimeDetect !== 'internal') {
60
            $mimeByName = elFinderVolumeDriver::mimetypeInternalDetect($name);
61
            if ($mime == 'unknown') {
62
                $mime = $mimeByName;
63
            }
64
        }
65
66
        if (!$this->allowPutMime($mime) || ($mimeByName && $mimeByName !== 'unknown' && !$this->allowPutMime($mimeByName))) {
67
            return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME);
68
        }
69
70
        $tmpsize = sprintf('%u', filesize($tmpname));
71
        if ($this->uploadMaxSize > 0 && $tmpsize > $this->uploadMaxSize) {
72
            return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE);
73
        }
74
75
        $dstpath = $this->decode($dst);
76
        if (isset($hashes[$name])) {
77
            $test = $this->decode($hashes[$name]);
78
        } else {
79
            $test = $this->joinPathCE($dstpath, $name);
80
        }
81
82
        $file = $this->stat($test);
83
        $this->clearcache();
84
85
        if ($file && $file['name'] === $name) { // file exists and check filename for item ID based filesystem
86
            // check POST data `overwrite` for 3rd party uploader
87
            $overwrite = isset($_POST['overwrite'])? (bool)$_POST['overwrite'] : $this->options['uploadOverwrite'];
88
            if ($overwrite) {
89
                if (!$file['write']) {
90
                    return $this->setError(elFinder::ERROR_PERM_DENIED);
91
                }
92
                if ($file['mime'] == 'directory') {
93
                    return $this->setError(elFinder::ERROR_NOT_REPLACE, $name);
94
                }
95
                $document = new org_openpsa_documents_document_dba($test);
96
                $document->backup_version();
97
                $attachments = org_openpsa_helpers::get_dm2_attachments($document, 'document');
98
                foreach ($attachments as $att) {
99
                    if (!$att->delete()) {
100
                        return false;
101
                    }
102
                }
103
104
                if (!$this->create_attachment($document, $name, $mime, $fp)) {
105
                    return false;
106
                }
107
                //make sure metadata.revised changes
108
                $document->update();
109
110
                return $this->stat($document->guid);
111
            } else {
112
                $name = $this->uniqueName($dstpath, $name, '-', false);
113
            }
114
        }
115
116
        $stat = [
117
            'mime'   => $mime,
118
            'width'  => 0,
119
            'height' => 0,
120
            'size'   => $tmpsize];
121
122
        if (strpos($mime, 'image') === 0 && ($s = getimagesize($tmpname))) {
123
            $stat['width'] = $s[0];
124
            $stat['height'] = $s[1];
125
        }
126
127
        if (($path = $this->saveCE($fp, $dstpath, $name, $stat)) == false) {
128
            return false;
129
        }
130
131
        return $this->stat($path);
132
    }
133
134
    private function get_by_path($path)
135
    {
136
        try {
137
            return org_openpsa_documents_document_dba::get_cached($path);
138
        } catch (midcom_error $e) {
139
            $e->log();
140
            try {
141
                return org_openpsa_documents_directory::get_cached($path);
142
            } catch (midcom_error $e) {
143
                $e->log();
144
            }
145
        }
146
        return false;
147
    }
148
149
    /**
150
     * Return parent directory path
151
     *
152
     * @param  string  $path  file path
153
     * @return string
154
     */
155
    protected function _dirname($path)
156
    {
157
        $object = $this->get_by_path($path);
158
        if ($object === false) {
159
            return '';
160
        }
161
        return $object->get_parent()->guid;
162
    }
163
164
    /**
165
     * Return file name
166
     *
167
     * @param  string  $path  file path
168
     * @return string
169
     */
170
    protected function _basename($path)
171
    {
172
        $object = $this->get_by_path($path);
173
        if ($object === false) {
174
            return '';
175
        }
176
        return $object->get_label();
177
    }
178
179
    /**
180
     * Join dir name and file name and return full path.
181
     * Some drivers (db) use int as path - so we give to concat path to driver itself
182
     *
183
     * @param  string  $dir   dir path
184
     * @param  string  $name  file name
185
     * @return string
186
     */
187
    protected function _joinPath($dir, $name)
188
    {
189
        $mc = org_openpsa_documents_document_dba::new_collector('title', $name);
190
        $mc->add_constraint('topic.guid', '=', $dir);
191
        $keys = $mc->list_keys();
192
        if ($keys) {
193
            return key($keys);
194
        }
195
        $mc = org_openpsa_documents_directory::new_collector('extra', $name);
196
        $mc->add_constraint('up.guid', '=', $dir);
197
        $keys = $mc->list_keys();
198
        if ($keys) {
199
            return key($keys);
200
        }
201
        return -1;
202
    }
203
204
    /**
205
     * Return normalized path
206
     *
207
     * @param  string  $path  file path
208
     * @return string
209
     */
210
    protected function _normpath($path)
211
    {
212
        return $path;
213
    }
214
215
    /**
216
     * Return file path related to root dir
217
     *
218
     * @param  string  $path  file path
219
     * @return string
220
     */
221
    protected function _relpath($path)
222
    {
223
        return $path;
224
    }
225
226
    /**
227
     * Convert path related to root dir into real path
228
     *
229
     * @param  string  $path  rel file path
230
     * @return string
231
     */
232
    protected function _abspath($path)
233
    {
234
        return $path;
235
    }
236
237
    /**
238
     * Return fake path started from root dir.
239
     * Required to show path on client side.
240
     *
241
     * @param  string  $path  file path
242
     * @return string
243
     */
244
    protected function _path($path)
245
    {
246
        $object = $this->get_by_path($path);
247
        if ($object === false) {
248
            return '';
249
        }
250
        $output = [$object->get_label()];
251
252
        $parent = $object->get_parent();
253
        while (   $parent
254
               && $parent->component == 'org.openpsa.documents') {
0 ignored issues
show
Bug Best Practice introduced by
The property component does not exist on midcom_core_dbaobject. Since you implemented __get, consider adding a @property annotation.
Loading history...
255
            $output[] = $parent->extra;
0 ignored issues
show
Bug Best Practice introduced by
The property extra does not exist on midcom_core_dbaobject. Since you implemented __get, consider adding a @property annotation.
Loading history...
256
            $parent = $parent->get_parent();
257
        }
258
        $output[] = $this->rootName;
259
        return implode($this->separator, $output);
260
    }
261
262
    /**
263
     * Return true if $path is children of $parent
264
     *
265
     * @param  string  $path    path to check
266
     * @param  string  $parent  parent path
267
     * @return bool
268
     */
269
    protected function _inpath($path, $parent)
270
    {
271
        if ($path === $parent) {
272
            return true;
273
        }
274
275
        $object = midcom::get()->dbfactory->get_object_by_guid($path);
276
        try {
277
            $parentdir = org_openpsa_documents_directory::get_cached($parent);
278
        } catch (midcom_error $e) {
279
            $e->log();
280
            return false;
281
        }
282
283
        $qb = org_openpsa_documents_directory::new_query_builder();
284
        $qb->add_constraint('up', 'INTREE', $parentdir->id);
285
        if ($object instanceof org_openpsa_documents_document_dba) {
286
            $qb->add_constraint('id', '=', $object->topic);
287
        } else {
288
            $qb->add_constraint('id', '=', $object->id);
289
        }
290
        return $qb->count() > 0;
291
    }
292
293
    /**
294
     * Return stat for given path.
295
     * Stat contains following fields:
296
     * - (int)    size    file size in b. required
297
     * - (int)    ts      file modification time in unix time. required
298
     * - (string) mime    mimetype. required for folders, others - optionally
299
     * - (bool)   read    read permissions. required
300
     * - (bool)   write   write permissions. required
301
     * - (bool)   locked  is object locked. optionally
302
     * - (bool)   hidden  is object hidden. optionally
303
     * - (string) alias   for symlinks - link target path relative to root path. optionally
304
     * - (string) target  for symlinks - link target path. optionally
305
     *
306
     * If file does not exists - returns empty array or false.
307
     *
308
     * @param  string  $path    file path
309
     * @return array|false
310
     */
311
    protected function _stat($path)
312
    {
313
        if (!mgd_is_guid($path)) {
314
            return false;
315
        }
316
        $object = midcom::get()->dbfactory->get_object_by_guid($path);
317
318
        $data = [
319
            'ts' => $object->metadata->revised,
320
            'read' => true,
321
            'write' => $object->can_do('midgard:update'),
322
            'locked' => $object->metadata->is_locked(),
323
            'mime' => ''
324
        ];
325
        $creator = org_openpsa_widgets_contact::get($object->metadata->creator);
326
        $data['owner'] = $creator->show_inline();
327
328
        if ($object instanceof org_openpsa_documents_document_dba) {
329
            $owner = $object->orgOpenpsaOwnerWg;
330
331
            $attachments = org_openpsa_helpers::get_dm2_attachments($object, 'document');
332
            if ($attachments) {
333
                $att = current($attachments);
334
                $data['mime'] = $att->mimetype;
335
                if ($stat = $att->stat()) {
336
                    $data['size'] = $stat['size'];
337
                }
338
            }
339
        } else {
340
            $owner = $object->get_parameter('org.openpsa.core', 'orgOpenpsaOwnerWg');
341
342
            $qb = org_openpsa_documents_directory::new_query_builder();
343
            $qb->add_constraint('up', '=', $object->id);
344
            $qb->add_constraint('component', '=', 'org.openpsa.documents');
345
            $qb->set_limit(1);
346
            $data['dirs'] = $qb->count();
347
            $data['mime'] = 'directory';
348
        }
349
350
        if (   $owner
351
            && $group = midcom::get()->auth->get_assignee($owner)) {
352
            $data['group'] = $group->name;
353
        }
354
355
        if (   $this->root !== $path
356
            && $parent = $object->get_parent()) {
357
            $data['phash'] = $this->encode($parent->guid);
358
        }
359
        return $data;
360
    }
361
362
    /**
363
     * Return true if path is dir and has at least one childs directory
364
     *
365
     * @param  string  $path  dir path
366
     * @return bool
367
     */
368
    protected function _subdirs($path)
369
    {
370
        $topic = org_openpsa_documents_directory::get_cached($path);
371
        $qb = org_openpsa_documents_directory::new_query_builder();
372
        $qb->add_constraint('up', '=', $topic->id);
373
        $qb->add_constraint('component', '=', 'org.openpsa.documents');
374
        $qb->set_limit(1);
375
        return $qb->count() > 0;
376
    }
377
378
    /**
379
     * Return object width and height
380
     * Ususaly used for images, but can be realize for video etc...
381
     *
382
     * @param  string  $path  file path
383
     * @param  string  $mime  file mime type
384
     * @return string
385
     */
386
    protected function _dimensions($path, $mime)
387
    {
388
        throw new midcom_error('_dimensions not implemented');
389
    }
390
391
    /**
392
     * Return files list in directory
393
     *
394
     * @param  string  $path  dir path
395
     * @return array
396
     */
397
    protected function _scandir($path)
398
    {
399
        $topic = org_openpsa_documents_directory::get_cached($path);
400
        $mc = org_openpsa_documents_document_dba::new_collector('topic', $topic->id);
401
        $mc->add_constraint('nextVersion', '=', 0);
402
        $files = array_keys($mc->list_keys());
403
        $mc = org_openpsa_documents_directory::new_collector('up', $topic->id);
404
        return array_merge($files, array_keys($mc->list_keys()));
405
    }
406
407
    /**
408
     * Open file and return file pointer
409
     *
410
     * @param  string $path file path
411
     * @param  string $mode open mode
412
     * @return resource|false
413
     */
414
    protected function _fopen($path, $mode="rb")
415
    {
416
        $document = org_openpsa_documents_document_dba::get_cached($path);
417
        $attachments = org_openpsa_helpers::get_dm2_attachments($document, 'document');
418
        if ($attachments) {
419
            $att = current($attachments);
420
            return $att->open($mode);
421
        }
422
        return false;
423
    }
424
425
    /**
426
     * Close opened file
427
     *
428
     * @param  resource  $fp    file pointer
429
     * @param  string    $path  file path
430
     * @return bool
431
     */
432
    protected function _fclose($fp, $path='')
433
    {
434
        fclose($fp);
435
        return true;
436
    }
437
438
    /**
439
     * Create dir and return created dir path or false on failed
440
     *
441
     * @param  string  $path  parent dir path
442
     * @param string  $name  new directory name
443
     * @return string|bool
444
     */
445
    protected function _mkdir($path, $name)
446
    {
447
        $parent = org_openpsa_documents_directory::get_cached($path);
448
        $dir = new org_openpsa_documents_directory;
449
        $dir->extra = $name;
450
        $dir->component = 'org.openpsa.documents';
451
        $dir->up = $parent->id;
452
        if (!$dir->create()) {
453
            return false;
454
        }
455
        if ($groups = org_openpsa_helpers_list::workgroups()) {
456
            $dir->set_parameter('org.openpsa.core', 'orgOpenpsaOwnerWg', key($groups));
457
        }
458
        $access_types = org_openpsa_core_acl::get_options();
459
        $dir->set_parameter('org.openpsa.core', 'orgOpenpsaAccesstype', key($access_types));
460
461
        return $dir->guid;
462
    }
463
464
    private function create_document($parentguid, $title)
465
    {
466
        $dir = org_openpsa_documents_directory::get_cached($parentguid);
467
        $document = new org_openpsa_documents_document_dba;
468
        $document->topic = $dir->id;
469
        $document->title = $title;
470
        $document->author = midcom_connection::get_user();
471
        $document->docStatus = org_openpsa_documents_document_dba::STATUS_DRAFT;
472
        $document->orgOpenpsaOwnerWg = $dir->get_parameter('org.openpsa.core', 'orgOpenpsaOwnerWg');
473
        $document->orgOpenpsaAccesstype = $dir->get_parameter('org.openpsa.core', 'orgOpenpsaAccesstype');
474
475
        if ($document->create()) {
476
            return $document;
477
        }
478
        return false;
479
    }
480
481
    /**
482
     * Create file and return its path or false on failed
483
     *
484
     * @param  string  $path  parent dir path
485
     * @param string  $name  new file name
486
     * @return string|bool
487
     */
488
    protected function _mkfile($path, $name)
489
    {
490
        if ($document = $this->create_document($path, $name)) {
491
            return $document->guid;
492
        }
493
        return false;
494
    }
495
496
    /**
497
     * Create symlink
498
     *
499
     * @param  string  $source     file to link to
500
     * @param  string  $targetDir  folder to create link in
501
     * @param  string  $name       symlink name
502
     * @return bool
503
     */
504
    protected function _symlink($source, $targetDir, $name)
505
    {
506
        return false;
507
    }
508
509
    /**
510
     * Copy file into another file (only inside one volume)
511
     *
512
     * @param  string  $source     source file path
513
     * @param  string  $targetDir  target dir path
514
     * @param  string  $name       file name
515
     * @return bool
516
     */
517
    protected function _copy($source, $targetDir, $name)
518
    {
519
        $target = org_openpsa_documents_directory::get_cached($targetDir);
520
        $source = midcom::get()->dbfactory->get_object_by_guid($source);
521
        $copy = new midcom_helper_reflector_copy;
522
        $copy->source = $source;
523
        $copy->target = $target;
524
525
        if (!$copy->execute()) {
526
            debug_print_r('Copying failed with the following errors', $copy->errors, MIDCOM_LOG_ERROR);
527
            return false;
528
        }
529
530
        return $copy->get_object()->guid;
531
    }
532
533
    /**
534
     * Move file into another parent dir.
535
     * Return new file path or false.
536
     *
537
     * @param  string  $source     source file path
538
     * @param  string  $targetDir  target dir path
539
     * @param  string  $name       file name
540
     * @return string|bool
541
     */
542
    protected function _move($source, $targetDir, $name)
543
    {
544
        $target = org_openpsa_documents_directory::get_cached($targetDir);
545
        if ($object = $this->get_by_path($source)) {
546
            if ($object instanceof org_openpsa_documents_document_dba) {
547
                $object->topic = $target->id;
548
                $object->title = $name;
549
            } else {
550
                $object->up = $target->id;
551
                $object->extra = $name;
552
            }
553
            if ($object->update()) {
554
                midcom::get()->cache->invalidate($target->guid);
555
                return $source;
556
            }
557
        }
558
        return false;
559
    }
560
561
    /**
562
     * Remove file
563
     *
564
     * @param  string  $path  file path
565
     * @return bool
566
     */
567
    protected function _unlink($path)
568
    {
569
        try {
570
            $doc = new org_openpsa_documents_document_dba($path);
571
            return $doc->delete();
572
        } catch (midcom_error $e) {
573
            return false;
574
        }
575
    }
576
577
    /**
578
     * Remove dir
579
     *
580
     * @param  string  $path  dir path
581
     * @return bool
582
     */
583
    protected function _rmdir($path)
584
    {
585
        $dir = new org_openpsa_documents_directory($path);
586
        return $dir->delete();
587
    }
588
589
    /**
590
     * Create new file and write into it from file pointer.
591
     * Return new file path or false on error.
592
     *
593
     * @param  resource  $fp   file pointer
594
     * @param  string    $dir  target dir path
595
     * @param  string    $name file name
596
     * @param  array     $stat file stat (required by some virtual fs)
597
     * @return bool|string
598
     */
599
    protected function _save($fp, $dir, $name, $stat)
600
    {
601
        $doc = $this->create_document($dir, $name);
602
        if (!$doc) {
603
            return false;
604
        }
605
606
        if (!$this->create_attachment($doc, $name, $stat['mime'], $fp)) {
607
            return false;
608
        }
609
        return $doc->guid;
610
    }
611
612
    private function create_attachment(org_openpsa_documents_document_dba $doc, $name, $mimetype, $fp)
613
    {
614
        $filename = midcom_db_attachment::safe_filename($name, true);
615
        $att = $doc->create_attachment($filename, $name, $mimetype);
616
        if (   !$att
617
            || !$att->copy_from_handle($fp)) {
618
            return false;
619
        }
620
        $identifier = md5(time() . $name);
621
        return $att->set_parameter('midcom.helper.datamanager2.type.blobs', 'fieldname', 'document')
622
            && $att->set_parameter('midcom.helper.datamanager2.type.blobs', 'identifier', 'document')
623
            && $doc->set_parameter('midcom.helper.datamanager2.type.blobs', "guids_document", $identifier . ':' . $att->guid);
624
    }
625
626
    /**
627
     * Get file contents
628
     *
629
     * @param  string  $path  file path
630
     * @return string|false
631
     */
632
    protected function _getContents($path)
633
    {
634
        throw new midcom_error('_getContents not implemented');
635
    }
636
637
    /**
638
     * Write a string to a file
639
     *
640
     * @param  string  $path     file path
641
     * @param  string  $content  new file content
642
     * @return bool
643
     */
644
    protected function _filePutContents($path, $content)
645
    {
646
        throw new midcom_error('_filePutContents not implemented');
647
    }
648
649
    /**
650
     * Extract files from archive
651
     *
652
     * @param  string  $path file path
653
     * @param  array   $arc  archiver options
654
     * @return bool
655
     */
656
    protected function _extract($path, $arc)
657
    {
658
        throw new midcom_error('_extract not implemented');
659
    }
660
661
    /**
662
     * Create archive and return its path
663
     *
664
     * @param  string  $dir    target dir
665
     * @param  array   $files  files names list
666
     * @param  string  $name   archive name
667
     * @param  array   $arc    archiver options
668
     * @return string|bool
669
     */
670
    protected function _archive($dir, $files, $name, $arc)
671
    {
672
        throw new midcom_error('_archive not implemented');
673
    }
674
675
    /**
676
     * Detect available archivers
677
     *
678
     * @return void
679
     */
680
    protected function _checkArchivers()
681
    {
682
        return;
683
    }
684
685
    /**
686
     * Change file mode (chmod)
687
     *
688
     * @param  string  $path  file path
689
     * @param  string  $mode  octal string such as '0755'
690
     * @return bool
691
     */
692
    protected function _chmod($path, $mode)
693
    {
694
        throw new midcom_error('_chmod not implemented');
695
    }
696
}
697