elFinderVolumeOpenpsa::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 4
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
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
use midcom\datamanager\storage\blobs;
10
11
/**
12
 * elFinder driver
13
 *
14
 * @package org.openpsa.documents
15
 */
16
class elFinderVolumeOpenpsa extends elFinderVolumeDriver
17
{
18
    public function __construct()
19
    {
20
        // elfinder tmp detection doesn't work on OS X
21
        $this->tmp = midcom::get()->config->get('midcom_tempdir');
22
    }
23
24
    /**
25
     * Save uploaded file.
26
     * On success return array with new file stat and with removed file hash (if existed file was replaced)
27
     *
28
     * Copied from parent and slightly modified to support attachment versioning
29
     *
30
     * @param  Resource $fp      file pointer
31
     * @param  string   $dst     destination folder hash
32
     * @param  string   $name     file name
33
     * @param  string   $tmpname file tmp name - required to detect mime type
34
     * @return array|false
35
     * @author Dmitry (dio) Levashov
36
     **/
37
    public function upload($fp, $dst, $name, $tmpname, $hashes = [])
38
    {
39
        if ($this->commandDisabled('upload')) {
40
            return $this->setError(elFinder::ERROR_PERM_DENIED);
41
        }
42
43
        if (($dir = $this->dir($dst)) == false) {
44
            return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#' . $dst);
45
        }
46
47
        if (empty($dir['write'])) {
48
            return $this->setError(elFinder::ERROR_PERM_DENIED);
49
        }
50
51
        if (!$this->nameAccepted($name, false)) {
52
            return $this->setError(elFinder::ERROR_INVALID_NAME);
53
        }
54
55
        $mimeByName = '';
56
        if ($this->mimeDetect === 'internal') {
57
            $mime = $this->mimetype($tmpname, $name);
58
        } else {
59
            $mime = $this->mimetype($tmpname, $name);
60
            $mimeByName = $this->mimetype($name, true);
61
            if ($mime === 'unknown') {
62
                $mime = $mimeByName;
63
            }
64
        }
65
66
        if (!$this->allowPutMime($mime) || ($mimeByName && !$this->allowPutMime($mimeByName))) {
67
            return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, '(' . $mime . ')');
68
        }
69
70
        $tmpsize = (int)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
            $file = $this->stat($test);
79
        } else {
80
            $test = $this->joinPathCE($dstpath, $name);
81
            $file = $this->isNameExists($test);
82
        }
83
84
        $this->clearcache();
85
86
        if ($file && $file['name'] === $name) { // file exists and check filename for item ID based filesystem
87
            if ($this->uploadOverwrite) {
88
                if (!$file['write']) {
89
                    return $this->setError(elFinder::ERROR_PERM_DENIED);
90
                } elseif ($file['mime'] == 'directory') {
91
                    return $this->setError(elFinder::ERROR_NOT_REPLACE, $name);
92
                }
93
                $document = new org_openpsa_documents_document_dba($test);
94
                $document->backup_version();
95
                $attachments = blobs::get_attachments($document, 'document');
96
                foreach ($attachments as $att) {
97
                    if (!$att->delete()) {
98
                        return false;
99
                    }
100
                }
101
102
                if (!$this->create_attachment($document, $name, $mime, $fp)) {
103
                    return false;
104
                }
105
                //make sure metadata.revised changes
106
                $document->update();
107
108
                return $this->stat($document->guid);
109
            } else {
110
                $name = $this->uniqueName($dstpath, $name, '-', false);
111
            }
112
        }
113
114
        $stat = [
115
            'mime'   => $mime,
116
            'width'  => 0,
117
            'height' => 0,
118
            'size'   => $tmpsize];
119
120
        if (str_starts_with($mime, 'image') && ($s = getimagesize($tmpname))) {
121
            $stat['width'] = $s[0];
122
            $stat['height'] = $s[1];
123
        }
124
125
        if (($path = $this->saveCE($fp, $dstpath, $name, $stat)) == false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $path = $this->saveCE($f...$dstpath, $name, $stat) of type false|string against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
126
            return false;
127
        }
128
129
        $stat = $this->stat($path);
130
        // Try get URL
131
        if (empty($stat['url']) && ($url = $this->getContentUrl($stat['hash']))) {
132
            $stat['url'] = $url;
133
        }
134
135
        return $stat;
136
    }
137
138
    private function get_by_path(string $path) : ?midcom_core_dbaobject
139
    {
140
        try {
141
            return org_openpsa_documents_document_dba::get_cached($path);
142
        } catch (midcom_error $e) {
143
            $e->log();
144
            try {
145
                return org_openpsa_documents_directory::get_cached($path);
146
            } catch (midcom_error $e) {
147
                $e->log();
148
            }
149
        }
150
        return null;
151
    }
152
153
    /**
154
     * Return parent directory path
155
     *
156
     * @param  string  $path  file path
157
     * @return string
158
     */
159
    protected function _dirname($path)
160
    {
161
        if ($object = $this->get_by_path($path)) {
162
            return $object->get_parent()->guid;
163
        }
164
        return '';
165
    }
166
167
    /**
168
     * Return file name
169
     *
170
     * @param  string  $path  file path
171
     * @return string
172
     */
173
    protected function _basename($path)
174
    {
175
        if ($object = $this->get_by_path($path)) {
176
            return $object->get_label();
0 ignored issues
show
Bug introduced by
The method get_label() does not exist on midcom_core_dbaobject. It seems like you code against a sub-type of midcom_core_dbaobject such as org_openpsa_calendar_event_dba or org_openpsa_invoices_invoice_dba or net_nemein_tag_tag_dba or org_openpsa_invoices_invoice_item_dba or midcom_db_parameter or org_openpsa_calendar_event_member_dba or org_openpsa_sales_salesproject_offer_dba or midcom_db_topic or net_nemein_tag_link_dba or org_openpsa_invoices_billing_data_dba or org_openpsa_directmarketing_campaign_member_dba or org_openpsa_contacts_group_dba or midcom_db_person or midcom_db_member or org_openpsa_projects_project or org_openpsa_calendar_event_resource_dba or midcom_db_group or org_openpsa_projects_task_dba or org_openpsa_documents_document_dba. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

176
            return $object->/** @scrutinizer ignore-call */ get_label();
Loading history...
177
        }
178
        return '';
179
    }
180
181
    /**
182
     * Join dir name and file name and return full path.
183
     * Some drivers (db) use int as path - so we give to concat path to driver itself
184
     *
185
     * @param  string  $dir   dir path
186
     * @param  string  $name  file name
187
     * @return string
188
     */
189
    protected function _joinPath($dir, $name)
190
    {
191
        $mc = org_openpsa_documents_document_dba::new_collector('title', $name);
192
        $mc->add_constraint('topic.guid', '=', $dir);
193
        if ($keys = $mc->list_keys()) {
194
            return key($keys);
195
        }
196
        $mc = org_openpsa_documents_directory::new_collector('extra', $name);
197
        $mc->add_constraint('up.guid', '=', $dir);
198
        if ($keys = $mc->list_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 === null) {
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 = blobs::get_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 child 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 = blobs::get_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(string $parentguid, string $title) : ?org_openpsa_documents_document_dba
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');
0 ignored issues
show
Documentation Bug introduced by
It seems like $dir->get_parameter('org...'orgOpenpsaAccesstype') can also be of type string. However, the property $orgOpenpsaAccesstype is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
474
475
        if ($document->create()) {
476
            return $document;
477
        }
478
        return null;
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->target = $target;
523
524
        if ($new_object = $copy->execute($source)) {
525
            return $new_object->guid;
526
        }
527
        debug_print_r('Copying failed with the following errors', $copy->errors, MIDCOM_LOG_ERROR);
528
        return false;
529
    }
530
531
    /**
532
     * Move file into another parent dir.
533
     * Return new file path or false.
534
     *
535
     * @param  string  $source     source file path
536
     * @param  string  $targetDir  target dir path
537
     * @param  string  $name       file name
538
     * @return string|bool
539
     */
540
    protected function _move($source, $targetDir, $name)
541
    {
542
        $target = org_openpsa_documents_directory::get_cached($targetDir);
543
        if ($object = $this->get_by_path($source)) {
544
            if ($object instanceof org_openpsa_documents_document_dba) {
545
                $object->topic = $target->id;
546
                $object->title = $name;
547
            } else {
548
                $object->up = $target->id;
0 ignored issues
show
Bug Best Practice introduced by
The property up does not exist on midcom_core_dbaobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
549
                $object->extra = $name;
0 ignored issues
show
Bug Best Practice introduced by
The property extra does not exist on midcom_core_dbaobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
550
            }
551
            if ($object->update()) {
552
                midcom::get()->cache->invalidate($target->guid);
553
                return $source;
554
            }
555
        }
556
        return false;
557
    }
558
559
    /**
560
     * Remove file
561
     *
562
     * @param  string  $path  file path
563
     * @return bool
564
     */
565
    protected function _unlink($path)
566
    {
567
        try {
568
            $doc = new org_openpsa_documents_document_dba($path);
569
            return $doc->delete();
570
        } catch (midcom_error) {
571
            return false;
572
        }
573
    }
574
575
    /**
576
     * Remove dir
577
     *
578
     * @param  string  $path  dir path
579
     * @return bool
580
     */
581
    protected function _rmdir($path)
582
    {
583
        $dir = new org_openpsa_documents_directory($path);
584
        return $dir->delete();
585
    }
586
587
    /**
588
     * Create new file and write into it from file pointer.
589
     * Return new file path or false on error.
590
     *
591
     * @param  resource  $fp   file pointer
592
     * @param  string    $dir  target dir path
593
     * @param  string    $name file name
594
     * @param  array     $stat file stat (required by some virtual fs)
595
     * @return bool|string
596
     */
597
    protected function _save($fp, $dir, $name, $stat)
598
    {
599
        $doc = $this->create_document($dir, $name);
600
        if (!$doc) {
601
            return false;
602
        }
603
604
        if (!$this->create_attachment($doc, $name, $stat['mime'], $fp)) {
605
            return false;
606
        }
607
        return $doc->guid;
608
    }
609
610
    private function create_attachment(org_openpsa_documents_document_dba $doc, string $name, string $mimetype, $fp) : bool
611
    {
612
        $filename = midcom_db_attachment::safe_filename($name);
613
        $att = $doc->create_attachment($filename, $name, $mimetype);
614
        if (   !$att
615
            || !$att->copy_from_handle($fp)) {
616
            return false;
617
        }
618
        $identifier = md5(time() . $name);
619
        return $att->set_parameter('midcom.helper.datamanager2.type.blobs', 'fieldname', 'document')
620
            && $att->set_parameter('midcom.helper.datamanager2.type.blobs', 'identifier', 'document')
621
            && $doc->set_parameter('midcom.helper.datamanager2.type.blobs', "guids_document", $identifier . ':' . $att->guid);
622
    }
623
624
    /**
625
     * Get file contents
626
     *
627
     * @param  string  $path  file path
628
     * @return string|false
629
     */
630
    protected function _getContents($path)
631
    {
632
        throw new midcom_error('_getContents not implemented');
633
    }
634
635
    /**
636
     * Write a string to a file
637
     *
638
     * @param  string  $path     file path
639
     * @param  string  $content  new file content
640
     * @return bool
641
     */
642
    protected function _filePutContents($path, $content)
643
    {
644
        throw new midcom_error('_filePutContents not implemented');
645
    }
646
647
    /**
648
     * Extract files from archive
649
     *
650
     * @param  string  $path file path
651
     * @param  array   $arc  archiver options
652
     * @return bool
653
     */
654
    protected function _extract($path, $arc)
655
    {
656
        throw new midcom_error('_extract not implemented');
657
    }
658
659
    /**
660
     * Create archive and return its path
661
     *
662
     * @param  string  $dir    target dir
663
     * @param  array   $files  files names list
664
     * @param  string  $name   archive name
665
     * @param  array   $arc    archiver options
666
     * @return string|bool
667
     */
668
    protected function _archive($dir, $files, $name, $arc)
669
    {
670
        throw new midcom_error('_archive not implemented');
671
    }
672
673
    /**
674
     * Detect available archivers
675
     *
676
     * @return void
677
     */
678
    protected function _checkArchivers()
679
    {
680
    }
681
682
    /**
683
     * Change file mode (chmod)
684
     *
685
     * @param  string  $path  file path
686
     * @param  string  $mode  octal string such as '0755'
687
     * @return bool
688
     */
689
    protected function _chmod($path, $mode)
690
    {
691
        throw new midcom_error('_chmod not implemented');
692
    }
693
}
694