recca0120 /
laravel-elfinder
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Base class for elFinder volume. |
||
| 4 | * Provide 2 layers: |
||
| 5 | * 1. Public API (commands) |
||
| 6 | * 2. abstract fs API. |
||
| 7 | * |
||
| 8 | * All abstract methods begin with "_" |
||
| 9 | * |
||
| 10 | * @author Dmitry (dio) Levashov |
||
| 11 | * @author Troex Nevelin |
||
| 12 | * @author Alexey Sukhotin |
||
| 13 | **/ |
||
| 14 | abstract class elFinderVolumeDriver |
||
|
0 ignored issues
–
show
|
|||
| 15 | { |
||
| 16 | /** |
||
| 17 | * Net mount key. |
||
| 18 | * |
||
| 19 | * @var string |
||
| 20 | **/ |
||
| 21 | public $netMountKey = ''; |
||
| 22 | |||
| 23 | /** |
||
| 24 | * Request args |
||
| 25 | * $_POST or $_GET values. |
||
| 26 | * |
||
| 27 | * @var array |
||
| 28 | */ |
||
| 29 | protected $ARGS = []; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * Driver id |
||
| 33 | * Must be started from letter and contains [a-z0-9] |
||
| 34 | * Used as part of volume id. |
||
| 35 | * |
||
| 36 | * @var string |
||
| 37 | **/ |
||
| 38 | protected $driverId = 'a'; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * Volume id - used as prefix for files hashes. |
||
| 42 | * |
||
| 43 | * @var string |
||
| 44 | **/ |
||
| 45 | protected $id = ''; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * Flag - volume "mounted" and available. |
||
| 49 | * |
||
| 50 | * @var bool |
||
| 51 | **/ |
||
| 52 | protected $mounted = false; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * Root directory path. |
||
| 56 | * |
||
| 57 | * @var string |
||
| 58 | **/ |
||
| 59 | protected $root = ''; |
||
| 60 | |||
| 61 | /** |
||
| 62 | * Root basename | alias. |
||
| 63 | * |
||
| 64 | * @var string |
||
| 65 | **/ |
||
| 66 | protected $rootName = ''; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * Default directory to open. |
||
| 70 | * |
||
| 71 | * @var string |
||
| 72 | **/ |
||
| 73 | protected $startPath = ''; |
||
| 74 | |||
| 75 | /** |
||
| 76 | * Base URL. |
||
| 77 | * |
||
| 78 | * @var string |
||
| 79 | **/ |
||
| 80 | protected $URL = ''; |
||
| 81 | |||
| 82 | /** |
||
| 83 | * A file save destination path when a temporary content URL is required |
||
| 84 | * on a network volume or the like |
||
| 85 | * If not specified, it tries to use "Connector Path/../files/.tmb". |
||
| 86 | * |
||
| 87 | * @var string |
||
| 88 | */ |
||
| 89 | protected $tmpLinkPath = ''; |
||
| 90 | |||
| 91 | /** |
||
| 92 | * A file save destination URL when a temporary content URL is required |
||
| 93 | * on a network volume or the like |
||
| 94 | * If not specified, it tries to use "Connector URL/../files/.tmb". |
||
| 95 | * |
||
| 96 | * @var string |
||
| 97 | */ |
||
| 98 | protected $tmpLinkUrl = ''; |
||
| 99 | |||
| 100 | /** |
||
| 101 | * Thumbnails dir path. |
||
| 102 | * |
||
| 103 | * @var string |
||
| 104 | **/ |
||
| 105 | protected $tmbPath = ''; |
||
| 106 | |||
| 107 | /** |
||
| 108 | * Is thumbnails dir writable. |
||
| 109 | * |
||
| 110 | * @var bool |
||
| 111 | **/ |
||
| 112 | protected $tmbPathWritable = false; |
||
| 113 | |||
| 114 | /** |
||
| 115 | * Thumbnails base URL. |
||
| 116 | * |
||
| 117 | * @var string |
||
| 118 | **/ |
||
| 119 | protected $tmbURL = ''; |
||
| 120 | |||
| 121 | /** |
||
| 122 | * Thumbnails size in px. |
||
| 123 | * |
||
| 124 | * @var int |
||
| 125 | **/ |
||
| 126 | protected $tmbSize = 48; |
||
| 127 | |||
| 128 | /** |
||
| 129 | * Image manipulation lib name |
||
| 130 | * auto|imagick|gd|convert. |
||
| 131 | * |
||
| 132 | * @var string |
||
| 133 | **/ |
||
| 134 | protected $imgLib = 'auto'; |
||
| 135 | |||
| 136 | /** |
||
| 137 | * Video to Image converter. |
||
| 138 | * |
||
| 139 | * @var array |
||
| 140 | */ |
||
| 141 | protected $imgConverter = []; |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Library to crypt files name. |
||
| 145 | * |
||
| 146 | * @var string |
||
| 147 | **/ |
||
| 148 | protected $cryptLib = ''; |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Archivers config. |
||
| 152 | * |
||
| 153 | * @var array |
||
| 154 | **/ |
||
| 155 | protected $archivers = [ |
||
| 156 | 'create' => [], |
||
| 157 | 'extract' => [], |
||
| 158 | ]; |
||
| 159 | |||
| 160 | /** |
||
| 161 | * Server character encoding. |
||
| 162 | * |
||
| 163 | * @var string or null |
||
| 164 | **/ |
||
| 165 | protected $encoding = null; |
||
| 166 | |||
| 167 | /** |
||
| 168 | * How many subdirs levels return for tree. |
||
| 169 | * |
||
| 170 | * @var int |
||
| 171 | **/ |
||
| 172 | protected $treeDeep = 1; |
||
| 173 | |||
| 174 | /** |
||
| 175 | * Errors from last failed action. |
||
| 176 | * |
||
| 177 | * @var array |
||
| 178 | **/ |
||
| 179 | protected $error = []; |
||
| 180 | |||
| 181 | /** |
||
| 182 | * Today 24:00 timestamp. |
||
| 183 | * |
||
| 184 | * @var int |
||
| 185 | **/ |
||
| 186 | protected $today = 0; |
||
| 187 | |||
| 188 | /** |
||
| 189 | * Yesterday 24:00 timestamp. |
||
| 190 | * |
||
| 191 | * @var int |
||
| 192 | **/ |
||
| 193 | protected $yesterday = 0; |
||
| 194 | |||
| 195 | /** |
||
| 196 | * Force make dirctory on extract. |
||
| 197 | * |
||
| 198 | * @var int |
||
| 199 | **/ |
||
| 200 | protected $extractToNewdir = 'auto'; |
||
| 201 | |||
| 202 | /** |
||
| 203 | * Object configuration. |
||
| 204 | * |
||
| 205 | * @var array |
||
| 206 | **/ |
||
| 207 | protected $options = [ |
||
| 208 | // Driver ID (Prefix of volume ID), Normally, the value specified for each volume driver is used. |
||
| 209 | 'driverId' => '', |
||
| 210 | // Id (Suffix of volume ID), Normally, the number incremented according to the specified number of volumes is used. |
||
| 211 | 'id' => '', |
||
| 212 | // revision id of root directory that uses for caching control of root stat |
||
| 213 | 'rootRev' => '', |
||
| 214 | // driver type it uses volume root's CSS class name. e.g. 'group' -> Adds 'elfinder-group' to CSS class name. |
||
| 215 | 'type' => '', |
||
| 216 | // root directory path |
||
| 217 | 'path' => '', |
||
| 218 | // Folder hash value on elFinder to be the parent of this volume |
||
| 219 | 'phash' => '', |
||
| 220 | // Folder hash value on elFinder to trash bin of this volume, it require 'copyJoin' to true |
||
| 221 | 'trashHash' => '', |
||
| 222 | // open this path on initial request instead of root path |
||
| 223 | 'startPath' => '', |
||
| 224 | // how many subdirs levels return per request |
||
| 225 | 'treeDeep' => 1, |
||
| 226 | // root url, not set to disable sending URL to client (replacement for old "fileURL" option) |
||
| 227 | 'URL' => '', |
||
| 228 | // directory link url to own manager url with folder hash (`true`, `false` or default `'auto'`: URL is empty then `true` else `false`) |
||
| 229 | 'dirUrlOwn' => 'auto', |
||
| 230 | // directory separator. required by client to show paths correctly |
||
| 231 | 'separator' => DIRECTORY_SEPARATOR, |
||
| 232 | // Server character encoding (default is '': UTF-8) |
||
| 233 | 'encoding' => '', |
||
| 234 | // for convert character encoding (default is '': Not change locale) |
||
| 235 | 'locale' => '', |
||
| 236 | // URL of volume icon (16x16 pixel image file) |
||
| 237 | 'icon' => '', |
||
| 238 | // CSS Class of volume root in tree |
||
| 239 | 'rootCssClass' => '', |
||
| 240 | // Items to disable session caching |
||
| 241 | 'noSessionCache' => [], |
||
| 242 | // enable i18n folder name that convert name to elFinderInstance.messages['folder_'+name] |
||
| 243 | 'i18nFolderName' => false, |
||
| 244 | // Search timeout (sec) |
||
| 245 | 'searchTimeout' => 30, |
||
| 246 | // Search exclusion directory regex pattern (require demiliter e.g. '#/path/to/exclude_directory#i') |
||
| 247 | 'searchExDirReg' => '', |
||
| 248 | // library to crypt/uncrypt files names (not implemented) |
||
| 249 | 'cryptLib' => '', |
||
| 250 | // how to detect files mimetypes. (auto/internal/finfo/mime_content_type) |
||
| 251 | 'mimeDetect' => 'auto', |
||
| 252 | // mime.types file path (for mimeDetect==internal) |
||
| 253 | 'mimefile' => '', |
||
| 254 | // Static extension/MIME of general server side scripts to security issues |
||
| 255 | 'staticMineMap' => [ |
||
| 256 | 'php:*' => 'text/x-php', |
||
| 257 | 'php3:*' => 'text/x-php', |
||
| 258 | 'php4:*' => 'text/x-php', |
||
| 259 | 'php5:*' => 'text/x-php', |
||
| 260 | 'phtml:*' => 'text/x-php', |
||
| 261 | 'cgi:*' => 'text/x-httpd-cgi', |
||
| 262 | 'pl:*' => 'text/x-perl', |
||
| 263 | 'asp:*' => 'text/x-asap', |
||
| 264 | 'aspx:*' => 'text/x-asap', |
||
| 265 | 'py:*' => 'text/x-python', |
||
| 266 | 'rb:*' => 'text/x-ruby', |
||
| 267 | 'jsp:*' => 'text/x-jsp', |
||
| 268 | ], |
||
| 269 | // mime type normalize map : Array '[ext]:[detected mime type]' => '[normalized mime]' |
||
| 270 | 'mimeMap' => [ |
||
| 271 | 'md:application/x-genesis-rom' => 'text/x-markdown', |
||
| 272 | 'md:text/plain' => 'text/x-markdown', |
||
| 273 | 'markdown:text/plain' => 'text/x-markdown', |
||
| 274 | 'css:text/x-asm' => 'text/css', |
||
| 275 | 'ico:image/vnd.microsoft.icon' => 'image/x-icon', |
||
| 276 | 'csv:text/plain' => 'text/csv', |
||
| 277 | 'm4a:video/mp4' => 'audio/mp4', |
||
| 278 | 'oga:application/ogg' => 'audio/ogg', |
||
| 279 | 'ogv:application/ogg' => 'video/ogg', |
||
| 280 | 'zip:application/x-zip' => 'application/zip', |
||
| 281 | ], |
||
| 282 | // An option to add MimeMap to the `mimeMap` option |
||
| 283 | // Array '[ext]:[detected mime type]' => '[normalized mime]' |
||
| 284 | 'additionalMimeMap' => [], |
||
| 285 | // MIME regex of send HTTP header "Content-Disposition: inline" or allow preview in quicklook |
||
| 286 | // '.' is allow inline of all of MIME types |
||
| 287 | // '$^' is not allow inline of all of MIME types |
||
| 288 | 'dispInlineRegex' => '^(?:(?:image|video|audio)|(?:text/plain|application/pdf)$)', |
||
| 289 | // temporary content URL's base path |
||
| 290 | 'tmpLinkPath' => '', |
||
| 291 | // temporary content URL's base URL |
||
| 292 | 'tmpLinkUrl' => '', |
||
| 293 | // directory for thumbnails |
||
| 294 | 'tmbPath' => '.tmb', |
||
| 295 | // mode to create thumbnails dir |
||
| 296 | 'tmbPathMode' => 0777, |
||
| 297 | // thumbnails dir URL. Set it if store thumbnails outside root directory |
||
| 298 | 'tmbURL' => '', |
||
| 299 | // thumbnails size (px) |
||
| 300 | 'tmbSize' => 48, |
||
| 301 | // thumbnails crop (true - crop, false - scale image to fit thumbnail size) |
||
| 302 | 'tmbCrop' => true, |
||
| 303 | // thumbnails background color (hex #rrggbb or 'transparent') |
||
| 304 | 'tmbBgColor' => 'transparent', |
||
| 305 | // image rotate fallback background color (hex #rrggbb) |
||
| 306 | 'bgColorFb' => '#ffffff', |
||
| 307 | // image manipulations library |
||
| 308 | 'imgLib' => 'auto', |
||
| 309 | // Fallback self image to thumbnail (nothing imgLib) |
||
| 310 | 'tmbFbSelf' => true, |
||
| 311 | // Video to Image converters ['TYPE or MIME' => ['func' => function($file){ /* Converts $file to Image */ return true; }, 'maxlen' => (int)TransferLength]] |
||
| 312 | 'imgConverter' => [], |
||
| 313 | // Max length of transfer to image converter |
||
| 314 | 'tmbVideoConvLen' => 10000000, |
||
| 315 | // Captre point seccond |
||
| 316 | 'tmbVideoConvSec' => 6, |
||
| 317 | // Resource path of fallback icon images defailt: php/resouces |
||
| 318 | 'resourcePath' => '', |
||
| 319 | // Jpeg image saveing quality |
||
| 320 | 'jpgQuality' => 100, |
||
| 321 | // on paste file - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext |
||
| 322 | 'copyOverwrite' => true, |
||
| 323 | // if true - join new and old directories content on paste |
||
| 324 | 'copyJoin' => true, |
||
| 325 | // on upload - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext |
||
| 326 | 'uploadOverwrite' => true, |
||
| 327 | // mimetypes allowed to upload |
||
| 328 | 'uploadAllow' => [], |
||
| 329 | // mimetypes not allowed to upload |
||
| 330 | 'uploadDeny' => [], |
||
| 331 | // order to proccess uploadAllow and uploadDeny options |
||
| 332 | 'uploadOrder' => ['deny', 'allow'], |
||
| 333 | // maximum upload file size. NOTE - this is size for every uploaded files |
||
| 334 | 'uploadMaxSize' => 0, |
||
| 335 | // maximum number of chunked upload connection. `-1` to disable chunked upload |
||
| 336 | 'uploadMaxConn' => 3, |
||
| 337 | // maximum get file size. NOTE - Maximum value is 50% of PHP memory_limit |
||
| 338 | 'getMaxSize' => 0, |
||
| 339 | // files dates format |
||
| 340 | 'dateFormat' => 'j M Y H:i', |
||
| 341 | // files time format |
||
| 342 | 'timeFormat' => 'H:i', |
||
| 343 | // if true - every folder will be check for children folders, -1 - every folder will be check asynchronously, false - all folders will be marked as having subfolders |
||
| 344 | 'checkSubfolders' => true, // true, false or -1 |
||
| 345 | // allow to copy from this volume to other ones? |
||
| 346 | 'copyFrom' => true, |
||
| 347 | // allow to copy from other volumes to this one? |
||
| 348 | 'copyTo' => true, |
||
| 349 | // cmd duplicate suffix format e.g. '_%s_' to without spaces |
||
| 350 | 'duplicateSuffix' => ' %s ', |
||
| 351 | // unique name numbar format e.g. '(%d)' to (1), (2)... |
||
| 352 | 'uniqueNumFormat' => '%d', |
||
| 353 | // list of commands disabled on this root |
||
| 354 | 'disabled' => [], |
||
| 355 | // enable file owner, group & mode info, `false` to inactivate "chmod" command. |
||
| 356 | 'statOwner' => false, |
||
| 357 | // allow exec chmod of read-only files |
||
| 358 | 'allowChmodReadOnly' => false, |
||
| 359 | // regexp or function name to validate new file name |
||
| 360 | 'acceptedName' => '/^[^\.].*/', // Notice: overwritten it in some volume drivers contractor |
||
| 361 | // regexp or function name to validate new directory name |
||
| 362 | 'acceptedDirname' => '', // used `acceptedName` if empty value |
||
| 363 | // function/class method to control files permissions |
||
| 364 | 'accessControl' => null, |
||
| 365 | // some data required by access control |
||
| 366 | 'accessControlData' => null, |
||
| 367 | // default permissions. |
||
| 368 | 'defaults' => [ |
||
| 369 | 'read' => true, |
||
| 370 | 'write' => true, |
||
| 371 | 'locked' => false, |
||
| 372 | 'hidden' => false, |
||
| 373 | ], |
||
| 374 | // files attributes |
||
| 375 | 'attributes' => [], |
||
| 376 | // max allowed archive files size (0 - no limit) |
||
| 377 | 'maxArcFilesSize' => 0, |
||
| 378 | // Allowed archive's mimetypes to create. Leave empty for all available types. |
||
| 379 | 'archiveMimes' => [], |
||
| 380 | // Manual config for archivers. See example below. Leave empty for auto detect |
||
| 381 | 'archivers' => [], |
||
| 382 | // plugin settings |
||
| 383 | 'plugin' => [], |
||
| 384 | // Is support parent directory time stamp update on add|remove|rename item |
||
| 385 | // Default `null` is auto detection that is LocalFileSystem, FTP or Dropbox are `true` |
||
| 386 | 'syncChkAsTs' => null, |
||
| 387 | // Long pooling sync checker function for syncChkAsTs is true |
||
| 388 | // Calls with args (TARGET DIRCTORY PATH, STAND-BY(sec), OLD TIMESTAMP, VOLUME DRIVER INSTANCE, ELFINDER INSTANCE) |
||
| 389 | // This function must return the following values. Changed: New Timestamp or Same: Old Timestamp or Error: false |
||
| 390 | // Default `null` is try use elFinderVolumeLocalFileSystem::localFileSystemInotify() on LocalFileSystem driver |
||
| 391 | // another driver use elFinder stat() checker |
||
| 392 | 'syncCheckFunc' => null, |
||
| 393 | // Long polling sync stand-by time (sec) |
||
| 394 | 'plStandby' => 30, |
||
| 395 | // Sleep time (sec) for elFinder stat() checker (syncChkAsTs is true) |
||
| 396 | 'tsPlSleep' => 10, |
||
| 397 | // Sleep time (sec) for elFinder ls() checker (syncChkAsTs is false) |
||
| 398 | 'lsPlSleep' => 30, |
||
| 399 | // Client side sync interval minimum (ms) |
||
| 400 | // Default `null` is auto set to ('tsPlSleep' or 'lsPlSleep') * 1000 |
||
| 401 | // `0` to disable auto sync |
||
| 402 | 'syncMinMs' => null, |
||
| 403 | // required to fix bug on macos |
||
| 404 | // However, we recommend to use the Normalizer plugin instead this option |
||
| 405 | 'utf8fix' => false, |
||
| 406 | // й ё Й Ё Ø Å |
||
| 407 | 'utf8patterns' => ["\u0438\u0306", "\u0435\u0308", "\u0418\u0306", "\u0415\u0308", "\u00d8A", "\u030a"], |
||
| 408 | 'utf8replace' => ["\u0439", "\u0451", "\u0419", "\u0401", "\u00d8", "\u00c5"], |
||
| 409 | ]; |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Defaults permissions. |
||
| 413 | * |
||
| 414 | * @var array |
||
| 415 | **/ |
||
| 416 | protected $defaults = [ |
||
| 417 | 'read' => true, |
||
| 418 | 'write' => true, |
||
| 419 | 'locked' => false, |
||
| 420 | 'hidden' => false, |
||
| 421 | ]; |
||
| 422 | |||
| 423 | /** |
||
| 424 | * Access control function/class. |
||
| 425 | * |
||
| 426 | * @var mixed |
||
| 427 | **/ |
||
| 428 | protected $attributes = []; |
||
| 429 | |||
| 430 | /** |
||
| 431 | * Access control function/class. |
||
| 432 | * |
||
| 433 | * @var mixed |
||
| 434 | **/ |
||
| 435 | protected $access = null; |
||
| 436 | |||
| 437 | /** |
||
| 438 | * Mime types allowed to upload. |
||
| 439 | * |
||
| 440 | * @var array |
||
| 441 | **/ |
||
| 442 | protected $uploadAllow = []; |
||
| 443 | |||
| 444 | /** |
||
| 445 | * Mime types denied to upload. |
||
| 446 | * |
||
| 447 | * @var array |
||
| 448 | **/ |
||
| 449 | protected $uploadDeny = []; |
||
| 450 | |||
| 451 | /** |
||
| 452 | * Order to validate uploadAllow and uploadDeny. |
||
| 453 | * |
||
| 454 | * @var array |
||
| 455 | **/ |
||
| 456 | protected $uploadOrder = []; |
||
| 457 | |||
| 458 | /** |
||
| 459 | * Maximum allowed upload file size. |
||
| 460 | * Set as number or string with unit - "10M", "500K", "1G". |
||
| 461 | * |
||
| 462 | * @var int|string |
||
| 463 | **/ |
||
| 464 | protected $uploadMaxSize = 0; |
||
| 465 | |||
| 466 | /** |
||
| 467 | * Run time setting of overwrite items on upload. |
||
| 468 | * |
||
| 469 | * @var string |
||
| 470 | */ |
||
| 471 | protected $uploadOverwrite = true; |
||
| 472 | |||
| 473 | /** |
||
| 474 | * Maximum allowed get file size. |
||
| 475 | * Set as number or string with unit - "10M", "500K", "1G". |
||
| 476 | * |
||
| 477 | * @var int|string |
||
| 478 | **/ |
||
| 479 | protected $getMaxSize = -1; |
||
| 480 | |||
| 481 | /** |
||
| 482 | * Mimetype detect method. |
||
| 483 | * |
||
| 484 | * @var string |
||
| 485 | **/ |
||
| 486 | protected $mimeDetect = 'auto'; |
||
| 487 | |||
| 488 | /** |
||
| 489 | * Finfo object for mimeDetect == 'finfo'. |
||
| 490 | * |
||
| 491 | * @var object |
||
| 492 | **/ |
||
| 493 | protected $finfo = null; |
||
| 494 | |||
| 495 | /** |
||
| 496 | * List of disabled client's commands. |
||
| 497 | * |
||
| 498 | * @var array |
||
| 499 | **/ |
||
| 500 | protected $disabled = []; |
||
| 501 | |||
| 502 | /** |
||
| 503 | * default extensions/mimetypes for mimeDetect == 'internal'. |
||
| 504 | * |
||
| 505 | * @var array |
||
| 506 | **/ |
||
| 507 | protected static $mimetypes = [ |
||
| 508 | // applications |
||
| 509 | 'ai' => 'application/postscript', |
||
| 510 | 'eps' => 'application/postscript', |
||
| 511 | 'exe' => 'application/x-executable', |
||
| 512 | 'doc' => 'application/msword', |
||
| 513 | 'dot' => 'application/msword', |
||
| 514 | 'xls' => 'application/vnd.ms-excel', |
||
| 515 | 'xlt' => 'application/vnd.ms-excel', |
||
| 516 | 'xla' => 'application/vnd.ms-excel', |
||
| 517 | 'ppt' => 'application/vnd.ms-powerpoint', |
||
| 518 | 'pps' => 'application/vnd.ms-powerpoint', |
||
| 519 | 'pdf' => 'application/pdf', |
||
| 520 | 'xml' => 'application/xml', |
||
| 521 | 'swf' => 'application/x-shockwave-flash', |
||
| 522 | 'torrent' => 'application/x-bittorrent', |
||
| 523 | 'jar' => 'application/x-jar', |
||
| 524 | // open office (finfo detect as application/zip) |
||
| 525 | 'odt' => 'application/vnd.oasis.opendocument.text', |
||
| 526 | 'ott' => 'application/vnd.oasis.opendocument.text-template', |
||
| 527 | 'oth' => 'application/vnd.oasis.opendocument.text-web', |
||
| 528 | 'odm' => 'application/vnd.oasis.opendocument.text-master', |
||
| 529 | 'odg' => 'application/vnd.oasis.opendocument.graphics', |
||
| 530 | 'otg' => 'application/vnd.oasis.opendocument.graphics-template', |
||
| 531 | 'odp' => 'application/vnd.oasis.opendocument.presentation', |
||
| 532 | 'otp' => 'application/vnd.oasis.opendocument.presentation-template', |
||
| 533 | 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', |
||
| 534 | 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', |
||
| 535 | 'odc' => 'application/vnd.oasis.opendocument.chart', |
||
| 536 | 'odf' => 'application/vnd.oasis.opendocument.formula', |
||
| 537 | 'odb' => 'application/vnd.oasis.opendocument.database', |
||
| 538 | 'odi' => 'application/vnd.oasis.opendocument.image', |
||
| 539 | 'oxt' => 'application/vnd.openofficeorg.extension', |
||
| 540 | // MS office 2007 (finfo detect as application/zip) |
||
| 541 | 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
||
| 542 | 'docm' => 'application/vnd.ms-word.document.macroEnabled.12', |
||
| 543 | 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', |
||
| 544 | 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', |
||
| 545 | 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', |
||
| 546 | 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', |
||
| 547 | 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', |
||
| 548 | 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', |
||
| 549 | 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', |
||
| 550 | 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', |
||
| 551 | 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', |
||
| 552 | 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', |
||
| 553 | 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', |
||
| 554 | 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', |
||
| 555 | 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', |
||
| 556 | 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', |
||
| 557 | 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', |
||
| 558 | 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', |
||
| 559 | 'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12', |
||
| 560 | // archives |
||
| 561 | 'gz' => 'application/x-gzip', |
||
| 562 | 'tgz' => 'application/x-gzip', |
||
| 563 | 'bz' => 'application/x-bzip2', |
||
| 564 | 'bz2' => 'application/x-bzip2', |
||
| 565 | 'tbz' => 'application/x-bzip2', |
||
| 566 | 'xz' => 'application/x-xz', |
||
| 567 | 'zip' => 'application/zip', |
||
| 568 | 'rar' => 'application/x-rar', |
||
| 569 | 'tar' => 'application/x-tar', |
||
| 570 | '7z' => 'application/x-7z-compressed', |
||
| 571 | // texts |
||
| 572 | 'txt' => 'text/plain', |
||
| 573 | 'php' => 'text/x-php', |
||
| 574 | 'html' => 'text/html', |
||
| 575 | 'htm' => 'text/html', |
||
| 576 | 'js' => 'text/javascript', |
||
| 577 | 'css' => 'text/css', |
||
| 578 | 'rtf' => 'text/rtf', |
||
| 579 | 'rtfd' => 'text/rtfd', |
||
| 580 | 'py' => 'text/x-python', |
||
| 581 | 'java' => 'text/x-java-source', |
||
| 582 | 'rb' => 'text/x-ruby', |
||
| 583 | 'sh' => 'text/x-shellscript', |
||
| 584 | 'pl' => 'text/x-perl', |
||
| 585 | //'xml' => 'text/xml', |
||
| 586 | 'sql' => 'text/x-sql', |
||
| 587 | 'c' => 'text/x-csrc', |
||
| 588 | 'h' => 'text/x-chdr', |
||
| 589 | 'cpp' => 'text/x-c++src', |
||
| 590 | 'hh' => 'text/x-c++hdr', |
||
| 591 | 'log' => 'text/plain', |
||
| 592 | 'csv' => 'text/csv', |
||
| 593 | 'md' => 'text/x-markdown', |
||
| 594 | 'markdown' => 'text/x-markdown', |
||
| 595 | // images |
||
| 596 | 'bmp' => 'image/x-ms-bmp', |
||
| 597 | 'jpg' => 'image/jpeg', |
||
| 598 | 'jpeg' => 'image/jpeg', |
||
| 599 | 'gif' => 'image/gif', |
||
| 600 | 'png' => 'image/png', |
||
| 601 | 'tif' => 'image/tiff', |
||
| 602 | 'tiff' => 'image/tiff', |
||
| 603 | 'tga' => 'image/x-targa', |
||
| 604 | 'psd' => 'image/vnd.adobe.photoshop', |
||
| 605 | //'ai' => 'image/vnd.adobe.photoshop', |
||
| 606 | 'xbm' => 'image/xbm', |
||
| 607 | 'pxm' => 'image/pxm', |
||
| 608 | //audio |
||
| 609 | 'mp3' => 'audio/mpeg', |
||
| 610 | 'mid' => 'audio/midi', |
||
| 611 | 'ogg' => 'audio/ogg', |
||
| 612 | 'oga' => 'audio/ogg', |
||
| 613 | 'm4a' => 'audio/mp4', |
||
| 614 | 'wav' => 'audio/wav', |
||
| 615 | 'wma' => 'audio/x-ms-wma', |
||
| 616 | // video |
||
| 617 | 'avi' => 'video/x-msvideo', |
||
| 618 | 'dv' => 'video/x-dv', |
||
| 619 | 'mp4' => 'video/mp4', |
||
| 620 | 'mpeg' => 'video/mpeg', |
||
| 621 | 'mpg' => 'video/mpeg', |
||
| 622 | 'mov' => 'video/quicktime', |
||
| 623 | 'wm' => 'video/x-ms-wmv', |
||
| 624 | 'flv' => 'video/x-flv', |
||
| 625 | 'mkv' => 'video/x-matroska', |
||
| 626 | 'webm' => 'video/webm', |
||
| 627 | 'ogv' => 'video/ogg', |
||
| 628 | 'ogm' => 'video/ogg', |
||
| 629 | ]; |
||
| 630 | |||
| 631 | /** |
||
| 632 | * Directory separator - required by client. |
||
| 633 | * |
||
| 634 | * @var string |
||
| 635 | **/ |
||
| 636 | protected $separator = DIRECTORY_SEPARATOR; |
||
| 637 | |||
| 638 | /** |
||
| 639 | * System Root path (Unix like: '/', Windows: '\', 'C:\' or 'D:\'...). |
||
| 640 | * |
||
| 641 | * @var string |
||
| 642 | **/ |
||
| 643 | protected $systemRoot = DIRECTORY_SEPARATOR; |
||
| 644 | |||
| 645 | /** |
||
| 646 | * Mimetypes allowed to display. |
||
| 647 | * |
||
| 648 | * @var array |
||
| 649 | **/ |
||
| 650 | protected $onlyMimes = []; |
||
| 651 | |||
| 652 | /** |
||
| 653 | * Store files moved or overwrited files info. |
||
| 654 | * |
||
| 655 | * @var array |
||
| 656 | **/ |
||
| 657 | protected $removed = []; |
||
| 658 | |||
| 659 | /** |
||
| 660 | * Store files added files info. |
||
| 661 | * |
||
| 662 | * @var array |
||
| 663 | **/ |
||
| 664 | protected $added = []; |
||
| 665 | |||
| 666 | /** |
||
| 667 | * Cache storage. |
||
| 668 | * |
||
| 669 | * @var array |
||
| 670 | **/ |
||
| 671 | protected $cache = []; |
||
| 672 | |||
| 673 | /** |
||
| 674 | * Cache by folders. |
||
| 675 | * |
||
| 676 | * @var array |
||
| 677 | **/ |
||
| 678 | protected $dirsCache = []; |
||
| 679 | |||
| 680 | /** |
||
| 681 | * You should use `$this->sessionCache['subdirs']` instead. |
||
| 682 | * |
||
| 683 | * @var array |
||
| 684 | * @deprecated |
||
| 685 | */ |
||
| 686 | protected $subdirsCache = []; |
||
| 687 | |||
| 688 | /** |
||
| 689 | * This volume session cache. |
||
| 690 | * |
||
| 691 | * @var array |
||
| 692 | */ |
||
| 693 | protected $sessionCache; |
||
| 694 | |||
| 695 | /** |
||
| 696 | * Session caching item list. |
||
| 697 | * |
||
| 698 | * @var array |
||
| 699 | */ |
||
| 700 | protected $sessionCaching = ['rootstat' => true, 'subdirs' => true]; |
||
| 701 | |||
| 702 | /** |
||
| 703 | * elFinder session wrapper object. |
||
| 704 | * |
||
| 705 | * @var elFinderSessionInterface |
||
| 706 | */ |
||
| 707 | protected $session; |
||
| 708 | |||
| 709 | /** |
||
| 710 | * Search start time. |
||
| 711 | * |
||
| 712 | * @var int |
||
| 713 | */ |
||
| 714 | protected $searchStart; |
||
| 715 | |||
| 716 | /** |
||
| 717 | * Current query word on doSearch. |
||
| 718 | * |
||
| 719 | * @var string |
||
| 720 | **/ |
||
| 721 | protected $doSearchCurrentQuery = []; |
||
| 722 | |||
| 723 | /** |
||
| 724 | * Is root modified (for clear root stat cache). |
||
| 725 | * |
||
| 726 | * @var bool |
||
| 727 | */ |
||
| 728 | protected $rootModified = false; |
||
| 729 | |||
| 730 | /** |
||
| 731 | * Is disable of command `url`. |
||
| 732 | * |
||
| 733 | * @var string |
||
| 734 | */ |
||
| 735 | protected $disabledGetUrl = false; |
||
| 736 | |||
| 737 | /** |
||
| 738 | * Accepted filename validator. |
||
| 739 | * |
||
| 740 | * @var string | callable |
||
| 741 | */ |
||
| 742 | protected $nameValidator; |
||
| 743 | |||
| 744 | /** |
||
| 745 | * Accepted dirname validator. |
||
| 746 | * |
||
| 747 | * @var string | callable |
||
| 748 | */ |
||
| 749 | protected $dirnameValidator; |
||
| 750 | |||
| 751 | /** |
||
| 752 | * Flag - mimetypes from externail file was loaded. |
||
| 753 | * |
||
| 754 | * @var bool |
||
| 755 | **/ |
||
| 756 | private static $mimetypesLoaded = false; |
||
| 757 | |||
| 758 | /*********************************************************************/ |
||
| 759 | /* PUBLIC API */ |
||
| 760 | /*********************************************************************/ |
||
| 761 | |||
| 762 | /** |
||
| 763 | * Return driver id. Used as a part of volume id. |
||
| 764 | * |
||
| 765 | * @return string |
||
| 766 | * @author Dmitry (dio) Levashov |
||
| 767 | **/ |
||
| 768 | public function driverId() |
||
| 769 | { |
||
| 770 | return $this->driverId; |
||
| 771 | } |
||
| 772 | |||
| 773 | /** |
||
| 774 | * Return volume id. |
||
| 775 | * |
||
| 776 | * @return string |
||
| 777 | * @author Dmitry (dio) Levashov |
||
| 778 | **/ |
||
| 779 | public function id() |
||
| 780 | { |
||
| 781 | return $this->id; |
||
| 782 | } |
||
| 783 | |||
| 784 | /** |
||
| 785 | * Assign elFinder session wrapper object. |
||
| 786 | * |
||
| 787 | * @param $session elFinderSessionInterface |
||
| 788 | */ |
||
| 789 | public function setSession($session) |
||
| 790 | { |
||
| 791 | $this->session = $session; |
||
| 792 | } |
||
| 793 | |||
| 794 | /** |
||
| 795 | * Save session cache data |
||
| 796 | * Calls this function before umount this volume on elFinder::exec(). |
||
| 797 | * |
||
| 798 | * @return void |
||
| 799 | */ |
||
| 800 | public function saveSessionCache() |
||
| 801 | { |
||
| 802 | $this->session->set($this->id, $this->sessionCache); |
||
| 803 | } |
||
| 804 | |||
| 805 | /** |
||
| 806 | * Return debug info for client. |
||
| 807 | * |
||
| 808 | * @return array |
||
| 809 | * @author Dmitry (dio) Levashov |
||
| 810 | **/ |
||
| 811 | public function debug() |
||
| 812 | { |
||
| 813 | return [ |
||
| 814 | 'id' => $this->id(), |
||
| 815 | 'name' => strtolower(substr(get_class($this), strlen('elfinderdriver'))), |
||
| 816 | 'mimeDetect' => $this->mimeDetect, |
||
| 817 | 'imgLib' => $this->imgLib, |
||
| 818 | ]; |
||
| 819 | } |
||
| 820 | |||
| 821 | /** |
||
| 822 | * chmod a file or folder. |
||
| 823 | * |
||
| 824 | * @param string $hash file or folder hash to chmod |
||
| 825 | * @param string $mode octal string representing new permissions |
||
| 826 | * @return array|false |
||
| 827 | * @author David Bartle |
||
| 828 | **/ |
||
| 829 | public function chmod($hash, $mode) |
||
| 830 | { |
||
| 831 | if ($this->commandDisabled('chmod')) { |
||
| 832 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 833 | } |
||
| 834 | |||
| 835 | if (! ($file = $this->file($hash))) { |
||
| 836 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 837 | } |
||
| 838 | |||
| 839 | View Code Duplication | if (! $this->options['allowChmodReadOnly']) { |
|
| 840 | if (! $this->attr($this->decode($hash), 'write', null, ($file['mime'] === 'directory'))) { |
||
| 841 | return $this->setError(elFinder::ERROR_PERM_DENIED, $file['name']); |
||
| 842 | } |
||
| 843 | } |
||
| 844 | |||
| 845 | $path = $this->decode($hash); |
||
| 846 | $write = $file['write']; |
||
| 847 | |||
| 848 | View Code Duplication | if ($this->convEncOut(! $this->_chmod($this->convEncIn($path), $mode))) { |
|
| 849 | return $this->setError(elFinder::ERROR_PERM_DENIED, $file['name']); |
||
| 850 | } |
||
| 851 | |||
| 852 | $this->clearcache(); |
||
| 853 | if ($path == $this->root) { |
||
| 854 | $this->rootModified = true; |
||
| 855 | } |
||
| 856 | |||
| 857 | if ($file = $this->stat($path)) { |
||
| 858 | $files = [$file]; |
||
| 859 | if ($file['mime'] === 'directory' && $write !== $file['write']) { |
||
| 860 | foreach ($this->getScandir($path) as $stat) { |
||
| 861 | if ($this->mimeAccepted($stat['mime'])) { |
||
| 862 | $files[] = $stat; |
||
| 863 | } |
||
| 864 | } |
||
| 865 | } |
||
| 866 | |||
| 867 | return $files; |
||
| 868 | } else { |
||
| 869 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 870 | } |
||
| 871 | } |
||
| 872 | |||
| 873 | /** |
||
| 874 | * stat a file or folder for elFinder cmd exec. |
||
| 875 | * |
||
| 876 | * @param string $hash file or folder hash to chmod |
||
| 877 | * @return array |
||
| 878 | * @author Naoki Sawada |
||
| 879 | **/ |
||
| 880 | public function fstat($hash) |
||
| 881 | { |
||
| 882 | $path = $this->decode($hash); |
||
| 883 | |||
| 884 | return $this->stat($path); |
||
| 885 | } |
||
| 886 | |||
| 887 | /** |
||
| 888 | * Clear PHP stat cache & all of inner stat caches. |
||
| 889 | */ |
||
| 890 | public function clearstatcache() |
||
| 891 | { |
||
| 892 | clearstatcache(); |
||
| 893 | $this->clearcache(); |
||
| 894 | } |
||
| 895 | |||
| 896 | /** |
||
| 897 | * Clear inner stat caches for target hash. |
||
| 898 | * |
||
| 899 | * @param string $hash |
||
| 900 | */ |
||
| 901 | public function clearcaches($hash = null) |
||
| 902 | { |
||
| 903 | if ($hash === null) { |
||
| 904 | $this->clearcache(); |
||
| 905 | } else { |
||
| 906 | $path = $this->decode($hash); |
||
| 907 | unset($this->cache[$path], $this->dirsCache[$path]); |
||
| 908 | } |
||
| 909 | } |
||
| 910 | |||
| 911 | /** |
||
| 912 | * "Mount" volume. |
||
| 913 | * Return true if volume available for read or write, |
||
| 914 | * false - otherwise. |
||
| 915 | * |
||
| 916 | * @param array $opts |
||
| 917 | * @return bool |
||
| 918 | * @author Dmitry (dio) Levashov |
||
| 919 | * @author Alexey Sukhotin |
||
| 920 | */ |
||
| 921 | public function mount(array $opts) |
||
| 922 | { |
||
| 923 | $this->options = array_merge($this->options, $opts); |
||
| 924 | |||
| 925 | View Code Duplication | if (! isset($this->options['path']) || $this->options['path'] === '') { |
|
| 926 | return $this->setError('Path undefined.'); |
||
| 927 | } |
||
| 928 | |||
| 929 | if (! $this->session) { |
||
| 930 | return $this->setError('Session wrapper dose not set. Need to `$volume->setSession(elFinderSessionInterface);` before mount.'); |
||
| 931 | } |
||
| 932 | if (! ($this->session instanceof elFinderSessionInterface)) { |
||
| 933 | return $this->setError('Session wrapper instance must be "elFinderSessionInterface".'); |
||
| 934 | } |
||
| 935 | |||
| 936 | // set driverId |
||
| 937 | if (! empty($this->options['driverId'])) { |
||
| 938 | $this->driverId = $this->options['driverId']; |
||
| 939 | } |
||
| 940 | |||
| 941 | $this->id = $this->driverId.(! empty($this->options['id']) ? $this->options['id'] : elFinder::$volumesCnt++).'_'; |
||
| 942 | $this->root = $this->normpathCE($this->options['path']); |
||
| 943 | $this->separator = isset($this->options['separator']) ? $this->options['separator'] : DIRECTORY_SEPARATOR; |
||
| 944 | $this->systemRoot = isset($this->options['systemRoot']) ? $this->options['systemRoot'] : $this->separator; |
||
| 945 | |||
| 946 | // set server encoding |
||
| 947 | if (! empty($this->options['encoding']) && strtoupper($this->options['encoding']) !== 'UTF-8') { |
||
| 948 | $this->encoding = $this->options['encoding']; |
||
| 949 | } else { |
||
| 950 | $this->encoding = null; |
||
| 951 | } |
||
| 952 | |||
| 953 | // set ARGS |
||
| 954 | $this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET; |
||
| 955 | |||
| 956 | $argInit = ! empty($this->ARGS['init']); |
||
| 957 | |||
| 958 | // session cache |
||
| 959 | if ($argInit) { |
||
| 960 | $this->session->set($this->id, []); |
||
| 961 | } |
||
| 962 | $this->sessionCache = $this->session->get($this->id, []); |
||
| 963 | |||
| 964 | // default file attribute |
||
| 965 | $this->defaults = [ |
||
| 966 | 'read' => isset($this->options['defaults']['read']) ? (bool) $this->options['defaults']['read'] : true, |
||
| 967 | 'write' => isset($this->options['defaults']['write']) ? (bool) $this->options['defaults']['write'] : true, |
||
| 968 | 'locked' => isset($this->options['defaults']['locked']) ? (bool) $this->options['defaults']['locked'] : false, |
||
| 969 | 'hidden' => isset($this->options['defaults']['hidden']) ? (bool) $this->options['defaults']['hidden'] : false, |
||
| 970 | ]; |
||
| 971 | |||
| 972 | // root attributes |
||
| 973 | $this->attributes[] = [ |
||
| 974 | 'pattern' => '~^'.preg_quote($this->separator).'$~', |
||
| 975 | 'locked' => true, |
||
| 976 | 'hidden' => false, |
||
| 977 | ]; |
||
| 978 | // set files attributes |
||
| 979 | View Code Duplication | if (! empty($this->options['attributes']) && is_array($this->options['attributes'])) { |
|
| 980 | foreach ($this->options['attributes'] as $a) { |
||
| 981 | // attributes must contain pattern and at least one rule |
||
| 982 | if (! empty($a['pattern']) || count($a) > 1) { |
||
| 983 | $this->attributes[] = $a; |
||
| 984 | } |
||
| 985 | } |
||
| 986 | } |
||
| 987 | |||
| 988 | if (! empty($this->options['accessControl']) && is_callable($this->options['accessControl'])) { |
||
| 989 | $this->access = $this->options['accessControl']; |
||
| 990 | } |
||
| 991 | |||
| 992 | $this->today = mktime(0, 0, 0, date('m'), date('d'), date('Y')); |
||
| 993 | $this->yesterday = $this->today - 86400; |
||
| 994 | |||
| 995 | if (! $this->init()) { |
||
| 996 | return false; |
||
| 997 | } |
||
| 998 | |||
| 999 | // check some options is arrays |
||
| 1000 | $this->uploadAllow = isset($this->options['uploadAllow']) && is_array($this->options['uploadAllow']) |
||
| 1001 | ? $this->options['uploadAllow'] |
||
| 1002 | : []; |
||
| 1003 | |||
| 1004 | $this->uploadDeny = isset($this->options['uploadDeny']) && is_array($this->options['uploadDeny']) |
||
| 1005 | ? $this->options['uploadDeny'] |
||
| 1006 | : []; |
||
| 1007 | |||
| 1008 | $this->options['uiCmdMap'] = (isset($this->options['uiCmdMap']) && is_array($this->options['uiCmdMap'])) |
||
| 1009 | ? $this->options['uiCmdMap'] |
||
| 1010 | : []; |
||
| 1011 | |||
| 1012 | if (is_string($this->options['uploadOrder'])) { // telephat_mode on, compatibility with 1.x |
||
| 1013 | $parts = explode(',', isset($this->options['uploadOrder']) ? $this->options['uploadOrder'] : 'deny,allow'); |
||
| 1014 | $this->uploadOrder = [trim($parts[0]), trim($parts[1])]; |
||
| 1015 | } else { // telephat_mode off |
||
| 1016 | $this->uploadOrder = ! empty($this->options['uploadOrder']) ? $this->options['uploadOrder'] : ['deny', 'allow']; |
||
| 1017 | } |
||
| 1018 | |||
| 1019 | if (! empty($this->options['uploadMaxSize'])) { |
||
| 1020 | $this->uploadMaxSize = elFinder::getIniBytes('', $this->options['uploadMaxSize']); |
||
| 1021 | } |
||
| 1022 | // Set maximum to PHP_INT_MAX |
||
| 1023 | if (! defined('PHP_INT_MAX')) { |
||
| 1024 | define('PHP_INT_MAX', 2147483647); |
||
| 1025 | } |
||
| 1026 | if ($this->uploadMaxSize < 1 || $this->uploadMaxSize > PHP_INT_MAX) { |
||
| 1027 | $this->uploadMaxSize = PHP_INT_MAX; |
||
| 1028 | } |
||
| 1029 | |||
| 1030 | // Set to get maximum size to 50% of memory_limit |
||
| 1031 | $memLimit = elFinder::getIniBytes('memory_limit') / 2; |
||
| 1032 | if ($memLimit > 0) { |
||
| 1033 | $this->getMaxSize = empty($this->options['getMaxSize']) ? $memLimit : min($memLimit, elFinder::getIniBytes('', $this->options['getMaxSize'])); |
||
| 1034 | } else { |
||
| 1035 | $this->getMaxSize = -1; |
||
| 1036 | } |
||
| 1037 | |||
| 1038 | $this->disabled = isset($this->options['disabled']) && is_array($this->options['disabled']) |
||
| 1039 | ? array_values(array_diff($this->options['disabled'], ['open'])) // 'open' is required |
||
| 1040 | : []; |
||
| 1041 | |||
| 1042 | $this->cryptLib = $this->options['cryptLib']; |
||
| 1043 | $this->mimeDetect = $this->options['mimeDetect']; |
||
| 1044 | |||
| 1045 | // find available mimetype detect method |
||
| 1046 | $type = strtolower($this->options['mimeDetect']); |
||
| 1047 | $type = preg_match('/^(finfo|mime_content_type|internal|auto)$/i', $type) ? $type : 'auto'; |
||
| 1048 | $regexp = '/text\/x\-(php|c\+\+)/'; |
||
| 1049 | |||
| 1050 | if (($type == 'finfo' || $type == 'auto') |
||
| 1051 | && class_exists('finfo', false)) { |
||
| 1052 | $tmpFileInfo = explode(';', finfo_file(finfo_open(FILEINFO_MIME), __FILE__)); |
||
| 1053 | } else { |
||
| 1054 | $tmpFileInfo = false; |
||
| 1055 | } |
||
| 1056 | |||
| 1057 | $type = 'internal'; |
||
| 1058 | if ($tmpFileInfo && preg_match($regexp, array_shift($tmpFileInfo))) { |
||
| 1059 | $type = 'finfo'; |
||
| 1060 | $this->finfo = finfo_open(FILEINFO_MIME); |
||
| 1061 | } elseif (($type == 'mime_content_type' || $type == 'auto') && function_exists('mime_content_type')) { |
||
| 1062 | $_mimetypes = explode(';', mime_content_type(__FILE__)); |
||
| 1063 | if (preg_match($regexp, array_shift($_mimetypes))) { |
||
| 1064 | $type = 'mime_content_type'; |
||
| 1065 | } |
||
| 1066 | } |
||
| 1067 | $this->mimeDetect = $type; |
||
| 1068 | |||
| 1069 | // load mimes from external file for mimeDetect == 'internal' |
||
| 1070 | // based on Alexey Sukhotin idea and patch: http://elrte.org/redmine/issues/163 |
||
| 1071 | // file must be in file directory or in parent one |
||
| 1072 | if ($this->mimeDetect == 'internal' && ! self::$mimetypesLoaded) { |
||
| 1073 | self::$mimetypesLoaded = true; |
||
| 1074 | $this->mimeDetect = 'internal'; |
||
| 1075 | $file = false; |
||
| 1076 | if (! empty($this->options['mimefile']) && file_exists($this->options['mimefile'])) { |
||
| 1077 | $file = $this->options['mimefile']; |
||
| 1078 | } elseif (elFinder::$defaultMimefile && file_exists(elFinder::$defaultMimefile)) { |
||
| 1079 | $file = elFinder::$defaultMimefile; |
||
| 1080 | } elseif (file_exists(dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types')) { |
||
| 1081 | $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types'; |
||
| 1082 | } elseif (file_exists(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types')) { |
||
| 1083 | $file = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'mime.types'; |
||
| 1084 | } |
||
| 1085 | |||
| 1086 | View Code Duplication | if ($file && file_exists($file)) { |
|
| 1087 | $mimecf = file($file); |
||
| 1088 | |||
| 1089 | foreach ($mimecf as $line_num => $line) { |
||
| 1090 | if (! preg_match('/^\s*#/', $line)) { |
||
| 1091 | $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY); |
||
| 1092 | for ($i = 1, $size = count($mime); $i < $size; $i++) { |
||
| 1093 | if (! isset(self::$mimetypes[$mime[$i]])) { |
||
| 1094 | self::$mimetypes[$mime[$i]] = $mime[0]; |
||
| 1095 | } |
||
| 1096 | } |
||
| 1097 | } |
||
| 1098 | } |
||
| 1099 | } |
||
| 1100 | } |
||
| 1101 | |||
| 1102 | $this->rootName = empty($this->options['alias']) ? $this->basenameCE($this->root) : $this->options['alias']; |
||
| 1103 | |||
| 1104 | // This get's triggered if $this->root == '/' and alias is empty. |
||
| 1105 | // Maybe modify _basename instead? |
||
| 1106 | if ($this->rootName === '') { |
||
| 1107 | $this->rootName = $this->separator; |
||
| 1108 | } |
||
| 1109 | |||
| 1110 | $root = $this->stat($this->root); |
||
| 1111 | |||
| 1112 | if (! $root) { |
||
| 1113 | return $this->setError('Root folder does not exist.'); |
||
| 1114 | } |
||
| 1115 | if (! $root['read'] && ! $root['write']) { |
||
| 1116 | return $this->setError('Root folder has not read and write permissions.'); |
||
| 1117 | } |
||
| 1118 | |||
| 1119 | if ($root['read']) { |
||
| 1120 | if ($argInit) { |
||
| 1121 | // check startPath - path to open by default instead of root |
||
| 1122 | $startPath = $this->options['startPath'] ? $this->normpathCE($this->options['startPath']) : ''; |
||
| 1123 | if ($startPath) { |
||
| 1124 | $start = $this->stat($startPath); |
||
| 1125 | if (! empty($start) |
||
| 1126 | && $start['mime'] == 'directory' |
||
| 1127 | && $start['read'] |
||
| 1128 | && empty($start['hidden']) |
||
| 1129 | && $this->inpathCE($startPath, $this->root)) { |
||
| 1130 | $this->startPath = $startPath; |
||
| 1131 | if (substr($this->startPath, -1, 1) == $this->options['separator']) { |
||
| 1132 | $this->startPath = substr($this->startPath, 0, -1); |
||
| 1133 | } |
||
| 1134 | } |
||
| 1135 | } |
||
| 1136 | } |
||
| 1137 | } else { |
||
| 1138 | $this->options['URL'] = ''; |
||
| 1139 | $this->options['tmbURL'] = ''; |
||
| 1140 | $this->options['tmbPath'] = ''; |
||
| 1141 | // read only volume |
||
| 1142 | array_unshift($this->attributes, [ |
||
| 1143 | 'pattern' => '/.*/', |
||
| 1144 | 'read' => false, |
||
| 1145 | ]); |
||
| 1146 | } |
||
| 1147 | $this->treeDeep = $this->options['treeDeep'] > 0 ? (int) $this->options['treeDeep'] : 1; |
||
| 1148 | $this->tmbSize = $this->options['tmbSize'] > 0 ? (int) $this->options['tmbSize'] : 48; |
||
| 1149 | $this->URL = $this->options['URL']; |
||
| 1150 | if ($this->URL && preg_match('|[^/?&=]$|', $this->URL)) { |
||
| 1151 | $this->URL .= '/'; |
||
| 1152 | } |
||
| 1153 | if (strtolower($this->options['dirUrlOwn']) === 'auto') { |
||
| 1154 | $this->options['dirUrlOwn'] = $this->URL ? false : true; |
||
| 1155 | } else { |
||
| 1156 | $this->options['dirUrlOwn'] = (bool) $this->options['dirUrlOwn']; |
||
| 1157 | } |
||
| 1158 | |||
| 1159 | $this->tmbURL = ! empty($this->options['tmbURL']) ? $this->options['tmbURL'] : ''; |
||
| 1160 | if ($this->tmbURL && $this->tmbURL !== 'self' && preg_match('|[^/?&=]$|', $this->tmbURL)) { |
||
| 1161 | $this->tmbURL .= '/'; |
||
| 1162 | } |
||
| 1163 | |||
| 1164 | $this->nameValidator = ! empty($this->options['acceptedName']) && (is_string($this->options['acceptedName']) || is_callable($this->options['acceptedName'])) |
||
| 1165 | ? $this->options['acceptedName'] |
||
| 1166 | : ''; |
||
| 1167 | |||
| 1168 | $this->dirnameValidator = ! empty($this->options['acceptedDirname']) && (is_callable($this->options['acceptedDirname']) || (is_string($this->options['acceptedDirname']) && preg_match($this->options['acceptedDirname'], '') !== false)) |
||
| 1169 | ? $this->options['acceptedDirname'] |
||
| 1170 | : $this->nameValidator; |
||
| 1171 | |||
| 1172 | $this->_checkArchivers(); |
||
| 1173 | // manual control archive types to create |
||
| 1174 | View Code Duplication | if (! empty($this->options['archiveMimes']) && is_array($this->options['archiveMimes'])) { |
|
| 1175 | foreach ($this->archivers['create'] as $mime => $v) { |
||
| 1176 | if (! in_array($mime, $this->options['archiveMimes'])) { |
||
| 1177 | unset($this->archivers['create'][$mime]); |
||
| 1178 | } |
||
| 1179 | } |
||
| 1180 | } |
||
| 1181 | |||
| 1182 | // manualy add archivers |
||
| 1183 | View Code Duplication | if (! empty($this->options['archivers']['create']) && is_array($this->options['archivers']['create'])) { |
|
| 1184 | foreach ($this->options['archivers']['create'] as $mime => $conf) { |
||
| 1185 | if (strpos($mime, 'application/') === 0 |
||
| 1186 | && ! empty($conf['cmd']) |
||
| 1187 | && isset($conf['argc']) |
||
| 1188 | && ! empty($conf['ext']) |
||
| 1189 | && ! isset($this->archivers['create'][$mime])) { |
||
| 1190 | $this->archivers['create'][$mime] = $conf; |
||
| 1191 | } |
||
| 1192 | } |
||
| 1193 | } |
||
| 1194 | |||
| 1195 | View Code Duplication | if (! empty($this->options['archivers']['extract']) && is_array($this->options['archivers']['extract'])) { |
|
| 1196 | foreach ($this->options['archivers']['extract'] as $mime => $conf) { |
||
| 1197 | if (strpos($mime, 'application/') === 0 |
||
| 1198 | && ! empty($conf['cmd']) |
||
| 1199 | && isset($conf['argc']) |
||
| 1200 | && ! empty($conf['ext']) |
||
| 1201 | && ! isset($this->archivers['extract'][$mime])) { |
||
| 1202 | $this->archivers['extract'][$mime] = $conf; |
||
| 1203 | } |
||
| 1204 | } |
||
| 1205 | } |
||
| 1206 | |||
| 1207 | if (! empty($this->options['noSessionCache']) && is_array($this->options['noSessionCache'])) { |
||
| 1208 | foreach ($this->options['noSessionCache'] as $_key) { |
||
| 1209 | $this->sessionCaching[$_key] = false; |
||
| 1210 | unset($this->sessionCache[$_key]); |
||
| 1211 | } |
||
| 1212 | } |
||
| 1213 | if ($this->sessionCaching['subdirs']) { |
||
| 1214 | if (! isset($this->sessionCache['subdirs'])) { |
||
| 1215 | $this->sessionCache['subdirs'] = []; |
||
| 1216 | } |
||
| 1217 | } |
||
| 1218 | |||
| 1219 | $this->configure(); |
||
| 1220 | |||
| 1221 | // Normarize disabled (array_merge`for type array of JSON) |
||
| 1222 | $this->disabled = array_values(array_unique($this->disabled)); |
||
| 1223 | |||
| 1224 | // fix sync interval |
||
| 1225 | View Code Duplication | if ($this->options['syncMinMs'] !== 0) { |
|
| 1226 | $this->options['syncMinMs'] = max($this->options[$this->options['syncChkAsTs'] ? 'tsPlSleep' : 'lsPlSleep'] * 1000, intval($this->options['syncMinMs'])); |
||
| 1227 | } |
||
| 1228 | |||
| 1229 | // ` copyJoin` is required for the trash function |
||
| 1230 | if ($this->options['trashHash'] && empty($this->options['copyJoin'])) { |
||
| 1231 | $this->options['trashHash'] = ''; |
||
| 1232 | } |
||
| 1233 | |||
| 1234 | // set tmpLinkPath |
||
| 1235 | if (elFinder::$tmpLinkPath && ! $this->options['tmpLinkPath']) { |
||
| 1236 | $this->options['tmpLinkPath'] = elFinder::$tmpLinkPath; |
||
| 1237 | } |
||
| 1238 | if ($this->options['tmpLinkPath'] && is_writable($this->options['tmpLinkPath'])) { |
||
| 1239 | $this->tmpLinkPath = realpath($this->options['tmpLinkPath']); |
||
| 1240 | } elseif (! $this->options['URL'] && is_writable('../files/.tmb')) { |
||
| 1241 | $this->tmpLinkPath = realpath('../files/.tmb'); |
||
| 1242 | $this->options['tmpLinkUrl'] = ''; |
||
| 1243 | if (! elFinder::$tmpLinkPath) { |
||
| 1244 | elFinder::$tmpLinkPath = $this->tmpLinkPath; |
||
| 1245 | elFinder::$tmpLinkUrl = ''; |
||
| 1246 | } |
||
| 1247 | } |
||
| 1248 | |||
| 1249 | // set tmpLinkUrl |
||
| 1250 | if (elFinder::$tmpLinkUrl && ! $this->options['tmpLinkUrl']) { |
||
| 1251 | $this->options['tmpLinkUrl'] = elFinder::$tmpLinkUrl; |
||
| 1252 | } |
||
| 1253 | if ($this->options['tmpLinkUrl']) { |
||
| 1254 | $this->tmpLinkUrl = $this->options['tmpLinkUrl']; |
||
| 1255 | } |
||
| 1256 | if ($this->tmpLinkPath && ! $this->tmpLinkUrl) { |
||
| 1257 | $cur = realpath('./'); |
||
| 1258 | $i = 0; |
||
| 1259 | while ($cur !== $this->systemRoot && strpos($this->tmpLinkPath, $cur) !== 0) { |
||
| 1260 | $i++; |
||
| 1261 | $cur = dirname($cur); |
||
| 1262 | } |
||
| 1263 | list($req) = explode('?', $_SERVER['REQUEST_URI']); |
||
| 1264 | $reqs = explode('/', dirname($req)); |
||
| 1265 | $uri = implode('/', array_slice($reqs, 0, count($reqs) - 1)).substr($this->tmpLinkPath, strlen($cur)); |
||
| 1266 | $https = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off'); |
||
| 1267 | $this->tmpLinkUrl = ($https ? 'https://' : 'http://') |
||
| 1268 | .$_SERVER['SERVER_NAME'] // host |
||
| 1269 | .(((! $https && $_SERVER['SERVER_PORT'] == 80) || ($https && $_SERVER['SERVER_PORT'] == 443)) ? '' : (':'.$_SERVER['SERVER_PORT'])) // port |
||
| 1270 | .$uri; |
||
| 1271 | if (! elFinder::$tmpLinkUrl) { |
||
| 1272 | elFinder::$tmpLinkUrl = $this->tmpLinkUrl; |
||
| 1273 | } |
||
| 1274 | } |
||
| 1275 | |||
| 1276 | // remove last '/' |
||
| 1277 | if ($this->tmpLinkPath) { |
||
| 1278 | $this->tmpLinkPath = rtrim($this->tmpLinkPath, '/'); |
||
| 1279 | } |
||
| 1280 | if ($this->tmpLinkUrl) { |
||
| 1281 | $this->tmpLinkUrl = rtrim($this->tmpLinkUrl, '/'); |
||
| 1282 | } |
||
| 1283 | |||
| 1284 | // to update options cache |
||
| 1285 | $this->updateCache($this->root, $root); |
||
| 1286 | |||
| 1287 | return $this->mounted = true; |
||
| 1288 | } |
||
| 1289 | |||
| 1290 | /** |
||
| 1291 | * Some "unmount" stuffs - may be required by virtual fs. |
||
| 1292 | * |
||
| 1293 | * @return void |
||
| 1294 | * @author Dmitry (dio) Levashov |
||
| 1295 | **/ |
||
| 1296 | public function umount() |
||
| 1297 | { |
||
| 1298 | } |
||
| 1299 | |||
| 1300 | /** |
||
| 1301 | * Remove session cache of this volume. |
||
| 1302 | */ |
||
| 1303 | public function clearSessionCache() |
||
| 1304 | { |
||
| 1305 | $this->sessionCache = []; |
||
| 1306 | } |
||
| 1307 | |||
| 1308 | /** |
||
| 1309 | * Return error message from last failed action. |
||
| 1310 | * |
||
| 1311 | * @return array |
||
| 1312 | * @author Dmitry (dio) Levashov |
||
| 1313 | **/ |
||
| 1314 | public function error() |
||
| 1315 | { |
||
| 1316 | return $this->error; |
||
| 1317 | } |
||
| 1318 | |||
| 1319 | /** |
||
| 1320 | * Return is uploadable that given file name. |
||
| 1321 | * |
||
| 1322 | * @param string $name file name |
||
| 1323 | * @param bool $allowUnknown |
||
| 1324 | * @return bool |
||
| 1325 | * @author Naoki Sawada |
||
| 1326 | **/ |
||
| 1327 | public function isUploadableByName($name, $allowUnknown = false) |
||
| 1328 | { |
||
| 1329 | $mimeByName = $this->mimetype($name, true); |
||
| 1330 | |||
| 1331 | return ($allowUnknown && $mimeByName === 'unknown') || $this->allowPutMime($mimeByName); |
||
| 1332 | } |
||
| 1333 | |||
| 1334 | /** |
||
| 1335 | * Return Extention/MIME Table (elFinderVolumeDriver::$mimetypes). |
||
| 1336 | * |
||
| 1337 | * @return array |
||
| 1338 | * @author Naoki Sawada |
||
| 1339 | */ |
||
| 1340 | public function getMimeTable() |
||
| 1341 | { |
||
| 1342 | // load mime.types |
||
| 1343 | ! self::$mimetypesLoaded && self::mimetypeInternalDetect(); |
||
| 1344 | |||
| 1345 | return self::$mimetypes; |
||
| 1346 | } |
||
| 1347 | |||
| 1348 | /** |
||
| 1349 | * Return file extention detected by MIME type. |
||
| 1350 | * |
||
| 1351 | * @param string $mime MIME type |
||
| 1352 | * @param string $suffix Additional suffix |
||
| 1353 | * @return string |
||
| 1354 | * @author Naoki Sawada |
||
| 1355 | */ |
||
| 1356 | public function getExtentionByMime($mime, $suffix = '') |
||
| 1357 | { |
||
| 1358 | static $extTable = null; |
||
| 1359 | |||
| 1360 | if (is_null($extTable)) { |
||
| 1361 | $extTable = array_flip(array_unique($this->getMimeTable())); |
||
| 1362 | foreach (array_keys($this->options['mimeMap']) as $pair) { |
||
| 1363 | list($ext, $_mime) = explode(':', $pair); |
||
| 1364 | if ($_mime !== '*' && ! isset($extTable[$_mime])) { |
||
| 1365 | $extTable[$_mime] = $ext; |
||
| 1366 | } |
||
| 1367 | } |
||
| 1368 | } |
||
| 1369 | |||
| 1370 | if ($mime && isset($extTable[$mime])) { |
||
| 1371 | return $suffix ? ($extTable[$mime].$suffix) : $extTable[$mime]; |
||
| 1372 | } |
||
| 1373 | |||
| 1374 | return ''; |
||
| 1375 | } |
||
| 1376 | |||
| 1377 | /** |
||
| 1378 | * Set mimetypes allowed to display to client. |
||
| 1379 | * |
||
| 1380 | * @param array $mimes |
||
| 1381 | * @return void |
||
| 1382 | * @author Dmitry (dio) Levashov |
||
| 1383 | **/ |
||
| 1384 | public function setMimesFilter($mimes) |
||
| 1385 | { |
||
| 1386 | if (is_array($mimes)) { |
||
| 1387 | $this->onlyMimes = $mimes; |
||
| 1388 | } |
||
| 1389 | } |
||
| 1390 | |||
| 1391 | /** |
||
| 1392 | * Return root folder hash. |
||
| 1393 | * |
||
| 1394 | * @return string |
||
| 1395 | * @author Dmitry (dio) Levashov |
||
| 1396 | **/ |
||
| 1397 | public function root() |
||
| 1398 | { |
||
| 1399 | return $this->encode($this->root); |
||
| 1400 | } |
||
| 1401 | |||
| 1402 | /** |
||
| 1403 | * Return target path hash. |
||
| 1404 | * |
||
| 1405 | * @param string $path |
||
| 1406 | * @param string $name |
||
| 1407 | * @author Naoki Sawada |
||
| 1408 | * @return string |
||
| 1409 | */ |
||
| 1410 | public function getHash($path, $name = '') |
||
| 1411 | { |
||
| 1412 | if ($name !== '') { |
||
| 1413 | $path = $this->joinPathCE($path, $name); |
||
| 1414 | } |
||
| 1415 | |||
| 1416 | return $this->encode($path); |
||
| 1417 | } |
||
| 1418 | |||
| 1419 | /** |
||
| 1420 | * Return decoded path of target hash |
||
| 1421 | * This method do not check the stat of target |
||
| 1422 | * Use method `realpath()` to do check of the stat of target. |
||
| 1423 | * |
||
| 1424 | * @param string $hash |
||
| 1425 | * @author Naoki Sawada |
||
| 1426 | * @return string |
||
| 1427 | */ |
||
| 1428 | public function getPath($hash) |
||
| 1429 | { |
||
| 1430 | return $this->decode($hash); |
||
| 1431 | } |
||
| 1432 | |||
| 1433 | /** |
||
| 1434 | * Return root or startPath hash. |
||
| 1435 | * |
||
| 1436 | * @return string |
||
| 1437 | * @author Dmitry (dio) Levashov |
||
| 1438 | **/ |
||
| 1439 | public function defaultPath() |
||
| 1440 | { |
||
| 1441 | return $this->encode($this->startPath ? $this->startPath : $this->root); |
||
| 1442 | } |
||
| 1443 | |||
| 1444 | /** |
||
| 1445 | * Return volume options required by client:. |
||
| 1446 | * |
||
| 1447 | * @param $hash |
||
| 1448 | * @return array |
||
| 1449 | * @author Dmitry (dio) Levashov |
||
| 1450 | */ |
||
| 1451 | public function options($hash) |
||
| 1452 | { |
||
| 1453 | $create = $createext = []; |
||
| 1454 | if (isset($this->archivers['create']) && is_array($this->archivers['create'])) { |
||
| 1455 | foreach ($this->archivers['create'] as $m => $v) { |
||
| 1456 | $create[] = $m; |
||
| 1457 | $createext[$m] = $v['ext']; |
||
| 1458 | } |
||
| 1459 | } |
||
| 1460 | $opts = [ |
||
| 1461 | 'path' => $hash ? $this->path($hash) : '', |
||
| 1462 | 'url' => $this->URL, |
||
| 1463 | 'tmbUrl' => (! $this->imgLib && $this->options['tmbFbSelf']) ? 'self' : $this->tmbURL, |
||
| 1464 | 'disabled' => $this->disabled, |
||
| 1465 | 'separator' => $this->separator, |
||
| 1466 | 'copyOverwrite' => intval($this->options['copyOverwrite']), |
||
| 1467 | 'uploadOverwrite' => intval($this->options['uploadOverwrite']), |
||
| 1468 | 'uploadMaxSize' => intval($this->uploadMaxSize), |
||
| 1469 | 'uploadMaxConn' => intval($this->options['uploadMaxConn']), |
||
| 1470 | 'uploadMime' => [ |
||
| 1471 | 'firstOrder' => isset($this->uploadOrder[0]) ? $this->uploadOrder[0] : 'deny', |
||
| 1472 | 'allow' => $this->uploadAllow, |
||
| 1473 | 'deny' => $this->uploadDeny, |
||
| 1474 | ], |
||
| 1475 | 'dispInlineRegex' => $this->options['dispInlineRegex'], |
||
| 1476 | 'jpgQuality' => intval($this->options['jpgQuality']), |
||
| 1477 | 'archivers' => [ |
||
| 1478 | 'create' => $create, |
||
| 1479 | 'extract' => isset($this->archivers['extract']) && is_array($this->archivers['extract']) ? array_keys($this->archivers['extract']) : [], |
||
| 1480 | 'createext' => $createext, |
||
| 1481 | ], |
||
| 1482 | 'uiCmdMap' => (isset($this->options['uiCmdMap']) && is_array($this->options['uiCmdMap'])) ? $this->options['uiCmdMap'] : [], |
||
| 1483 | 'syncChkAsTs' => intval($this->options['syncChkAsTs']), |
||
| 1484 | 'syncMinMs' => intval($this->options['syncMinMs']), |
||
| 1485 | 'i18nFolderName' => intval($this->options['i18nFolderName']), |
||
| 1486 | 'tmbCrop' => intval($this->options['tmbCrop']), |
||
| 1487 | ]; |
||
| 1488 | if (! empty($this->options['trashHash'])) { |
||
| 1489 | $opts['trashHash'] = $this->options['trashHash']; |
||
| 1490 | } |
||
| 1491 | if ($hash === null) { |
||
| 1492 | // call from getRootStatExtra() |
||
| 1493 | if (! empty($this->options['icon'])) { |
||
| 1494 | $opts['icon'] = $this->options['icon']; |
||
| 1495 | } |
||
| 1496 | if (! empty($this->options['rootCssClass'])) { |
||
| 1497 | $opts['csscls'] = $this->options['rootCssClass']; |
||
| 1498 | } |
||
| 1499 | if (isset($this->options['netkey'])) { |
||
| 1500 | $opts['netkey'] = $this->options['netkey']; |
||
| 1501 | } |
||
| 1502 | } |
||
| 1503 | |||
| 1504 | return $opts; |
||
| 1505 | } |
||
| 1506 | |||
| 1507 | /** |
||
| 1508 | * Get option value of this volume. |
||
| 1509 | * |
||
| 1510 | * @param string $name target option name |
||
| 1511 | * @return null|mixed target option value |
||
| 1512 | * @author Naoki Sawada |
||
| 1513 | */ |
||
| 1514 | public function getOption($name) |
||
| 1515 | { |
||
| 1516 | return isset($this->options[$name]) ? $this->options[$name] : null; |
||
| 1517 | } |
||
| 1518 | |||
| 1519 | /** |
||
| 1520 | * Get plugin values of this options. |
||
| 1521 | * |
||
| 1522 | * @param string $name Plugin name |
||
| 1523 | * @return null|array Plugin values |
||
| 1524 | * @author Naoki Sawada |
||
| 1525 | */ |
||
| 1526 | public function getOptionsPlugin($name = '') |
||
| 1527 | { |
||
| 1528 | if ($name) { |
||
| 1529 | return isset($this->options['plugin'][$name]) ? $this->options['plugin'][$name] : []; |
||
| 1530 | } else { |
||
| 1531 | return $this->options['plugin']; |
||
| 1532 | } |
||
| 1533 | } |
||
| 1534 | |||
| 1535 | /** |
||
| 1536 | * Return true if command disabled in options. |
||
| 1537 | * |
||
| 1538 | * @param string $cmd command name |
||
| 1539 | * @return bool |
||
| 1540 | * @author Dmitry (dio) Levashov |
||
| 1541 | **/ |
||
| 1542 | public function commandDisabled($cmd) |
||
| 1543 | { |
||
| 1544 | return in_array($cmd, $this->disabled); |
||
| 1545 | } |
||
| 1546 | |||
| 1547 | /** |
||
| 1548 | * Return true if mime is required mimes list. |
||
| 1549 | * |
||
| 1550 | * @param string $mime mime type to check |
||
| 1551 | * @param array $mimes allowed mime types list or not set to use client mimes list |
||
| 1552 | * @param bool|null $empty what to return on empty list |
||
| 1553 | * @return bool|null |
||
| 1554 | * @author Dmitry (dio) Levashov |
||
| 1555 | * @author Troex Nevelin |
||
| 1556 | **/ |
||
| 1557 | public function mimeAccepted($mime, $mimes = null, $empty = true) |
||
| 1558 | { |
||
| 1559 | $mimes = is_array($mimes) ? $mimes : $this->onlyMimes; |
||
| 1560 | if (empty($mimes)) { |
||
| 1561 | return $empty; |
||
| 1562 | } |
||
| 1563 | |||
| 1564 | return $mime == 'directory' |
||
| 1565 | || in_array('all', $mimes) |
||
| 1566 | || in_array('All', $mimes) |
||
| 1567 | || in_array($mime, $mimes) |
||
| 1568 | || in_array(substr($mime, 0, strpos($mime, '/')), $mimes); |
||
| 1569 | } |
||
| 1570 | |||
| 1571 | /** |
||
| 1572 | * Return true if voume is readable. |
||
| 1573 | * |
||
| 1574 | * @return bool |
||
| 1575 | * @author Dmitry (dio) Levashov |
||
| 1576 | **/ |
||
| 1577 | public function isReadable() |
||
| 1578 | { |
||
| 1579 | $stat = $this->stat($this->root); |
||
| 1580 | |||
| 1581 | return $stat['read']; |
||
| 1582 | } |
||
| 1583 | |||
| 1584 | /** |
||
| 1585 | * Return true if copy from this volume allowed. |
||
| 1586 | * |
||
| 1587 | * @return bool |
||
| 1588 | * @author Dmitry (dio) Levashov |
||
| 1589 | **/ |
||
| 1590 | public function copyFromAllowed() |
||
| 1591 | { |
||
| 1592 | return (bool) $this->options['copyFrom']; |
||
| 1593 | } |
||
| 1594 | |||
| 1595 | /** |
||
| 1596 | * Return file path related to root with convert encoging. |
||
| 1597 | * |
||
| 1598 | * @param string $hash file hash |
||
| 1599 | * @return string |
||
| 1600 | * @author Dmitry (dio) Levashov |
||
| 1601 | **/ |
||
| 1602 | public function path($hash) |
||
| 1603 | { |
||
| 1604 | return $this->convEncOut($this->_path($this->convEncIn($this->decode($hash)))); |
||
| 1605 | } |
||
| 1606 | |||
| 1607 | /** |
||
| 1608 | * Return file real path if file exists. |
||
| 1609 | * |
||
| 1610 | * @param string $hash file hash |
||
| 1611 | * @return string | false |
||
| 1612 | * @author Dmitry (dio) Levashov |
||
| 1613 | **/ |
||
| 1614 | public function realpath($hash) |
||
| 1615 | { |
||
| 1616 | $path = $this->decode($hash); |
||
| 1617 | |||
| 1618 | return $this->stat($path) ? $path : false; |
||
| 1619 | } |
||
| 1620 | |||
| 1621 | /** |
||
| 1622 | * Return list of moved/overwrited files. |
||
| 1623 | * |
||
| 1624 | * @return array |
||
| 1625 | * @author Dmitry (dio) Levashov |
||
| 1626 | **/ |
||
| 1627 | public function removed() |
||
| 1628 | { |
||
| 1629 | if ($this->removed) { |
||
| 1630 | $unsetSubdir = isset($this->sessionCache['subdirs']) ? true : false; |
||
| 1631 | foreach ($this->removed as $item) { |
||
| 1632 | if ($item['mime'] === 'directory') { |
||
| 1633 | $path = $this->decode($item['hash']); |
||
| 1634 | if ($unsetSubdir) { |
||
| 1635 | unset($this->sessionCache['subdirs'][$path]); |
||
| 1636 | } |
||
| 1637 | if ($item['phash'] !== '') { |
||
| 1638 | $parent = $this->decode($item['phash']); |
||
| 1639 | unset($this->cache[$parent]); |
||
| 1640 | if ($unsetSubdir) { |
||
| 1641 | unset($this->sessionCache['subdirs'][$parent]); |
||
| 1642 | } |
||
| 1643 | } |
||
| 1644 | } |
||
| 1645 | } |
||
| 1646 | } |
||
| 1647 | |||
| 1648 | return $this->removed; |
||
| 1649 | } |
||
| 1650 | |||
| 1651 | /** |
||
| 1652 | * Return list of added files. |
||
| 1653 | * |
||
| 1654 | * @deprecated |
||
| 1655 | * @return array |
||
| 1656 | * @author Naoki Sawada |
||
| 1657 | **/ |
||
| 1658 | public function added() |
||
| 1659 | { |
||
| 1660 | return $this->added; |
||
| 1661 | } |
||
| 1662 | |||
| 1663 | /** |
||
| 1664 | * Clean removed files list. |
||
| 1665 | * |
||
| 1666 | * @return void |
||
| 1667 | * @author Dmitry (dio) Levashov |
||
| 1668 | **/ |
||
| 1669 | public function resetRemoved() |
||
| 1670 | { |
||
| 1671 | $this->resetResultStat(); |
||
| 1672 | } |
||
| 1673 | |||
| 1674 | /** |
||
| 1675 | * Clean added/removed files list. |
||
| 1676 | * |
||
| 1677 | * @return void |
||
| 1678 | **/ |
||
| 1679 | public function resetResultStat() |
||
| 1680 | { |
||
| 1681 | $this->removed = []; |
||
| 1682 | $this->added = []; |
||
| 1683 | } |
||
| 1684 | |||
| 1685 | /** |
||
| 1686 | * Return file/dir hash or first founded child hash with required attr == $val. |
||
| 1687 | * |
||
| 1688 | * @param string $hash file hash |
||
| 1689 | * @param string $attr attribute name |
||
| 1690 | * @param bool $val attribute value |
||
| 1691 | * @return string|false |
||
| 1692 | * @author Dmitry (dio) Levashov |
||
| 1693 | **/ |
||
| 1694 | public function closest($hash, $attr, $val) |
||
| 1695 | { |
||
| 1696 | return ($path = $this->closestByAttr($this->decode($hash), $attr, $val)) ? $this->encode($path) : false; |
||
| 1697 | } |
||
| 1698 | |||
| 1699 | /** |
||
| 1700 | * Return file info or false on error. |
||
| 1701 | * |
||
| 1702 | * @param string $hash file hash |
||
| 1703 | * @return array|false |
||
| 1704 | * @internal param bool $realpath add realpath field to file info |
||
| 1705 | * @author Dmitry (dio) Levashov |
||
| 1706 | */ |
||
| 1707 | public function file($hash) |
||
| 1708 | { |
||
| 1709 | $file = $this->stat($this->decode($hash)); |
||
| 1710 | |||
| 1711 | return ($file) ? $file : $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 1712 | } |
||
| 1713 | |||
| 1714 | /** |
||
| 1715 | * Return folder info. |
||
| 1716 | * |
||
| 1717 | * @param string $hash folder hash |
||
| 1718 | * @param bool $resolveLink |
||
| 1719 | * @return array|false |
||
| 1720 | * @internal param bool $hidden return hidden file info |
||
| 1721 | * @author Dmitry (dio) Levashov |
||
| 1722 | */ |
||
| 1723 | public function dir($hash, $resolveLink = false) |
||
| 1724 | { |
||
| 1725 | if (($dir = $this->file($hash)) == false) { |
||
| 1726 | return $this->setError(elFinder::ERROR_DIR_NOT_FOUND); |
||
| 1727 | } |
||
| 1728 | |||
| 1729 | if ($resolveLink && ! empty($dir['thash'])) { |
||
| 1730 | $dir = $this->file($dir['thash']); |
||
| 1731 | } |
||
| 1732 | |||
| 1733 | return $dir && $dir['mime'] == 'directory' && empty($dir['hidden']) |
||
| 1734 | ? $dir |
||
| 1735 | : $this->setError(elFinder::ERROR_NOT_DIR); |
||
| 1736 | } |
||
| 1737 | |||
| 1738 | /** |
||
| 1739 | * Return directory content or false on error. |
||
| 1740 | * |
||
| 1741 | * @param string $hash file hash |
||
| 1742 | * @return array|false |
||
| 1743 | * @author Dmitry (dio) Levashov |
||
| 1744 | **/ |
||
| 1745 | public function scandir($hash) |
||
| 1746 | { |
||
| 1747 | if (($dir = $this->dir($hash)) == false) { |
||
| 1748 | return false; |
||
| 1749 | } |
||
| 1750 | |||
| 1751 | $path = $this->decode($hash); |
||
| 1752 | if ($res = $dir['read'] |
||
| 1753 | ? $this->getScandir($path) |
||
| 1754 | : $this->setError(elFinder::ERROR_PERM_DENIED)) { |
||
| 1755 | $dirs = null; |
||
| 1756 | View Code Duplication | if ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$path])) { |
|
| 1757 | $dirs = $this->sessionCache['subdirs'][$path]; |
||
| 1758 | } |
||
| 1759 | if ($dirs !== null || (isset($dir['dirs']) && $dir['dirs'] != 1)) { |
||
| 1760 | $_dir = $dir; |
||
| 1761 | if ($dirs || $this->subdirs($hash)) { |
||
| 1762 | $dir['dirs'] = 1; |
||
| 1763 | } else { |
||
| 1764 | unset($dir['dirs']); |
||
| 1765 | } |
||
| 1766 | if ($dir !== $_dir) { |
||
| 1767 | $this->updateCache($path, $dir); |
||
| 1768 | } |
||
| 1769 | } |
||
| 1770 | } |
||
| 1771 | |||
| 1772 | return $res; |
||
| 1773 | } |
||
| 1774 | |||
| 1775 | /** |
||
| 1776 | * Return dir files names list. |
||
| 1777 | * |
||
| 1778 | * @param string $hash file hash |
||
| 1779 | * @param null $intersect |
||
| 1780 | * @return array |
||
| 1781 | * @author Dmitry (dio) Levashov |
||
| 1782 | */ |
||
| 1783 | public function ls($hash, $intersect = null) |
||
| 1784 | { |
||
| 1785 | if (($dir = $this->dir($hash)) == false || ! $dir['read']) { |
||
| 1786 | return false; |
||
| 1787 | } |
||
| 1788 | |||
| 1789 | $list = []; |
||
| 1790 | $path = $this->decode($hash); |
||
| 1791 | |||
| 1792 | $check = []; |
||
| 1793 | if ($intersect) { |
||
| 1794 | $check = array_flip($intersect); |
||
| 1795 | } |
||
| 1796 | |||
| 1797 | foreach ($this->getScandir($path) as $stat) { |
||
| 1798 | if (empty($stat['hidden']) && (! $check || isset($check[$stat['name']])) && $this->mimeAccepted($stat['mime'])) { |
||
| 1799 | $list[$stat['hash']] = $stat['name']; |
||
| 1800 | } |
||
| 1801 | } |
||
| 1802 | |||
| 1803 | return $list; |
||
| 1804 | } |
||
| 1805 | |||
| 1806 | /** |
||
| 1807 | * Return subfolders for required folder or false on error. |
||
| 1808 | * |
||
| 1809 | * @param string $hash folder hash or empty string to get tree from root folder |
||
| 1810 | * @param int $deep subdir deep |
||
| 1811 | * @param string $exclude dir hash which subfolders must be exluded from result, required to not get stat twice on cwd subfolders |
||
| 1812 | * @return array|false |
||
| 1813 | * @author Dmitry (dio) Levashov |
||
| 1814 | **/ |
||
| 1815 | public function tree($hash = '', $deep = 0, $exclude = '') |
||
| 1816 | { |
||
| 1817 | $path = $hash ? $this->decode($hash) : $this->root; |
||
| 1818 | |||
| 1819 | View Code Duplication | if (($dir = $this->stat($path)) == false || $dir['mime'] != 'directory') { |
|
| 1820 | return false; |
||
| 1821 | } |
||
| 1822 | |||
| 1823 | $dirs = $this->gettree($path, $deep > 0 ? $deep - 1 : $this->treeDeep - 1, $exclude ? $this->decode($exclude) : null); |
||
| 1824 | array_unshift($dirs, $dir); |
||
| 1825 | |||
| 1826 | return $dirs; |
||
| 1827 | } |
||
| 1828 | |||
| 1829 | /** |
||
| 1830 | * Return part of dirs tree from required dir up to root dir. |
||
| 1831 | * |
||
| 1832 | * @param string $hash directory hash |
||
| 1833 | * @param bool|null $lineal only lineal parents |
||
| 1834 | * @param string $until hash that is enough to that extent >= 2.1.24 |
||
| 1835 | * @return array |
||
| 1836 | * @author Dmitry (dio) Levashov |
||
| 1837 | **/ |
||
| 1838 | public function parents($hash, $lineal = false) |
||
| 1839 | { |
||
| 1840 | if (($current = $this->dir($hash)) == false) { |
||
| 1841 | return false; |
||
| 1842 | } |
||
| 1843 | |||
| 1844 | $args = func_get_args(); |
||
| 1845 | // checks 3rd param `$until` (elFinder >= 2.1.24) |
||
| 1846 | $until = ''; |
||
| 1847 | if (isset($args[2])) { |
||
| 1848 | $until = $args[2]; |
||
| 1849 | } |
||
| 1850 | |||
| 1851 | $path = $this->decode($hash); |
||
| 1852 | $tree = []; |
||
| 1853 | |||
| 1854 | while ($path && $path != $this->root) { |
||
| 1855 | elFinder::extendTimeLimit(); |
||
| 1856 | $path = $this->dirnameCE($path); |
||
| 1857 | if (! ($stat = $this->stat($path)) || ! empty($stat['hidden']) || ! $stat['read']) { |
||
| 1858 | return false; |
||
| 1859 | } |
||
| 1860 | |||
| 1861 | array_unshift($tree, $stat); |
||
| 1862 | if (! $lineal) { |
||
| 1863 | foreach ($this->gettree($path, 0) as $dir) { |
||
| 1864 | elFinder::extendTimeLimit(); |
||
| 1865 | if (! isset($tree[$dir['hash']])) { |
||
| 1866 | $tree[$dir['hash']] = $dir; |
||
| 1867 | } |
||
| 1868 | } |
||
| 1869 | } |
||
| 1870 | |||
| 1871 | if ($until && $until === $this->encode($path)) { |
||
| 1872 | break; |
||
| 1873 | } |
||
| 1874 | } |
||
| 1875 | |||
| 1876 | return $tree ? array_values($tree) : [$current]; |
||
| 1877 | } |
||
| 1878 | |||
| 1879 | /** |
||
| 1880 | * Create thumbnail for required file and return its name of false on failed. |
||
| 1881 | * |
||
| 1882 | * @param $hash |
||
| 1883 | * @return false|string |
||
| 1884 | * @author Dmitry (dio) Levashov |
||
| 1885 | */ |
||
| 1886 | public function tmb($hash) |
||
| 1887 | { |
||
| 1888 | $path = $this->decode($hash); |
||
| 1889 | $stat = $this->stat($path); |
||
| 1890 | |||
| 1891 | if (isset($stat['tmb'])) { |
||
| 1892 | $res = $stat['tmb'] == '1' ? $this->createTmb($path, $stat) : $stat['tmb']; |
||
| 1893 | if (! $res) { |
||
| 1894 | list($type) = explode('/', $stat['mime']); |
||
| 1895 | $fallback = $this->options['resourcePath'].DIRECTORY_SEPARATOR.strtolower($type).'.png'; |
||
| 1896 | if (is_file($fallback)) { |
||
| 1897 | $res = $this->tmbname($stat); |
||
| 1898 | if (! copy($fallback, $this->tmbPath.DIRECTORY_SEPARATOR.$res)) { |
||
| 1899 | $res = false; |
||
| 1900 | } |
||
| 1901 | } |
||
| 1902 | } |
||
| 1903 | |||
| 1904 | return $res; |
||
| 1905 | } |
||
| 1906 | |||
| 1907 | return false; |
||
| 1908 | } |
||
| 1909 | |||
| 1910 | /** |
||
| 1911 | * Return file size / total directory size. |
||
| 1912 | * |
||
| 1913 | * @param string file hash |
||
| 1914 | * @return int |
||
| 1915 | * @author Dmitry (dio) Levashov |
||
| 1916 | **/ |
||
| 1917 | public function size($hash) |
||
| 1918 | { |
||
| 1919 | return $this->countSize($this->decode($hash)); |
||
| 1920 | } |
||
| 1921 | |||
| 1922 | /** |
||
| 1923 | * Open file for reading and return file pointer. |
||
| 1924 | * |
||
| 1925 | * @param string file hash |
||
| 1926 | * @return resource |
||
| 1927 | * @author Dmitry (dio) Levashov |
||
| 1928 | **/ |
||
| 1929 | public function open($hash) |
||
| 1930 | { |
||
| 1931 | View Code Duplication | if (($file = $this->file($hash)) == false |
|
| 1932 | || $file['mime'] == 'directory') { |
||
| 1933 | return false; |
||
| 1934 | } |
||
| 1935 | |||
| 1936 | return $this->fopenCE($this->decode($hash), 'rb'); |
||
| 1937 | } |
||
| 1938 | |||
| 1939 | /** |
||
| 1940 | * Close file pointer. |
||
| 1941 | * |
||
| 1942 | * @param resource $fp file pointer |
||
| 1943 | * @param string $hash file hash |
||
| 1944 | * @return void |
||
| 1945 | * @author Dmitry (dio) Levashov |
||
| 1946 | **/ |
||
| 1947 | public function close($fp, $hash) |
||
| 1948 | { |
||
| 1949 | $this->fcloseCE($fp, $this->decode($hash)); |
||
| 1950 | } |
||
| 1951 | |||
| 1952 | /** |
||
| 1953 | * Create directory and return dir info. |
||
| 1954 | * |
||
| 1955 | * @param string $dsthash destination directory hash |
||
| 1956 | * @param string $name directory name |
||
| 1957 | * @return array|false |
||
| 1958 | * @author Dmitry (dio) Levashov |
||
| 1959 | **/ |
||
| 1960 | public function mkdir($dsthash, $name) |
||
| 1961 | { |
||
| 1962 | if ($this->commandDisabled('mkdir')) { |
||
| 1963 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 1964 | } |
||
| 1965 | |||
| 1966 | if (! $this->nameAccepted($name, true)) { |
||
| 1967 | return $this->setError(elFinder::ERROR_INVALID_DIRNAME); |
||
| 1968 | } |
||
| 1969 | |||
| 1970 | if (($dir = $this->dir($dsthash)) == false) { |
||
| 1971 | return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dsthash); |
||
| 1972 | } |
||
| 1973 | |||
| 1974 | $path = $this->decode($dsthash); |
||
| 1975 | |||
| 1976 | if (! $dir['write'] || ! $this->allowCreate($path, $name, true)) { |
||
| 1977 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 1978 | } |
||
| 1979 | |||
| 1980 | $dst = $this->joinPathCE($path, $name); |
||
| 1981 | $stat = $this->isNameExists($dst); |
||
| 1982 | if (! empty($stat)) { |
||
| 1983 | return $this->setError(elFinder::ERROR_EXISTS, $name); |
||
| 1984 | } |
||
| 1985 | $this->clearcache(); |
||
| 1986 | |||
| 1987 | $mkpath = $this->convEncOut($this->_mkdir($this->convEncIn($path), $this->convEncIn($name))); |
||
| 1988 | if ($mkpath) { |
||
| 1989 | $this->updateSubdirsCache($path, true); |
||
| 1990 | $this->updateSubdirsCache($mkpath, false); |
||
| 1991 | } |
||
| 1992 | |||
| 1993 | return $mkpath ? $this->stat($mkpath) : false; |
||
| 1994 | } |
||
| 1995 | |||
| 1996 | /** |
||
| 1997 | * Create empty file and return its info. |
||
| 1998 | * |
||
| 1999 | * @param string $dst destination directory |
||
| 2000 | * @param string $name file name |
||
| 2001 | * @return array|false |
||
| 2002 | * @author Dmitry (dio) Levashov |
||
| 2003 | **/ |
||
| 2004 | public function mkfile($dst, $name) |
||
| 2005 | { |
||
| 2006 | if ($this->commandDisabled('mkfile')) { |
||
| 2007 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2008 | } |
||
| 2009 | |||
| 2010 | if (! $this->nameAccepted($name, false)) { |
||
| 2011 | return $this->setError(elFinder::ERROR_INVALID_NAME); |
||
| 2012 | } |
||
| 2013 | |||
| 2014 | $mimeByName = $this->mimetype($name, true); |
||
| 2015 | if ($mimeByName && ! $this->allowPutMime($mimeByName)) { |
||
| 2016 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $name); |
||
| 2017 | } |
||
| 2018 | |||
| 2019 | View Code Duplication | if (($dir = $this->dir($dst)) == false) { |
|
| 2020 | return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); |
||
| 2021 | } |
||
| 2022 | |||
| 2023 | $path = $this->decode($dst); |
||
| 2024 | |||
| 2025 | if (! $dir['write'] || ! $this->allowCreate($path, $name, false)) { |
||
| 2026 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2027 | } |
||
| 2028 | |||
| 2029 | if ($this->isNameExists($this->joinPathCE($path, $name))) { |
||
| 2030 | return $this->setError(elFinder::ERROR_EXISTS, $name); |
||
| 2031 | } |
||
| 2032 | |||
| 2033 | $this->clearcache(); |
||
| 2034 | |||
| 2035 | return ($path = $this->convEncOut($this->_mkfile($this->convEncIn($path), $this->convEncIn($name)))) ? $this->stat($path) : false; |
||
| 2036 | } |
||
| 2037 | |||
| 2038 | /** |
||
| 2039 | * Rename file and return file info. |
||
| 2040 | * |
||
| 2041 | * @param string $hash file hash |
||
| 2042 | * @param string $name new file name |
||
| 2043 | * @return array|false |
||
| 2044 | * @author Dmitry (dio) Levashov |
||
| 2045 | **/ |
||
| 2046 | public function rename($hash, $name) |
||
| 2047 | { |
||
| 2048 | if ($this->commandDisabled('rename')) { |
||
| 2049 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2050 | } |
||
| 2051 | |||
| 2052 | if (! ($file = $this->file($hash))) { |
||
| 2053 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2054 | } |
||
| 2055 | |||
| 2056 | if ($name === $file['name']) { |
||
| 2057 | return $file; |
||
| 2058 | } |
||
| 2059 | |||
| 2060 | if (! empty($file['locked'])) { |
||
| 2061 | return $this->setError(elFinder::ERROR_LOCKED, $file['name']); |
||
| 2062 | } |
||
| 2063 | |||
| 2064 | $isDir = ($file['mime'] === 'directory'); |
||
| 2065 | |||
| 2066 | if (! $this->nameAccepted($name, $isDir)) { |
||
| 2067 | return $this->setError(elFinder::ERROR_INVALID_DIRNAME); |
||
| 2068 | } |
||
| 2069 | |||
| 2070 | if (! $isDir) { |
||
| 2071 | $mimeByName = $this->mimetype($name, true); |
||
| 2072 | if ($mimeByName && ! $this->allowPutMime($mimeByName)) { |
||
| 2073 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $name); |
||
| 2074 | } |
||
| 2075 | } |
||
| 2076 | |||
| 2077 | $path = $this->decode($hash); |
||
| 2078 | $dir = $this->dirnameCE($path); |
||
| 2079 | $stat = $this->isNameExists($this->joinPathCE($dir, $name)); |
||
| 2080 | if ($stat) { |
||
| 2081 | return $this->setError(elFinder::ERROR_EXISTS, $name); |
||
| 2082 | } |
||
| 2083 | |||
| 2084 | if (! $this->allowCreate($dir, $name, ($file['mime'] === 'directory'))) { |
||
| 2085 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2086 | } |
||
| 2087 | |||
| 2088 | $this->rmTmb($file); // remove old name tmbs, we cannot do this after dir move |
||
| 2089 | |||
| 2090 | if ($path = $this->convEncOut($this->_move($this->convEncIn($path), $this->convEncIn($dir), $this->convEncIn($name)))) { |
||
| 2091 | $this->clearcache(); |
||
| 2092 | |||
| 2093 | return $this->stat($path); |
||
| 2094 | } |
||
| 2095 | |||
| 2096 | return false; |
||
| 2097 | } |
||
| 2098 | |||
| 2099 | /** |
||
| 2100 | * Create file copy with suffix "copy number" and return its info. |
||
| 2101 | * |
||
| 2102 | * @param string $hash file hash |
||
| 2103 | * @param string $suffix suffix to add to file name |
||
| 2104 | * @return array|false |
||
| 2105 | * @author Dmitry (dio) Levashov |
||
| 2106 | **/ |
||
| 2107 | public function duplicate($hash, $suffix = 'copy') |
||
| 2108 | { |
||
| 2109 | if ($this->commandDisabled('duplicate')) { |
||
| 2110 | return $this->setError(elFinder::ERROR_COPY, '#'.$hash, elFinder::ERROR_PERM_DENIED); |
||
| 2111 | } |
||
| 2112 | |||
| 2113 | if (($file = $this->file($hash)) == false) { |
||
| 2114 | return $this->setError(elFinder::ERROR_COPY, elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2115 | } |
||
| 2116 | |||
| 2117 | $path = $this->decode($hash); |
||
| 2118 | $dir = $this->dirnameCE($path); |
||
| 2119 | $name = $this->uniqueName($dir, $file['name'], sprintf($this->options['duplicateSuffix'], $suffix)); |
||
| 2120 | |||
| 2121 | if (! $this->allowCreate($dir, $name, ($file['mime'] === 'directory'))) { |
||
| 2122 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2123 | } |
||
| 2124 | |||
| 2125 | return ($path = $this->copy($path, $dir, $name)) == false |
||
| 2126 | ? false |
||
| 2127 | : $this->stat($path); |
||
| 2128 | } |
||
| 2129 | |||
| 2130 | /** |
||
| 2131 | * Save uploaded file. |
||
| 2132 | * On success return array with new file stat and with removed file hash (if existed file was replaced). |
||
| 2133 | * |
||
| 2134 | * @param resource $fp file pointer |
||
| 2135 | * @param string $dst destination folder hash |
||
| 2136 | * @param $name |
||
| 2137 | * @param string $tmpname file tmp name - required to detect mime type |
||
| 2138 | * @param array $hashes exists files hash array with filename as key |
||
| 2139 | * @return array|false |
||
| 2140 | * @internal param string $src file name |
||
| 2141 | * @author Dmitry (dio) Levashov |
||
| 2142 | */ |
||
| 2143 | public function upload($fp, $dst, $name, $tmpname, $hashes = []) |
||
| 2144 | { |
||
| 2145 | if ($this->commandDisabled('upload')) { |
||
| 2146 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2147 | } |
||
| 2148 | |||
| 2149 | View Code Duplication | if (($dir = $this->dir($dst)) == false) { |
|
| 2150 | return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); |
||
| 2151 | } |
||
| 2152 | |||
| 2153 | if (empty($dir['write'])) { |
||
| 2154 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2155 | } |
||
| 2156 | |||
| 2157 | if (! $this->nameAccepted($name, false)) { |
||
| 2158 | return $this->setError(elFinder::ERROR_INVALID_NAME); |
||
| 2159 | } |
||
| 2160 | |||
| 2161 | $mimeByName = ''; |
||
| 2162 | if ($this->mimeDetect === 'internal') { |
||
| 2163 | $mime = $this->mimetype($name, true); |
||
| 2164 | } else { |
||
| 2165 | $mime = $this->mimetype($tmpname, $name); |
||
| 2166 | $mimeByName = $this->mimetype($name, true); |
||
| 2167 | if ($mime === 'unknown') { |
||
| 2168 | $mime = $mimeByName; |
||
| 2169 | } |
||
| 2170 | } |
||
| 2171 | |||
| 2172 | View Code Duplication | if (! $this->allowPutMime($mime) || ($mimeByName && ! $this->allowPutMime($mimeByName))) { |
|
| 2173 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME); |
||
| 2174 | } |
||
| 2175 | |||
| 2176 | $tmpsize = sprintf('%u', filesize($tmpname)); |
||
| 2177 | if ($this->uploadMaxSize > 0 && $tmpsize > $this->uploadMaxSize) { |
||
| 2178 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE); |
||
| 2179 | } |
||
| 2180 | |||
| 2181 | $dstpath = $this->decode($dst); |
||
| 2182 | View Code Duplication | if (isset($hashes[$name])) { |
|
| 2183 | $test = $this->decode($hashes[$name]); |
||
| 2184 | $file = $this->stat($test); |
||
| 2185 | } else { |
||
| 2186 | $test = $this->joinPathCE($dstpath, $name); |
||
| 2187 | $file = $this->isNameExists($test); |
||
| 2188 | } |
||
| 2189 | |||
| 2190 | $this->clearcache(); |
||
| 2191 | |||
| 2192 | if ($file && $file['name'] === $name) { // file exists and check filename for item ID based filesystem |
||
| 2193 | if ($this->uploadOverwrite) { |
||
| 2194 | View Code Duplication | if (! $file['write']) { |
|
| 2195 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2196 | } elseif ($file['mime'] == 'directory') { |
||
| 2197 | return $this->setError(elFinder::ERROR_NOT_REPLACE, $name); |
||
| 2198 | } |
||
| 2199 | $this->remove($test); |
||
| 2200 | } else { |
||
| 2201 | $name = $this->uniqueName($dstpath, $name, '-', false); |
||
| 2202 | } |
||
| 2203 | } |
||
| 2204 | |||
| 2205 | $stat = [ |
||
| 2206 | 'mime' => $mime, |
||
| 2207 | 'width' => 0, |
||
| 2208 | 'height' => 0, |
||
| 2209 | 'size' => $tmpsize, ]; |
||
| 2210 | |||
| 2211 | // $w = $h = 0; |
||
| 2212 | if (strpos($mime, 'image') === 0 && ($s = getimagesize($tmpname))) { |
||
| 2213 | $stat['width'] = $s[0]; |
||
| 2214 | $stat['height'] = $s[1]; |
||
| 2215 | } |
||
| 2216 | // $this->clearcache(); |
||
| 2217 | if (($path = $this->saveCE($fp, $dstpath, $name, $stat)) == false) { |
||
| 2218 | return false; |
||
| 2219 | } |
||
| 2220 | |||
| 2221 | $stat = $this->stat($path); |
||
| 2222 | // Try get URL |
||
| 2223 | if (empty($stat['url']) && ($url = $this->getContentUrl($stat['hash']))) { |
||
| 2224 | $stat['url'] = $url; |
||
| 2225 | } |
||
| 2226 | |||
| 2227 | return $stat; |
||
| 2228 | } |
||
| 2229 | |||
| 2230 | /** |
||
| 2231 | * Paste files. |
||
| 2232 | * |
||
| 2233 | * @param object $volume source volume |
||
| 2234 | * @param $src |
||
| 2235 | * @param string $dst destination dir hash |
||
| 2236 | * @param bool $rmSrc remove source after copy? |
||
| 2237 | * @param array $hashes |
||
| 2238 | * @return array|false |
||
| 2239 | * @internal param string $source file hash |
||
| 2240 | * @author Dmitry (dio) Levashov |
||
| 2241 | */ |
||
| 2242 | public function paste($volume, $src, $dst, $rmSrc = false, $hashes = []) |
||
| 2243 | { |
||
| 2244 | $err = $rmSrc ? elFinder::ERROR_MOVE : elFinder::ERROR_COPY; |
||
| 2245 | |||
| 2246 | if ($this->commandDisabled('paste')) { |
||
| 2247 | return $this->setError($err, '#'.$src, elFinder::ERROR_PERM_DENIED); |
||
| 2248 | } |
||
| 2249 | |||
| 2250 | if (($file = $volume->file($src, $rmSrc)) == false) { |
||
| 2251 | return $this->setError($err, '#'.$src, elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2252 | } |
||
| 2253 | |||
| 2254 | $name = $file['name']; |
||
| 2255 | $errpath = $volume->path($file['hash']); |
||
| 2256 | |||
| 2257 | View Code Duplication | if (($dir = $this->dir($dst)) == false) { |
|
| 2258 | return $this->setError($err, $errpath, elFinder::ERROR_TRGDIR_NOT_FOUND, '#'.$dst); |
||
| 2259 | } |
||
| 2260 | |||
| 2261 | if (! $dir['write'] || ! $file['read']) { |
||
| 2262 | return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); |
||
| 2263 | } |
||
| 2264 | |||
| 2265 | $destination = $this->decode($dst); |
||
| 2266 | |||
| 2267 | if (($test = $volume->closest($src, $rmSrc ? 'locked' : 'read', $rmSrc))) { |
||
| 2268 | return $rmSrc |
||
| 2269 | ? $this->setError($err, $errpath, elFinder::ERROR_LOCKED, $volume->path($test)) |
||
| 2270 | : $this->setError($err, $errpath, empty($file['thash']) ? elFinder::ERROR_PERM_DENIED : elFinder::ERROR_MKOUTLINK); |
||
| 2271 | } |
||
| 2272 | |||
| 2273 | View Code Duplication | if (isset($hashes[$name])) { |
|
| 2274 | $test = $this->decode($hashes[$name]); |
||
| 2275 | $stat = $this->stat($test); |
||
| 2276 | } else { |
||
| 2277 | $test = $this->joinPathCE($destination, $name); |
||
| 2278 | $stat = $this->isNameExists($test); |
||
| 2279 | } |
||
| 2280 | $this->clearcache(); |
||
| 2281 | $dstDirExists = false; |
||
| 2282 | if ($stat && $stat['name'] === $name) { // file exists and check filename for item ID based filesystem |
||
| 2283 | if ($this->options['copyOverwrite']) { |
||
| 2284 | // do not replace file with dir or dir with file |
||
| 2285 | if (! $this->isSameType($file['mime'], $stat['mime'])) { |
||
| 2286 | return $this->setError(elFinder::ERROR_NOT_REPLACE, $this->path($stat['hash'])); |
||
| 2287 | } |
||
| 2288 | // existed file is not writable |
||
| 2289 | if (! $stat['write']) { |
||
| 2290 | return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); |
||
| 2291 | } |
||
| 2292 | if ($this->options['copyJoin']) { |
||
| 2293 | if ($stat['locked']) { |
||
| 2294 | return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash'])); |
||
| 2295 | } |
||
| 2296 | } else { |
||
| 2297 | // existed file locked or has locked child |
||
| 2298 | if (($locked = $this->closestByAttr($test, 'locked', true))) { |
||
| 2299 | $stat = $this->stat($locked); |
||
| 2300 | |||
| 2301 | return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash'])); |
||
| 2302 | } |
||
| 2303 | } |
||
| 2304 | // target is entity file of alias |
||
| 2305 | if ($volume === $this && ((isset($file['target']) && $test == $file['target']) || $test == $this->decode($src))) { |
||
| 2306 | return $this->setError(elFinder::ERROR_REPLACE, $errpath); |
||
| 2307 | } |
||
| 2308 | // remove existed file |
||
| 2309 | if (! $this->options['copyJoin'] || $stat['mime'] !== 'directory') { |
||
| 2310 | if (! $this->remove($test)) { |
||
| 2311 | return $this->setError(elFinder::ERROR_REPLACE, $this->path($stat['hash'])); |
||
| 2312 | } |
||
| 2313 | } elseif ($stat['mime'] === 'directory') { |
||
| 2314 | $dstDirExists = true; |
||
| 2315 | } |
||
| 2316 | } else { |
||
| 2317 | $name = $this->uniqueName($destination, $name, ' ', false); |
||
| 2318 | } |
||
| 2319 | } |
||
| 2320 | |||
| 2321 | // copy/move inside current volume |
||
| 2322 | if ($volume === $this) { // changing == operand to === fixes issue #1285 - Paul Canning 24/03/2016 |
||
| 2323 | $source = $this->decode($src); |
||
| 2324 | // do not copy into itself |
||
| 2325 | if ($this->inpathCE($destination, $source)) { |
||
| 2326 | return $this->setError(elFinder::ERROR_COPY_INTO_ITSELF, $errpath); |
||
| 2327 | } |
||
| 2328 | $rmDir = false; |
||
| 2329 | if ($rmSrc) { |
||
| 2330 | if ($dstDirExists) { |
||
| 2331 | $rmDir = true; |
||
| 2332 | $method = 'copy'; |
||
| 2333 | } else { |
||
| 2334 | $method = 'move'; |
||
| 2335 | } |
||
| 2336 | } else { |
||
| 2337 | $method = 'copy'; |
||
| 2338 | } |
||
| 2339 | $this->clearcache(); |
||
| 2340 | if ($res = ($path = $this->$method($source, $destination, $name)) ? $this->stat($path) : false) { |
||
| 2341 | if ($rmDir) { |
||
| 2342 | $this->remove($source); |
||
| 2343 | } |
||
| 2344 | } else { |
||
| 2345 | return false; |
||
| 2346 | } |
||
| 2347 | } else { |
||
| 2348 | // copy/move from another volume |
||
| 2349 | if (! $this->options['copyTo'] || ! $volume->copyFromAllowed()) { |
||
| 2350 | return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED); |
||
| 2351 | } |
||
| 2352 | |||
| 2353 | if (($path = $this->copyFrom($volume, $src, $destination, $name)) == false) { |
||
| 2354 | return false; |
||
| 2355 | } |
||
| 2356 | |||
| 2357 | if ($rmSrc) { |
||
| 2358 | if (! $volume->rm($src)) { |
||
| 2359 | return $this->setError(elFinder::ERROR_MOVE, $errpath, elFinder::ERROR_RM_SRC); |
||
| 2360 | } |
||
| 2361 | } |
||
| 2362 | $res = $this->stat($path); |
||
| 2363 | } |
||
| 2364 | |||
| 2365 | return $res; |
||
| 2366 | } |
||
| 2367 | |||
| 2368 | /** |
||
| 2369 | * Return path to archive of target items. |
||
| 2370 | * |
||
| 2371 | * @param array $hashes |
||
| 2372 | * @return string archive path |
||
| 2373 | * @author Naoki Sawada |
||
| 2374 | */ |
||
| 2375 | public function zipdl($hashes) |
||
| 2376 | { |
||
| 2377 | if ($this->commandDisabled('zipdl')) { |
||
| 2378 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2379 | } |
||
| 2380 | |||
| 2381 | $archivers = $this->getArchivers(); |
||
| 2382 | $cmd = null; |
||
| 2383 | if (! $archivers || empty($archivers['create'])) { |
||
| 2384 | return false; |
||
| 2385 | } |
||
| 2386 | $archivers = $archivers['create']; |
||
| 2387 | foreach (['zip', 'tgz'] as $ext) { |
||
| 2388 | $mime = self::$mimetypes[$ext]; |
||
| 2389 | if (isset($archivers[$mime])) { |
||
| 2390 | $cmd = $archivers[$mime]; |
||
| 2391 | break; |
||
| 2392 | } |
||
| 2393 | } |
||
| 2394 | if (! $cmd) { |
||
| 2395 | $cmd = $archivers[0]; |
||
| 2396 | $ext = $cmd['ext']; |
||
| 2397 | $mime = $this->mimetype('file.'.$ext, true); |
||
| 2398 | } |
||
| 2399 | $res = false; |
||
| 2400 | $mixed = false; |
||
| 2401 | $hashes = array_values($hashes); |
||
| 2402 | $dirname = dirname(str_replace($this->separator, DIRECTORY_SEPARATOR, $this->path($hashes[0]))); |
||
| 2403 | $cnt = count($hashes); |
||
| 2404 | if ($cnt > 1) { |
||
| 2405 | for ($i = 1; $i < $cnt; $i++) { |
||
| 2406 | if ($dirname !== dirname(str_replace($this->separator, DIRECTORY_SEPARATOR, $this->path($hashes[$i])))) { |
||
| 2407 | $mixed = true; |
||
| 2408 | break; |
||
| 2409 | } |
||
| 2410 | } |
||
| 2411 | } |
||
| 2412 | if ($mixed || $this->root == $this->dirnameCE($this->decode($hashes[0]))) { |
||
| 2413 | $prefix = $this->rootName; |
||
| 2414 | } else { |
||
| 2415 | $prefix = basename($dirname); |
||
| 2416 | } |
||
| 2417 | if ($dir = $this->getItemsInHand($hashes)) { |
||
| 2418 | $tmppre = (substr(PHP_OS, 0, 3) === 'WIN') ? 'zdl' : 'elfzdl'; |
||
| 2419 | $pdir = dirname($dir); |
||
| 2420 | // garbage collection |
||
| 2421 | $ttl = 7200; // expire 2h |
||
| 2422 | $time = time(); |
||
| 2423 | foreach (glob($pdir.DIRECTORY_SEPARATOR.$tmppre.'*') as $_file) { |
||
| 2424 | if (filemtime($_file) + $ttl < $time) { |
||
| 2425 | unlink($_file); |
||
| 2426 | } |
||
| 2427 | } |
||
| 2428 | $files = self::localScandir($dir); |
||
| 2429 | if ($files && ($arc = tempnam($dir, $tmppre))) { |
||
| 2430 | unlink($arc); |
||
| 2431 | $arc = $arc.'.'.$ext; |
||
| 2432 | $name = basename($arc); |
||
| 2433 | if ($arc = $this->makeArchive($dir, $files, $name, $cmd)) { |
||
| 2434 | $file = tempnam($pdir, $tmppre); |
||
| 2435 | unlink($file); |
||
| 2436 | $res = rename($arc, $file); |
||
| 2437 | $this->rmdirRecursive($dir); |
||
| 2438 | } |
||
| 2439 | } |
||
| 2440 | } |
||
| 2441 | |||
| 2442 | return $res ? ['path' => $file, 'ext' => $ext, 'mime' => $mime, 'prefix' => $prefix] : false; |
||
| 2443 | } |
||
| 2444 | |||
| 2445 | /** |
||
| 2446 | * Return file contents. |
||
| 2447 | * |
||
| 2448 | * @param string $hash file hash |
||
| 2449 | * @return string|false |
||
| 2450 | * @author Dmitry (dio) Levashov |
||
| 2451 | **/ |
||
| 2452 | public function getContents($hash) |
||
| 2453 | { |
||
| 2454 | $file = $this->file($hash); |
||
| 2455 | |||
| 2456 | if (! $file) { |
||
| 2457 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2458 | } |
||
| 2459 | |||
| 2460 | if ($file['mime'] == 'directory') { |
||
| 2461 | return $this->setError(elFinder::ERROR_NOT_FILE); |
||
| 2462 | } |
||
| 2463 | |||
| 2464 | if (! $file['read']) { |
||
| 2465 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2466 | } |
||
| 2467 | |||
| 2468 | if ($this->getMaxSize > 0 && $file['size'] > $this->getMaxSize) { |
||
| 2469 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE); |
||
| 2470 | } |
||
| 2471 | |||
| 2472 | return $this->_getContents($this->convEncIn($this->decode($hash), true)); |
||
| 2473 | } |
||
| 2474 | |||
| 2475 | /** |
||
| 2476 | * Put content in text file and return file info. |
||
| 2477 | * |
||
| 2478 | * @param string $hash file hash |
||
| 2479 | * @param string $content new file content |
||
| 2480 | * @return array |
||
| 2481 | * @author Dmitry (dio) Levashov |
||
| 2482 | **/ |
||
| 2483 | public function putContents($hash, $content) |
||
| 2484 | { |
||
| 2485 | if ($this->commandDisabled('edit')) { |
||
| 2486 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2487 | } |
||
| 2488 | |||
| 2489 | $path = $this->decode($hash); |
||
| 2490 | |||
| 2491 | if (! ($file = $this->file($hash))) { |
||
| 2492 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2493 | } |
||
| 2494 | |||
| 2495 | if (! $file['write']) { |
||
| 2496 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2497 | } |
||
| 2498 | |||
| 2499 | // check data cheme |
||
| 2500 | if (preg_match('~^data:(.+?/.+?);base64,~', $content, $m)) { |
||
| 2501 | $dMime = $m[1]; |
||
| 2502 | if ($file['size'] > 0 && $dMime !== $file['mime']) { |
||
| 2503 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2504 | } |
||
| 2505 | $content = base64_decode(substr($content, strlen($m[0]))); |
||
| 2506 | } |
||
| 2507 | |||
| 2508 | // check MIME |
||
| 2509 | $name = $this->basenameCE($path); |
||
| 2510 | $mime = ''; |
||
| 2511 | $mimeByName = $this->mimetype($name, true); |
||
| 2512 | if ($this->mimeDetect !== 'internal') { |
||
| 2513 | if ($tp = tmpfile()) { |
||
| 2514 | fwrite($tp, $content); |
||
| 2515 | $info = stream_get_meta_data($tp); |
||
| 2516 | $filepath = $info['uri']; |
||
| 2517 | $mime = $this->mimetype($filepath, $name); |
||
| 2518 | fclose($tp); |
||
| 2519 | } |
||
| 2520 | } |
||
| 2521 | View Code Duplication | if (! $this->allowPutMime($mimeByName) || ($mime && ! $this->allowPutMime($mime))) { |
|
| 2522 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME); |
||
| 2523 | } |
||
| 2524 | |||
| 2525 | $this->clearcache(); |
||
| 2526 | |||
| 2527 | return $this->convEncOut($this->_filePutContents($this->convEncIn($path), $content)) ? $this->stat($path) : false; |
||
| 2528 | } |
||
| 2529 | |||
| 2530 | /** |
||
| 2531 | * Extract files from archive. |
||
| 2532 | * |
||
| 2533 | * @param string $hash archive hash |
||
| 2534 | * @param null $makedir |
||
| 2535 | * @return array|bool |
||
| 2536 | * @author Dmitry (dio) Levashov, |
||
| 2537 | * @author Alexey Sukhotin |
||
| 2538 | */ |
||
| 2539 | public function extract($hash, $makedir = null) |
||
| 2540 | { |
||
| 2541 | if ($this->commandDisabled('extract')) { |
||
| 2542 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2543 | } |
||
| 2544 | |||
| 2545 | if (($file = $this->file($hash)) == false) { |
||
| 2546 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2547 | } |
||
| 2548 | |||
| 2549 | $archiver = isset($this->archivers['extract'][$file['mime']]) |
||
| 2550 | ? $this->archivers['extract'][$file['mime']] |
||
| 2551 | : false; |
||
| 2552 | |||
| 2553 | if (! $archiver) { |
||
| 2554 | return $this->setError(elFinder::ERROR_NOT_ARCHIVE); |
||
| 2555 | } |
||
| 2556 | |||
| 2557 | $path = $this->decode($hash); |
||
| 2558 | $parent = $this->stat($this->dirnameCE($path)); |
||
| 2559 | |||
| 2560 | if (! $file['read'] || ! $parent['write']) { |
||
| 2561 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2562 | } |
||
| 2563 | $this->clearcache(); |
||
| 2564 | $this->extractToNewdir = is_null($makedir) ? 'auto' : (bool) $makedir; |
||
| 2565 | |||
| 2566 | if ($path = $this->convEncOut($this->_extract($this->convEncIn($path), $archiver))) { |
||
| 2567 | if (is_array($path)) { |
||
| 2568 | foreach ($path as $_k => $_p) { |
||
| 2569 | $path[$_k] = $this->stat($_p); |
||
| 2570 | } |
||
| 2571 | } else { |
||
| 2572 | $path = $this->stat($path); |
||
| 2573 | } |
||
| 2574 | |||
| 2575 | return $path; |
||
| 2576 | } else { |
||
| 2577 | return false; |
||
| 2578 | } |
||
| 2579 | } |
||
| 2580 | |||
| 2581 | /** |
||
| 2582 | * Add files to archive. |
||
| 2583 | * |
||
| 2584 | * @param $hashes |
||
| 2585 | * @param $mime |
||
| 2586 | * @param string $name |
||
| 2587 | * @return array|bool |
||
| 2588 | */ |
||
| 2589 | public function archive($hashes, $mime, $name = '') |
||
| 2590 | { |
||
| 2591 | if ($this->commandDisabled('archive')) { |
||
| 2592 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2593 | } |
||
| 2594 | |||
| 2595 | if ($name !== '' && ! $this->nameAccepted($name, false)) { |
||
| 2596 | return $this->setError(elFinder::ERROR_INVALID_NAME); |
||
| 2597 | } |
||
| 2598 | |||
| 2599 | $archiver = isset($this->archivers['create'][$mime]) |
||
| 2600 | ? $this->archivers['create'][$mime] |
||
| 2601 | : false; |
||
| 2602 | |||
| 2603 | if (! $archiver) { |
||
| 2604 | return $this->setError(elFinder::ERROR_ARCHIVE_TYPE); |
||
| 2605 | } |
||
| 2606 | |||
| 2607 | $files = []; |
||
| 2608 | |||
| 2609 | foreach ($hashes as $hash) { |
||
| 2610 | View Code Duplication | if (($file = $this->file($hash)) == false) { |
|
| 2611 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND, '#' + $hash); |
||
| 2612 | } |
||
| 2613 | if (! $file['read']) { |
||
| 2614 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2615 | } |
||
| 2616 | $path = $this->decode($hash); |
||
| 2617 | if (! isset($dir)) { |
||
| 2618 | $dir = $this->dirnameCE($path); |
||
| 2619 | $stat = $this->stat($dir); |
||
| 2620 | if (! $stat['write']) { |
||
| 2621 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2622 | } |
||
| 2623 | } |
||
| 2624 | |||
| 2625 | $files[] = $this->basenameCE($path); |
||
| 2626 | } |
||
| 2627 | |||
| 2628 | if ($name === '') { |
||
| 2629 | $name = count($files) == 1 ? $files[0] : 'Archive'; |
||
| 2630 | } else { |
||
| 2631 | $name = str_replace(['/', '\\'], '_', preg_replace('/\.'.preg_quote($archiver['ext'], '/').'$/i', '', $name)); |
||
| 2632 | } |
||
| 2633 | $name .= '.'.$archiver['ext']; |
||
| 2634 | $name = $this->uniqueName($dir, $name, ''); |
||
| 2635 | $this->clearcache(); |
||
| 2636 | |||
| 2637 | return ($path = $this->convEncOut($this->_archive($this->convEncIn($dir), $this->convEncIn($files), $this->convEncIn($name), $archiver))) ? $this->stat($path) : false; |
||
| 2638 | } |
||
| 2639 | |||
| 2640 | /** |
||
| 2641 | * Resize image. |
||
| 2642 | * |
||
| 2643 | * @param string $hash image file |
||
| 2644 | * @param int $width new width |
||
| 2645 | * @param int $height new height |
||
| 2646 | * @param int $x X start poistion for crop |
||
| 2647 | * @param int $y Y start poistion for crop |
||
| 2648 | * @param string $mode action how to mainpulate image |
||
| 2649 | * @param string $bg background color |
||
| 2650 | * @param int $degree rotete degree |
||
| 2651 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 2652 | * @return array|false |
||
| 2653 | * @author Dmitry (dio) Levashov |
||
| 2654 | * @author Alexey Sukhotin |
||
| 2655 | * @author nao-pon |
||
| 2656 | * @author Troex Nevelin |
||
| 2657 | **/ |
||
| 2658 | public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0, $jpgQuality = null) |
||
| 2659 | { |
||
| 2660 | if ($this->commandDisabled('resize')) { |
||
| 2661 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2662 | } |
||
| 2663 | |||
| 2664 | if (($file = $this->file($hash)) == false) { |
||
| 2665 | return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); |
||
| 2666 | } |
||
| 2667 | |||
| 2668 | if (! $file['write'] || ! $file['read']) { |
||
| 2669 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2670 | } |
||
| 2671 | |||
| 2672 | $path = $this->decode($hash); |
||
| 2673 | |||
| 2674 | $work_path = $this->getWorkFile($this->encoding ? $this->convEncIn($path, true) : $path); |
||
| 2675 | |||
| 2676 | if (! $work_path || ! is_writable($work_path)) { |
||
| 2677 | if ($work_path && $path !== $work_path && is_file($work_path)) { |
||
| 2678 | unlink($work_path); |
||
| 2679 | } |
||
| 2680 | |||
| 2681 | return $this->setError(elFinder::ERROR_PERM_DENIED); |
||
| 2682 | } |
||
| 2683 | |||
| 2684 | if ($this->imgLib !== 'imagick' && $this->imgLib !== 'convert') { |
||
| 2685 | if (elFinder::isAnimationGif($work_path)) { |
||
| 2686 | return $this->setError(elFinder::ERROR_UNSUPPORT_TYPE); |
||
| 2687 | } |
||
| 2688 | } |
||
| 2689 | |||
| 2690 | switch ($mode) { |
||
| 2691 | |||
| 2692 | View Code Duplication | case 'propresize': |
|
| 2693 | $result = $this->imgResize($work_path, $width, $height, true, true, null, $jpgQuality); |
||
| 2694 | break; |
||
| 2695 | |||
| 2696 | case 'crop': |
||
| 2697 | $result = $this->imgCrop($work_path, $width, $height, $x, $y, null, $jpgQuality); |
||
| 2698 | break; |
||
| 2699 | |||
| 2700 | case 'fitsquare': |
||
| 2701 | $result = $this->imgSquareFit($work_path, $width, $height, 'center', 'middle', ($bg ? $bg : $this->options['tmbBgColor']), null, $jpgQuality); |
||
| 2702 | break; |
||
| 2703 | |||
| 2704 | case 'rotate': |
||
| 2705 | $result = $this->imgRotate($work_path, $degree, ($bg ? $bg : $this->options['bgColorFb']), null, $jpgQuality); |
||
| 2706 | break; |
||
| 2707 | |||
| 2708 | View Code Duplication | default: |
|
| 2709 | $result = $this->imgResize($work_path, $width, $height, false, true, null, $jpgQuality); |
||
| 2710 | break; |
||
| 2711 | } |
||
| 2712 | |||
| 2713 | $ret = false; |
||
| 2714 | if ($result) { |
||
| 2715 | $this->rmTmb($file); |
||
| 2716 | $this->clearstatcache(); |
||
| 2717 | $stat = $this->stat($path); |
||
| 2718 | $fstat = stat($work_path); |
||
| 2719 | $stat['size'] = $fstat['size']; |
||
| 2720 | $stat['ts'] = $fstat['mtime']; |
||
| 2721 | if ($imgsize = getimagesize($work_path)) { |
||
| 2722 | $stat['width'] = $imgsize[0]; |
||
| 2723 | $stat['height'] = $imgsize[1]; |
||
| 2724 | $stat['mime'] = $imgsize['mime']; |
||
| 2725 | } |
||
| 2726 | if ($path !== $work_path) { |
||
| 2727 | if ($fp = fopen($work_path, 'rb')) { |
||
| 2728 | $ret = $this->saveCE($fp, $this->dirnameCE($path), $this->basenameCE($path), $stat); |
||
| 2729 | fclose($fp); |
||
| 2730 | } |
||
| 2731 | } else { |
||
| 2732 | $ret = true; |
||
| 2733 | } |
||
| 2734 | if ($ret) { |
||
| 2735 | $this->clearcache(); |
||
| 2736 | $ret = $this->stat($path); |
||
| 2737 | $ret['width'] = $stat['width']; |
||
| 2738 | $ret['height'] = $stat['height']; |
||
| 2739 | } |
||
| 2740 | } |
||
| 2741 | if ($path !== $work_path) { |
||
| 2742 | is_file($work_path) && unlink($work_path); |
||
| 2743 | } |
||
| 2744 | |||
| 2745 | return $ret; |
||
| 2746 | } |
||
| 2747 | |||
| 2748 | /** |
||
| 2749 | * Remove file/dir. |
||
| 2750 | * |
||
| 2751 | * @param string $hash file hash |
||
| 2752 | * @return bool |
||
| 2753 | * @author Dmitry (dio) Levashov |
||
| 2754 | **/ |
||
| 2755 | public function rm($hash) |
||
| 2756 | { |
||
| 2757 | return $this->commandDisabled('rm') |
||
| 2758 | ? $this->setError(elFinder::ERROR_PERM_DENIED) |
||
| 2759 | : $this->remove($this->decode($hash)); |
||
| 2760 | } |
||
| 2761 | |||
| 2762 | /** |
||
| 2763 | * Search files. |
||
| 2764 | * |
||
| 2765 | * @param string $q search string |
||
| 2766 | * @param array $mimes |
||
| 2767 | * @param null $hash |
||
| 2768 | * @return array |
||
| 2769 | * @author Dmitry (dio) Levashov |
||
| 2770 | */ |
||
| 2771 | public function search($q, $mimes, $hash = null) |
||
| 2772 | { |
||
| 2773 | $dir = null; |
||
| 2774 | if ($hash) { |
||
| 2775 | $dir = $this->decode($hash); |
||
| 2776 | $stat = $this->stat($dir); |
||
| 2777 | if (! $stat || $stat['mime'] !== 'directory' || ! $stat['read']) { |
||
| 2778 | $q = ''; |
||
| 2779 | } |
||
| 2780 | } |
||
| 2781 | if ($mimes && $this->onlyMimes) { |
||
| 2782 | $mimes = array_intersect($mimes, $this->onlyMimes); |
||
| 2783 | if (! $mimes) { |
||
| 2784 | $q = ''; |
||
| 2785 | } |
||
| 2786 | } |
||
| 2787 | $this->searchStart = time(); |
||
| 2788 | |||
| 2789 | $qs = preg_split('/"([^"]+)"| +/', $q, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); |
||
| 2790 | $query = $excludes = []; |
||
| 2791 | foreach ($qs as $_q) { |
||
| 2792 | $_q = trim($_q); |
||
| 2793 | if ($_q !== '') { |
||
| 2794 | if ($_q[0] === '-') { |
||
| 2795 | if (isset($_q[1])) { |
||
| 2796 | $excludes[] = substr($_q, 1); |
||
| 2797 | } |
||
| 2798 | } else { |
||
| 2799 | $query[] = $_q; |
||
| 2800 | } |
||
| 2801 | } |
||
| 2802 | } |
||
| 2803 | if (! $query) { |
||
| 2804 | $q = ''; |
||
| 2805 | } else { |
||
| 2806 | $q = implode(' ', $query); |
||
| 2807 | $this->doSearchCurrentQuery = [ |
||
| 2808 | 'q' => $q, |
||
| 2809 | 'excludes' => $excludes, |
||
| 2810 | ]; |
||
| 2811 | } |
||
| 2812 | |||
| 2813 | // valided regex $this->options['searchExDirReg'] |
||
| 2814 | View Code Duplication | if ($this->options['searchExDirReg']) { |
|
| 2815 | if (false === preg_match($this->options['searchExDirReg'], '')) { |
||
| 2816 | $this->options['searchExDirReg'] = ''; |
||
| 2817 | } |
||
| 2818 | } |
||
| 2819 | |||
| 2820 | return ($q === '' || $this->commandDisabled('search')) |
||
| 2821 | ? [] |
||
| 2822 | : $this->doSearch(is_null($dir) ? $this->root : $dir, $q, $mimes); |
||
| 2823 | } |
||
| 2824 | |||
| 2825 | /** |
||
| 2826 | * Return image dimensions. |
||
| 2827 | * |
||
| 2828 | * @param string $hash file hash |
||
| 2829 | * @return array |
||
| 2830 | * @author Dmitry (dio) Levashov |
||
| 2831 | **/ |
||
| 2832 | public function dimensions($hash) |
||
| 2833 | { |
||
| 2834 | if (($file = $this->file($hash)) == false) { |
||
| 2835 | return false; |
||
| 2836 | } |
||
| 2837 | |||
| 2838 | return $this->convEncOut($this->_dimensions($this->convEncIn($this->decode($hash)), $file['mime'])); |
||
| 2839 | } |
||
| 2840 | |||
| 2841 | /** |
||
| 2842 | * Return has subdirs. |
||
| 2843 | * |
||
| 2844 | * @param string $hash file hash |
||
| 2845 | * @return bool |
||
| 2846 | * @author Naoki Sawada |
||
| 2847 | **/ |
||
| 2848 | public function subdirs($hash) |
||
| 2849 | { |
||
| 2850 | return (bool) $this->subdirsCE($this->decode($hash)); |
||
| 2851 | } |
||
| 2852 | |||
| 2853 | /** |
||
| 2854 | * Return content URL (for netmout volume driver) |
||
| 2855 | * If file.url == 1 requests from JavaScript client with XHR. |
||
| 2856 | * |
||
| 2857 | * @param string $hash file hash |
||
| 2858 | * @param array $options options array |
||
| 2859 | * @return bool|string |
||
| 2860 | * @author Naoki Sawada |
||
| 2861 | */ |
||
| 2862 | public function getContentUrl($hash, $options = []) |
||
| 2863 | { |
||
| 2864 | if (($file = $this->file($hash)) === false) { |
||
| 2865 | return false; |
||
| 2866 | } |
||
| 2867 | if (empty($file['url'])) { |
||
| 2868 | if ($this->URL) { |
||
| 2869 | $path = str_replace($this->separator, '/', substr($this->decode($hash), strlen($this->root) + 1)); |
||
| 2870 | if ($this->encoding) { |
||
| 2871 | $path = $this->convEncIn($path, true); |
||
| 2872 | } |
||
| 2873 | $path = str_replace('%2F', '/', rawurlencode($path)); |
||
| 2874 | |||
| 2875 | return $this->URL.$path; |
||
| 2876 | } |
||
| 2877 | |||
| 2878 | return false; |
||
| 2879 | } else { |
||
| 2880 | if ($file['url'] != 1) { |
||
| 2881 | return $file['url']; |
||
| 2882 | } elseif (! empty($options['temporary']) && $this->tmpLinkPath) { |
||
| 2883 | $name = 'temp_'.md5($hash); |
||
| 2884 | $path = $this->tmpLinkPath.DIRECTORY_SEPARATOR.$name; |
||
| 2885 | $contents = $this->getContents($hash); |
||
| 2886 | $gc = create_function('$p,$t', 'foreach(glob($p) as $f) { (filemtime($f) < (time() - $t)) && unlink($f); }'); |
||
| 2887 | /*$gc = function($p,$t) { |
||
| 2888 | foreach(glob($p) as $f) { |
||
| 2889 | (filemtime($f) < (time() - $t)) && unlink($f); |
||
| 2890 | } |
||
| 2891 | };*/ |
||
| 2892 | register_shutdown_function($gc, $this->tmpLinkPath.DIRECTORY_SEPARATOR.'temp_*', elFinder::$tmpLinkLifeTime); |
||
| 2893 | if (file_put_contents($path, $this->getContents($hash))) { |
||
| 2894 | return $this->tmpLinkUrl.'/'.$name; |
||
| 2895 | } |
||
| 2896 | } |
||
| 2897 | |||
| 2898 | return false; |
||
| 2899 | } |
||
| 2900 | } |
||
| 2901 | |||
| 2902 | /** |
||
| 2903 | * Return temp path. |
||
| 2904 | * |
||
| 2905 | * @return string |
||
| 2906 | * @author Naoki Sawada |
||
| 2907 | */ |
||
| 2908 | public function getTempPath() |
||
| 2909 | { |
||
| 2910 | $tempPath = null; |
||
| 2911 | if (isset($this->tmpPath) && $this->tmpPath && is_writable($this->tmpPath)) { |
||
| 2912 | $tempPath = $this->tmpPath; |
||
| 2913 | } elseif (isset($this->tmp) && $this->tmp && is_writable($this->tmp)) { |
||
| 2914 | $tempPath = $this->tmp; |
||
| 2915 | } elseif (function_exists('sys_get_temp_dir')) { |
||
| 2916 | $tempPath = sys_get_temp_dir(); |
||
| 2917 | } elseif ($this->tmbPathWritable) { |
||
| 2918 | $tempPath = $this->tmbPath; |
||
| 2919 | } |
||
| 2920 | if ($tempPath && DIRECTORY_SEPARATOR !== '/') { |
||
| 2921 | $tempPath = str_replace('/', DIRECTORY_SEPARATOR, $tempPath); |
||
| 2922 | } |
||
| 2923 | |||
| 2924 | return $tempPath; |
||
| 2925 | } |
||
| 2926 | |||
| 2927 | /** |
||
| 2928 | * (Make &) Get upload taget dirctory hash. |
||
| 2929 | * |
||
| 2930 | * @param string $baseTargetHash |
||
| 2931 | * @param string $path |
||
| 2932 | * @param array $result |
||
| 2933 | * @return bool|string |
||
| 2934 | * @author Naoki Sawada |
||
| 2935 | */ |
||
| 2936 | public function getUploadTaget($baseTargetHash, $path, &$result) |
||
| 2937 | { |
||
| 2938 | $base = $this->decode($baseTargetHash); |
||
| 2939 | $targetHash = $baseTargetHash; |
||
| 2940 | $path = ltrim($path, $this->separator); |
||
| 2941 | $dirs = explode($this->separator, $path); |
||
| 2942 | array_pop($dirs); |
||
| 2943 | foreach ($dirs as $dir) { |
||
| 2944 | $targetPath = $this->joinPathCE($base, $dir); |
||
| 2945 | if (! $_realpath = $this->realpath($this->encode($targetPath))) { |
||
| 2946 | if ($stat = $this->mkdir($targetHash, $dir)) { |
||
| 2947 | $result['added'][] = $stat; |
||
| 2948 | $targetHash = $stat['hash']; |
||
| 2949 | $base = $this->decode($targetHash); |
||
| 2950 | } else { |
||
| 2951 | return false; |
||
| 2952 | } |
||
| 2953 | } else { |
||
| 2954 | $targetHash = $this->encode($_realpath); |
||
| 2955 | if ($this->dir($targetHash)) { |
||
| 2956 | $base = $this->decode($targetHash); |
||
| 2957 | } else { |
||
| 2958 | return false; |
||
| 2959 | } |
||
| 2960 | } |
||
| 2961 | } |
||
| 2962 | |||
| 2963 | return $targetHash; |
||
| 2964 | } |
||
| 2965 | |||
| 2966 | /** |
||
| 2967 | * Return this uploadMaxSize value. |
||
| 2968 | * |
||
| 2969 | * @return int |
||
| 2970 | * @author Naoki Sawada |
||
| 2971 | */ |
||
| 2972 | public function getUploadMaxSize() |
||
| 2973 | { |
||
| 2974 | return $this->uploadMaxSize; |
||
| 2975 | } |
||
| 2976 | |||
| 2977 | public function setUploadOverwrite($var) |
||
| 2978 | { |
||
| 2979 | $this->uploadOverwrite = (bool) $var; |
||
| 2980 | } |
||
| 2981 | |||
| 2982 | /** |
||
| 2983 | * Image file utility. |
||
| 2984 | * |
||
| 2985 | * @param string $mode 'resize', 'rotate', 'propresize', 'crop', 'fitsquare' |
||
| 2986 | * @param string $src Image file local path |
||
| 2987 | * @param array $options excute options |
||
| 2988 | * @return bool |
||
| 2989 | * @author Naoki Sawada |
||
| 2990 | */ |
||
| 2991 | public function imageUtil($mode, $src, $options = []) |
||
| 2992 | { |
||
| 2993 | if (! isset($options['jpgQuality'])) { |
||
| 2994 | $options['jpgQuality'] = intval($this->options['jpgQuality']); |
||
| 2995 | } |
||
| 2996 | if (! isset($options['bgcolor'])) { |
||
| 2997 | $options['bgcolor'] = '#ffffff'; |
||
| 2998 | } |
||
| 2999 | if (! isset($options['bgColorFb'])) { |
||
| 3000 | $options['bgColorFb'] = $this->options['bgColorFb']; |
||
| 3001 | } |
||
| 3002 | |||
| 3003 | // check 'width' ,'height' |
||
| 3004 | if (in_array($mode, ['resize', 'propresize', 'crop', 'fitsquare'])) { |
||
| 3005 | if (empty($options['width']) || empty($options['height'])) { |
||
| 3006 | return false; |
||
| 3007 | } |
||
| 3008 | } |
||
| 3009 | |||
| 3010 | switch ($mode) { |
||
| 3011 | case 'rotate': |
||
| 3012 | if (empty($options['degree'])) { |
||
| 3013 | return true; |
||
| 3014 | } |
||
| 3015 | |||
| 3016 | return (bool) $this->imgRotate($src, $options['degree'], $options['bgColorFb'], null, $options['jpgQuality']); |
||
| 3017 | |||
| 3018 | View Code Duplication | case 'resize': |
|
| 3019 | return (bool) $this->imgResize($src, $options['width'], $options['height'], false, true, null, $options['jpgQuality'], $options); |
||
| 3020 | |||
| 3021 | View Code Duplication | case 'propresize': |
|
| 3022 | return (bool) $this->imgResize($src, $options['width'], $options['height'], true, true, null, $options['jpgQuality'], $options); |
||
| 3023 | |||
| 3024 | case 'crop': |
||
| 3025 | if (isset($options['x']) && isset($options['y'])) { |
||
| 3026 | return (bool) $this->imgCrop($src, $options['width'], $options['height'], $options['x'], $options['y'], null, $options['jpgQuality']); |
||
| 3027 | } |
||
| 3028 | break; |
||
| 3029 | |||
| 3030 | case 'fitsquare': |
||
| 3031 | return (bool) $this->imgSquareFit($src, $options['width'], $options['height'], 'center', 'middle', $options['bgcolor'], null, $options['jpgQuality']); |
||
| 3032 | |||
| 3033 | } |
||
| 3034 | |||
| 3035 | return false; |
||
| 3036 | } |
||
| 3037 | |||
| 3038 | /** |
||
| 3039 | * Convert Video To Image by ffmpeg. |
||
| 3040 | * |
||
| 3041 | * @param $file video source file path |
||
| 3042 | * @param $stat file stat array |
||
| 3043 | * @return bool |
||
| 3044 | * @author Naoki Sawada |
||
| 3045 | */ |
||
| 3046 | public function ffmpegToImg($file, $stat) |
||
| 3047 | { |
||
| 3048 | $name = basename($file); |
||
| 3049 | $path = dirname($file); |
||
| 3050 | $tmp = $path.DIRECTORY_SEPARATOR.md5($name); |
||
| 3051 | $GLOBALS['elFinderTempFiles'][] = $tmp; // regist to remove at the end |
||
| 3052 | if (rename($file, $tmp)) { |
||
| 3053 | // specific start time by file name (xxx^[sec].[extention] - video^3.mp4) |
||
| 3054 | if (preg_match('/\^(\d+(?:\.\d+)?)\.[^.]+$/', $stat['name'], $_m)) { |
||
| 3055 | $ss = $_m[1]; |
||
| 3056 | } else { |
||
| 3057 | $ss = $this->options['tmbVideoConvSec']; |
||
| 3058 | } |
||
| 3059 | $cmd = sprintf('ffmpeg -i %s -ss 00:00:%.3f -vframes 1 -f image2 %s', escapeshellarg($tmp), $ss, escapeshellarg($file)); |
||
| 3060 | $r = $this->procExec($cmd); |
||
| 3061 | unlink($tmp); |
||
| 3062 | |||
| 3063 | return $r === 0; |
||
| 3064 | } |
||
| 3065 | |||
| 3066 | return false; |
||
| 3067 | } |
||
| 3068 | |||
| 3069 | /** |
||
| 3070 | * Return new unique name based on file name and suffix. |
||
| 3071 | * |
||
| 3072 | * @param $dir |
||
| 3073 | * @param $name |
||
| 3074 | * @param string $suffix suffix append to name |
||
| 3075 | * @param bool $checkNum |
||
| 3076 | * @param int $start |
||
| 3077 | * @return string |
||
| 3078 | * @internal param string $path file path |
||
| 3079 | * @author Dmitry (dio) Levashov |
||
| 3080 | */ |
||
| 3081 | public function uniqueName($dir, $name, $suffix = ' copy', $checkNum = true, $start = 1) |
||
| 3082 | { |
||
| 3083 | $ext = ''; |
||
| 3084 | |||
| 3085 | if (preg_match('/\.((tar\.(gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(gz|bz2)|[a-z0-9]{1,4})$/i', $name, $m)) { |
||
| 3086 | $ext = '.'.$m[1]; |
||
| 3087 | $name = substr($name, 0, strlen($name) - strlen($m[0])); |
||
| 3088 | } |
||
| 3089 | |||
| 3090 | if ($checkNum && preg_match('/('.preg_quote($suffix, '/').')(\d*)$/i', $name, $m)) { |
||
| 3091 | $i = (int) $m[2]; |
||
| 3092 | $name = substr($name, 0, strlen($name) - strlen($m[2])); |
||
| 3093 | } else { |
||
| 3094 | $i = $start; |
||
| 3095 | $name .= $suffix; |
||
| 3096 | } |
||
| 3097 | $max = $i + 100000; |
||
| 3098 | |||
| 3099 | while ($i <= $max) { |
||
| 3100 | $n = $name.($i > 0 ? sprintf($this->options['uniqueNumFormat'], $i) : '').$ext; |
||
| 3101 | |||
| 3102 | if (! $this->isNameExists($this->joinPathCE($dir, $n))) { |
||
| 3103 | $this->clearcache(); |
||
| 3104 | |||
| 3105 | return $n; |
||
| 3106 | } |
||
| 3107 | $i++; |
||
| 3108 | } |
||
| 3109 | |||
| 3110 | return $name.md5($dir).$ext; |
||
| 3111 | } |
||
| 3112 | |||
| 3113 | /** |
||
| 3114 | * Converts character encoding from UTF-8 to server's one. |
||
| 3115 | * |
||
| 3116 | * @param mixed $var target string or array var |
||
| 3117 | * @param bool $restoreLocale do retore global locale, default is false |
||
| 3118 | * @param string $unknown replaces character for unknown |
||
| 3119 | * @return mixed |
||
| 3120 | * @author Naoki Sawada |
||
| 3121 | */ |
||
| 3122 | public function convEncIn($var = null, $restoreLocale = false, $unknown = '_') |
||
| 3123 | { |
||
| 3124 | return (! $this->encoding) ? $var : $this->convEnc($var, 'UTF-8', $this->encoding, $this->options['locale'], $restoreLocale, $unknown); |
||
| 3125 | } |
||
| 3126 | |||
| 3127 | /** |
||
| 3128 | * Converts character encoding from server's one to UTF-8. |
||
| 3129 | * |
||
| 3130 | * @param mixed $var target string or array var |
||
| 3131 | * @param bool $restoreLocale do retore global locale, default is true |
||
| 3132 | * @param string $unknown replaces character for unknown |
||
| 3133 | * @return mixed |
||
| 3134 | * @author Naoki Sawada |
||
| 3135 | */ |
||
| 3136 | public function convEncOut($var = null, $restoreLocale = true, $unknown = '_') |
||
| 3137 | { |
||
| 3138 | return (! $this->encoding) ? $var : $this->convEnc($var, $this->encoding, 'UTF-8', $this->options['locale'], $restoreLocale, $unknown); |
||
| 3139 | } |
||
| 3140 | |||
| 3141 | /** |
||
| 3142 | * Get image size array with `dimensions`. |
||
| 3143 | * |
||
| 3144 | * @param string $path path need convert encoding to server encoding |
||
| 3145 | * @param string $mime file mime type |
||
| 3146 | * @return array|false |
||
| 3147 | */ |
||
| 3148 | public function getImageSize($path, $mime = '') |
||
| 3149 | { |
||
| 3150 | $size = false; |
||
| 3151 | if ($mime === '' || strtolower(substr($mime, 0, 5)) === 'image') { |
||
| 3152 | if ($work = $this->getWorkFile($path)) { |
||
| 3153 | if ($size = getimagesize($work)) { |
||
| 3154 | $size['dimensions'] = $size[0].'x'.$size[1]; |
||
| 3155 | } |
||
| 3156 | } |
||
| 3157 | is_file($work) && unlink($work); |
||
| 3158 | } |
||
| 3159 | |||
| 3160 | return $size; |
||
| 3161 | } |
||
| 3162 | |||
| 3163 | /** |
||
| 3164 | * Remove directory recursive on local file system. |
||
| 3165 | * |
||
| 3166 | * @param string $dir Target dirctory path |
||
| 3167 | * @return bool |
||
| 3168 | * @author Naoki Sawada |
||
| 3169 | */ |
||
| 3170 | public function rmdirRecursive($dir) |
||
| 3171 | { |
||
| 3172 | return self::localRmdirRecursive($dir); |
||
| 3173 | } |
||
| 3174 | |||
| 3175 | /*********************************************************************/ |
||
| 3176 | /* INITIALIZATION */ |
||
| 3177 | /*********************************************************************/ |
||
| 3178 | |||
| 3179 | /** |
||
| 3180 | * Prepare driver before mount volume. |
||
| 3181 | * Return true if volume is ready. |
||
| 3182 | * |
||
| 3183 | * @return bool |
||
| 3184 | * @author Dmitry (dio) Levashov |
||
| 3185 | **/ |
||
| 3186 | protected function init() |
||
| 3187 | { |
||
| 3188 | return true; |
||
| 3189 | } |
||
| 3190 | |||
| 3191 | /** |
||
| 3192 | * Configure after successfull mount. |
||
| 3193 | * By default set thumbnails path and image manipulation library. |
||
| 3194 | * |
||
| 3195 | * @return void |
||
| 3196 | * @author Dmitry (dio) Levashov |
||
| 3197 | **/ |
||
| 3198 | protected function configure() |
||
| 3199 | { |
||
| 3200 | // set thumbnails path |
||
| 3201 | $path = $this->options['tmbPath']; |
||
| 3202 | if ($path) { |
||
| 3203 | View Code Duplication | if (! file_exists($path)) { |
|
| 3204 | if (mkdir($path)) { |
||
| 3205 | chmod($path, $this->options['tmbPathMode']); |
||
| 3206 | } else { |
||
| 3207 | $path = ''; |
||
| 3208 | } |
||
| 3209 | } |
||
| 3210 | |||
| 3211 | if (is_dir($path) && is_readable($path)) { |
||
| 3212 | $this->tmbPath = $path; |
||
| 3213 | $this->tmbPathWritable = is_writable($path); |
||
| 3214 | } |
||
| 3215 | } |
||
| 3216 | // set resouce path |
||
| 3217 | if (! is_dir($this->options['resourcePath'])) { |
||
| 3218 | $this->options['resourcePath'] = dirname(__FILE__).DIRECTORY_SEPARATOR.'resources'; |
||
| 3219 | } |
||
| 3220 | |||
| 3221 | // set image manipulation library |
||
| 3222 | $type = preg_match('/^(imagick|gd|convert|auto)$/i', $this->options['imgLib']) |
||
| 3223 | ? strtolower($this->options['imgLib']) |
||
| 3224 | : 'auto'; |
||
| 3225 | |||
| 3226 | $imgLibFallback = extension_loaded('imagick') ? 'imagick' : (function_exists('gd_info') ? 'gd' : ''); |
||
| 3227 | if (($type === 'imagick' || $type === 'auto') && extension_loaded('imagick')) { |
||
| 3228 | $this->imgLib = 'imagick'; |
||
| 3229 | } elseif (($type === 'gd' || $type === 'auto') && function_exists('gd_info')) { |
||
| 3230 | $this->imgLib = 'gd'; |
||
| 3231 | } else { |
||
| 3232 | $convertCache = 'imgLibConvert'; |
||
| 3233 | if (($convertCmd = $this->session->get($convertCache, false)) !== false) { |
||
| 3234 | $this->imgLib = $convertCmd; |
||
| 3235 | } else { |
||
| 3236 | $this->imgLib = ($this->procExec('convert -version') === 0) ? 'convert' : ''; |
||
| 3237 | $this->session->set($convertCache, $this->imgLib); |
||
| 3238 | } |
||
| 3239 | } |
||
| 3240 | if ($type !== 'auto' && $this->imgLib === '') { |
||
| 3241 | // fallback |
||
| 3242 | $this->imgLib = extension_loaded('imagick') ? 'imagick' : (function_exists('gd_info') ? 'gd' : ''); |
||
| 3243 | } |
||
| 3244 | |||
| 3245 | // check video to img converter |
||
| 3246 | View Code Duplication | if (! empty($this->options['imgConverter']) && is_array($this->options['imgConverter'])) { |
|
| 3247 | foreach ($this->options['imgConverter'] as $_type => $_converter) { |
||
| 3248 | if (isset($_converter['func'])) { |
||
| 3249 | $this->imgConverter[strtolower($_type)] = $_converter; |
||
| 3250 | } |
||
| 3251 | } |
||
| 3252 | } |
||
| 3253 | if (! isset($this->imgConverter['video'])) { |
||
| 3254 | $videoLibCache = 'videoLib'; |
||
| 3255 | if (($videoLibCmd = $this->session->get($videoLibCache, false)) === false) { |
||
| 3256 | $videoLibCmd = ($this->procExec('ffmpeg -version') === 0) ? 'ffmpeg' : ''; |
||
| 3257 | $this->session->set($videoLibCache, $videoLibCmd); |
||
| 3258 | } |
||
| 3259 | if ($videoLibCmd) { |
||
| 3260 | $this->imgConverter['video'] = [ |
||
| 3261 | 'func' => [$this, $videoLibCmd.'ToImg'], |
||
| 3262 | 'maxlen' => $this->options['tmbVideoConvLen'], |
||
| 3263 | ]; |
||
| 3264 | } |
||
| 3265 | } |
||
| 3266 | |||
| 3267 | // check archivers |
||
| 3268 | if (empty($this->archivers['create'])) { |
||
| 3269 | $this->disabled[] = 'archive'; |
||
| 3270 | } |
||
| 3271 | if (empty($this->archivers['extract'])) { |
||
| 3272 | $this->disabled[] = 'extract'; |
||
| 3273 | } |
||
| 3274 | $_arc = $this->getArchivers(); |
||
| 3275 | if (empty($_arc['create'])) { |
||
| 3276 | $this->disabled[] = 'zipdl'; |
||
| 3277 | } |
||
| 3278 | |||
| 3279 | // check 'statOwner' for command `chmod` |
||
| 3280 | if (empty($this->options['statOwner'])) { |
||
| 3281 | $this->disabled[] = 'chmod'; |
||
| 3282 | } |
||
| 3283 | |||
| 3284 | // check 'mimeMap' |
||
| 3285 | if (! is_array($this->options['mimeMap'])) { |
||
| 3286 | $this->options['mimeMap'] = []; |
||
| 3287 | } |
||
| 3288 | View Code Duplication | if (is_array($this->options['staticMineMap']) && $this->options['staticMineMap']) { |
|
| 3289 | $this->options['mimeMap'] = array_merge($this->options['mimeMap'], $this->options['staticMineMap']); |
||
| 3290 | } |
||
| 3291 | View Code Duplication | if (is_array($this->options['additionalMimeMap']) && $this->options['additionalMimeMap']) { |
|
| 3292 | $this->options['mimeMap'] = array_merge($this->options['mimeMap'], $this->options['additionalMimeMap']); |
||
| 3293 | } |
||
| 3294 | |||
| 3295 | // check 'url' in disabled commands |
||
| 3296 | if (in_array('url', $this->disabled)) { |
||
| 3297 | $this->disabledGetUrl = true; |
||
| 3298 | } |
||
| 3299 | |||
| 3300 | // set run time setting uploadOverwrite |
||
| 3301 | $this->uploadOverwrite = $this->options['uploadOverwrite']; |
||
| 3302 | } |
||
| 3303 | |||
| 3304 | /** |
||
| 3305 | * @deprecated |
||
| 3306 | */ |
||
| 3307 | protected function sessionRestart() |
||
| 3308 | { |
||
| 3309 | $this->sessionCache = $this->session->start()->get($this->id, []); |
||
| 3310 | |||
| 3311 | return true; |
||
| 3312 | } |
||
| 3313 | |||
| 3314 | /** |
||
| 3315 | * Save error message. |
||
| 3316 | * |
||
| 3317 | * @param array error |
||
| 3318 | * @return false |
||
| 3319 | * @author Naoki Sawada |
||
| 3320 | **/ |
||
| 3321 | protected function setError() |
||
| 3322 | { |
||
| 3323 | $this->error = []; |
||
| 3324 | $this->addError(func_get_args()); |
||
| 3325 | |||
| 3326 | return false; |
||
| 3327 | } |
||
| 3328 | |||
| 3329 | /** |
||
| 3330 | * Add error message. |
||
| 3331 | * |
||
| 3332 | * @param array error |
||
| 3333 | * @return false |
||
| 3334 | * @author Dmitry(dio) Levashov |
||
| 3335 | **/ |
||
| 3336 | protected function addError() |
||
| 3337 | { |
||
| 3338 | foreach (func_get_args() as $err) { |
||
| 3339 | if (is_array($err)) { |
||
| 3340 | $this->error = array_merge($this->error, $err); |
||
| 3341 | } else { |
||
| 3342 | $this->error[] = $err; |
||
| 3343 | } |
||
| 3344 | } |
||
| 3345 | |||
| 3346 | return false; |
||
| 3347 | } |
||
| 3348 | |||
| 3349 | /*********************************************************************/ |
||
| 3350 | /* FS API */ |
||
| 3351 | /*********************************************************************/ |
||
| 3352 | |||
| 3353 | /***************** server encoding support *******************/ |
||
| 3354 | |||
| 3355 | /** |
||
| 3356 | * Return parent directory path (with convert encoding). |
||
| 3357 | * |
||
| 3358 | * @param string $path file path |
||
| 3359 | * @return string |
||
| 3360 | * @author Naoki Sawada |
||
| 3361 | **/ |
||
| 3362 | protected function dirnameCE($path) |
||
| 3363 | { |
||
| 3364 | $dirname = (! $this->encoding) ? $this->_dirname($path) : $this->convEncOut($this->_dirname($this->convEncIn($path))); |
||
| 3365 | // check to infinite loop prevention |
||
| 3366 | return ($dirname != $path) ? $dirname : ''; |
||
| 3367 | } |
||
| 3368 | |||
| 3369 | /** |
||
| 3370 | * Return file name (with convert encoding). |
||
| 3371 | * |
||
| 3372 | * @param string $path file path |
||
| 3373 | * @return string |
||
| 3374 | * @author Naoki Sawada |
||
| 3375 | **/ |
||
| 3376 | protected function basenameCE($path) |
||
| 3377 | { |
||
| 3378 | return (! $this->encoding) ? $this->_basename($path) : $this->convEncOut($this->_basename($this->convEncIn($path))); |
||
| 3379 | } |
||
| 3380 | |||
| 3381 | /** |
||
| 3382 | * Join dir name and file name and return full path. (with convert encoding) |
||
| 3383 | * Some drivers (db) use int as path - so we give to concat path to driver itself. |
||
| 3384 | * |
||
| 3385 | * @param string $dir dir path |
||
| 3386 | * @param string $name file name |
||
| 3387 | * @return string |
||
| 3388 | * @author Naoki Sawada |
||
| 3389 | **/ |
||
| 3390 | protected function joinPathCE($dir, $name) |
||
| 3391 | { |
||
| 3392 | return (! $this->encoding) ? $this->_joinPath($dir, $name) : $this->convEncOut($this->_joinPath($this->convEncIn($dir), $this->convEncIn($name))); |
||
| 3393 | } |
||
| 3394 | |||
| 3395 | /** |
||
| 3396 | * Return normalized path (with convert encoding). |
||
| 3397 | * |
||
| 3398 | * @param string $path file path |
||
| 3399 | * @return string |
||
| 3400 | * @author Naoki Sawada |
||
| 3401 | **/ |
||
| 3402 | protected function normpathCE($path) |
||
| 3403 | { |
||
| 3404 | return (! $this->encoding) ? $this->_normpath($path) : $this->convEncOut($this->_normpath($this->convEncIn($path))); |
||
| 3405 | } |
||
| 3406 | |||
| 3407 | /** |
||
| 3408 | * Return file path related to root dir (with convert encoding). |
||
| 3409 | * |
||
| 3410 | * @param string $path file path |
||
| 3411 | * @return string |
||
| 3412 | * @author Naoki Sawada |
||
| 3413 | **/ |
||
| 3414 | protected function relpathCE($path) |
||
| 3415 | { |
||
| 3416 | return (! $this->encoding) ? $this->_relpath($path) : $this->convEncOut($this->_relpath($this->convEncIn($path))); |
||
| 3417 | } |
||
| 3418 | |||
| 3419 | /** |
||
| 3420 | * Convert path related to root dir into real path (with convert encoding). |
||
| 3421 | * |
||
| 3422 | * @param string $path rel file path |
||
| 3423 | * @return string |
||
| 3424 | * @author Naoki Sawada |
||
| 3425 | **/ |
||
| 3426 | protected function abspathCE($path) |
||
| 3427 | { |
||
| 3428 | return (! $this->encoding) ? $this->_abspath($path) : $this->convEncOut($this->_abspath($this->convEncIn($path))); |
||
| 3429 | } |
||
| 3430 | |||
| 3431 | /** |
||
| 3432 | * Return true if $path is children of $parent (with convert encoding). |
||
| 3433 | * |
||
| 3434 | * @param string $path path to check |
||
| 3435 | * @param string $parent parent path |
||
| 3436 | * @return bool |
||
| 3437 | * @author Naoki Sawada |
||
| 3438 | **/ |
||
| 3439 | protected function inpathCE($path, $parent) |
||
| 3440 | { |
||
| 3441 | return (! $this->encoding) ? $this->_inpath($path, $parent) : $this->convEncOut($this->_inpath($this->convEncIn($path), $this->convEncIn($parent))); |
||
| 3442 | } |
||
| 3443 | |||
| 3444 | /** |
||
| 3445 | * Open file and return file pointer (with convert encoding). |
||
| 3446 | * |
||
| 3447 | * @param string $path file path |
||
| 3448 | * @param string $mode |
||
| 3449 | * @return false|resource |
||
| 3450 | * @internal param bool $write open file for writing |
||
| 3451 | * @author Naoki Sawada |
||
| 3452 | */ |
||
| 3453 | protected function fopenCE($path, $mode = 'rb') |
||
| 3454 | { |
||
| 3455 | return (! $this->encoding) ? $this->_fopen($path, $mode) : $this->convEncOut($this->_fopen($this->convEncIn($path), $mode)); |
||
| 3456 | } |
||
| 3457 | |||
| 3458 | /** |
||
| 3459 | * Close opened file (with convert encoding). |
||
| 3460 | * |
||
| 3461 | * @param resource $fp file pointer |
||
| 3462 | * @param string $path file path |
||
| 3463 | * @return bool |
||
| 3464 | * @author Naoki Sawada |
||
| 3465 | **/ |
||
| 3466 | protected function fcloseCE($fp, $path = '') |
||
| 3467 | { |
||
| 3468 | return (! $this->encoding) ? $this->_fclose($fp, $path) : $this->convEncOut($this->_fclose($fp, $this->convEncIn($path))); |
||
| 3469 | } |
||
| 3470 | |||
| 3471 | /** |
||
| 3472 | * Create new file and write into it from file pointer. (with convert encoding) |
||
| 3473 | * Return new file path or false on error. |
||
| 3474 | * |
||
| 3475 | * @param resource $fp file pointer |
||
| 3476 | * @param string $dir target dir path |
||
| 3477 | * @param string $name file name |
||
| 3478 | * @param array $stat file stat (required by some virtual fs) |
||
| 3479 | * @return bool|string |
||
| 3480 | * @author Naoki Sawada |
||
| 3481 | **/ |
||
| 3482 | protected function saveCE($fp, $dir, $name, $stat) |
||
| 3483 | { |
||
| 3484 | return (! $this->encoding) ? $this->_save($fp, $dir, $name, $stat) : $this->convEncOut($this->_save($fp, $this->convEncIn($dir), $this->convEncIn($name), $this->convEncIn($stat))); |
||
| 3485 | } |
||
| 3486 | |||
| 3487 | /** |
||
| 3488 | * Return true if path is dir and has at least one childs directory (with convert encoding). |
||
| 3489 | * |
||
| 3490 | * @param string $path dir path |
||
| 3491 | * @return bool |
||
| 3492 | * @author Naoki Sawada |
||
| 3493 | **/ |
||
| 3494 | protected function subdirsCE($path) |
||
| 3495 | { |
||
| 3496 | View Code Duplication | if ($this->sessionCaching['subdirs']) { |
|
| 3497 | if (isset($this->sessionCache['subdirs'][$path]) && ! $this->isMyReload()) { |
||
| 3498 | return $this->sessionCache['subdirs'][$path]; |
||
| 3499 | } |
||
| 3500 | } |
||
| 3501 | $hasdir = (bool) ((! $this->encoding) ? $this->_subdirs($path) : $this->convEncOut($this->_subdirs($this->convEncIn($path)))); |
||
| 3502 | $this->updateSubdirsCache($path, $hasdir); |
||
| 3503 | |||
| 3504 | return $hasdir; |
||
| 3505 | } |
||
| 3506 | |||
| 3507 | /** |
||
| 3508 | * Return files list in directory (with convert encoding). |
||
| 3509 | * |
||
| 3510 | * @param string $path dir path |
||
| 3511 | * @return array |
||
| 3512 | * @author Naoki Sawada |
||
| 3513 | **/ |
||
| 3514 | protected function scandirCE($path) |
||
| 3515 | { |
||
| 3516 | return (! $this->encoding) ? $this->_scandir($path) : $this->convEncOut($this->_scandir($this->convEncIn($path))); |
||
| 3517 | } |
||
| 3518 | |||
| 3519 | /** |
||
| 3520 | * Create symlink (with convert encoding). |
||
| 3521 | * |
||
| 3522 | * @param string $source file to link to |
||
| 3523 | * @param string $targetDir folder to create link in |
||
| 3524 | * @param string $name symlink name |
||
| 3525 | * @return bool |
||
| 3526 | * @author Naoki Sawada |
||
| 3527 | **/ |
||
| 3528 | protected function symlinkCE($source, $targetDir, $name) |
||
| 3529 | { |
||
| 3530 | return (! $this->encoding) ? $this->_symlink($source, $targetDir, $name) : $this->convEncOut($this->_symlink($this->convEncIn($source), $this->convEncIn($targetDir), $this->convEncIn($name))); |
||
| 3531 | } |
||
| 3532 | |||
| 3533 | /***************** paths *******************/ |
||
| 3534 | |||
| 3535 | /** |
||
| 3536 | * Encode path into hash. |
||
| 3537 | * |
||
| 3538 | * @param string file path |
||
| 3539 | * @return string |
||
| 3540 | * @author Dmitry (dio) Levashov |
||
| 3541 | * @author Troex Nevelin |
||
| 3542 | **/ |
||
| 3543 | protected function encode($path) |
||
| 3544 | { |
||
| 3545 | if ($path !== '') { |
||
| 3546 | |||
| 3547 | // cut ROOT from $path for security reason, even if hacker decodes the path he will not know the root |
||
| 3548 | $p = $this->relpathCE($path); |
||
| 3549 | // if reqesting root dir $path will be empty, then assign '/' as we cannot leave it blank for crypt |
||
| 3550 | if ($p === '') { |
||
| 3551 | $p = $this->separator; |
||
| 3552 | } |
||
| 3553 | |||
| 3554 | // TODO crypt path and return hash |
||
| 3555 | $hash = $this->crypt($p); |
||
| 3556 | // hash is used as id in HTML that means it must contain vaild chars |
||
| 3557 | // make base64 html safe and append prefix in begining |
||
| 3558 | $hash = strtr(base64_encode($hash), '+/=', '-_.'); |
||
| 3559 | // remove dots '.' at the end, before it was '=' in base64 |
||
| 3560 | $hash = rtrim($hash, '.'); |
||
| 3561 | // append volume id to make hash unique |
||
| 3562 | return $this->id.$hash; |
||
| 3563 | } |
||
| 3564 | //TODO: Add return statement here |
||
| 3565 | } |
||
| 3566 | |||
| 3567 | /** |
||
| 3568 | * Decode path from hash. |
||
| 3569 | * |
||
| 3570 | * @param string file hash |
||
| 3571 | * @return string |
||
| 3572 | * @author Dmitry (dio) Levashov |
||
| 3573 | * @author Troex Nevelin |
||
| 3574 | **/ |
||
| 3575 | protected function decode($hash) |
||
| 3576 | { |
||
| 3577 | if (strpos($hash, $this->id) === 0) { |
||
| 3578 | // cut volume id after it was prepended in encode |
||
| 3579 | $h = substr($hash, strlen($this->id)); |
||
| 3580 | // replace HTML safe base64 to normal |
||
| 3581 | $h = base64_decode(strtr($h, '-_.', '+/=')); |
||
| 3582 | // TODO uncrypt hash and return path |
||
| 3583 | $path = $this->uncrypt($h); |
||
| 3584 | // append ROOT to path after it was cut in encode |
||
| 3585 | return $this->abspathCE($path); //$this->root.($path === $this->separator ? '' : $this->separator.$path); |
||
| 3586 | } |
||
| 3587 | //TODO: Add return statement here |
||
| 3588 | } |
||
| 3589 | |||
| 3590 | /** |
||
| 3591 | * Return crypted path |
||
| 3592 | * Not implemented. |
||
| 3593 | * |
||
| 3594 | * @param string path |
||
| 3595 | * @return mixed |
||
| 3596 | * @author Dmitry (dio) Levashov |
||
| 3597 | **/ |
||
| 3598 | protected function crypt($path) |
||
| 3599 | { |
||
| 3600 | return $path; |
||
| 3601 | } |
||
| 3602 | |||
| 3603 | /** |
||
| 3604 | * Return uncrypted path |
||
| 3605 | * Not implemented. |
||
| 3606 | * |
||
| 3607 | * @param mixed hash |
||
| 3608 | * @return mixed |
||
| 3609 | * @author Dmitry (dio) Levashov |
||
| 3610 | **/ |
||
| 3611 | protected function uncrypt($hash) |
||
| 3612 | { |
||
| 3613 | return $hash; |
||
| 3614 | } |
||
| 3615 | |||
| 3616 | /** |
||
| 3617 | * Validate file name based on $this->options['acceptedName'] regexp or function. |
||
| 3618 | * |
||
| 3619 | * @param string $name file name |
||
| 3620 | * @return bool |
||
| 3621 | * @author Dmitry (dio) Levashov |
||
| 3622 | **/ |
||
| 3623 | protected function nameAccepted($name, $isDir = false) |
||
| 3624 | { |
||
| 3625 | if (json_encode($name) === false) { |
||
| 3626 | return false; |
||
| 3627 | } |
||
| 3628 | $nameValidator = $isDir ? $this->dirnameValidator : $this->nameValidator; |
||
| 3629 | if ($nameValidator) { |
||
| 3630 | if (is_callable($nameValidator)) { |
||
| 3631 | $res = call_user_func($nameValidator, $name); |
||
| 3632 | |||
| 3633 | return $res; |
||
| 3634 | } |
||
| 3635 | if (preg_match($nameValidator, '') !== false) { |
||
| 3636 | return preg_match($nameValidator, $name); |
||
| 3637 | } |
||
| 3638 | } |
||
| 3639 | |||
| 3640 | return true; |
||
| 3641 | } |
||
| 3642 | |||
| 3643 | /** |
||
| 3644 | * Return session rootstat cache key. |
||
| 3645 | * |
||
| 3646 | * @return string |
||
| 3647 | */ |
||
| 3648 | protected function getRootstatCachekey() |
||
| 3649 | { |
||
| 3650 | return md5($this->root.(isset($this->options['alias']) ? $this->options['alias'] : '')); |
||
| 3651 | } |
||
| 3652 | |||
| 3653 | /** |
||
| 3654 | * Converts character encoding (base function). |
||
| 3655 | * |
||
| 3656 | * @param mixed $var target string or array var |
||
| 3657 | * @param string $from from character encoding |
||
| 3658 | * @param string $to to character encoding |
||
| 3659 | * @param string $locale local locale |
||
| 3660 | * @param $restoreLocale |
||
| 3661 | * @param string $unknown replaces character for unknown |
||
| 3662 | * @return mixed |
||
| 3663 | */ |
||
| 3664 | protected function convEnc($var, $from, $to, $locale, $restoreLocale, $unknown = '_') |
||
| 3665 | { |
||
| 3666 | if (strtoupper($from) !== strtoupper($to)) { |
||
| 3667 | if ($locale) { |
||
| 3668 | setlocale(LC_ALL, $locale); |
||
| 3669 | } |
||
| 3670 | if (is_array($var)) { |
||
| 3671 | $_ret = []; |
||
| 3672 | foreach ($var as $_k => $_v) { |
||
| 3673 | $_ret[$_k] = $this->convEnc($_v, $from, $to, '', false, $unknown = '_'); |
||
| 3674 | } |
||
| 3675 | $var = $_ret; |
||
| 3676 | } else { |
||
| 3677 | $_var = false; |
||
| 3678 | if (is_string($var)) { |
||
| 3679 | $_var = $var; |
||
| 3680 | if (false !== ($_var = iconv($from, $to.'//TRANSLIT', $_var))) { |
||
| 3681 | $_var = str_replace('?', $unknown, $_var); |
||
| 3682 | } |
||
| 3683 | } |
||
| 3684 | if ($_var !== false) { |
||
| 3685 | $var = $_var; |
||
| 3686 | } |
||
| 3687 | } |
||
| 3688 | if ($restoreLocale) { |
||
| 3689 | setlocale(LC_ALL, elFinder::$locale); |
||
| 3690 | } |
||
| 3691 | } |
||
| 3692 | |||
| 3693 | return $var; |
||
| 3694 | } |
||
| 3695 | |||
| 3696 | /*********************** util mainly for inheritance class *********************/ |
||
| 3697 | |||
| 3698 | /** |
||
| 3699 | * Get temporary filename. Tempfile will be removed when after script execution finishes or exit() is called. |
||
| 3700 | * When needing the unique file to a path, give $path to parameter. |
||
| 3701 | * |
||
| 3702 | * @param string $path for get unique file to a path |
||
| 3703 | * @return string|false |
||
| 3704 | * @author Naoki Sawada |
||
| 3705 | */ |
||
| 3706 | protected function getTempFile($path = '') |
||
| 3707 | { |
||
| 3708 | static $cache = []; |
||
| 3709 | static $rmfunc; |
||
| 3710 | |||
| 3711 | $key = ''; |
||
| 3712 | if ($path !== '') { |
||
| 3713 | $key = $this->id.'#'.$path; |
||
| 3714 | if (isset($cache[$key])) { |
||
| 3715 | return $cache[$key]; |
||
| 3716 | } |
||
| 3717 | } |
||
| 3718 | |||
| 3719 | if ($tmpdir = $this->getTempPath()) { |
||
| 3720 | if (! $rmfunc) { |
||
| 3721 | $rmfunc = create_function('$f', 'is_file($f) && unlink($f);'); |
||
| 3722 | } |
||
| 3723 | $name = tempnam($tmpdir, 'ELF'); |
||
| 3724 | if ($key) { |
||
| 3725 | $cache[$key] = $name; |
||
| 3726 | } |
||
| 3727 | register_shutdown_function($rmfunc, $name); |
||
| 3728 | |||
| 3729 | return $name; |
||
| 3730 | } |
||
| 3731 | |||
| 3732 | return false; |
||
| 3733 | } |
||
| 3734 | |||
| 3735 | /** |
||
| 3736 | * File path of local server side work file path. |
||
| 3737 | * |
||
| 3738 | * @param string $path path need convert encoding to server encoding |
||
| 3739 | * @return string |
||
| 3740 | * @author Naoki Sawada |
||
| 3741 | */ |
||
| 3742 | protected function getWorkFile($path) |
||
| 3743 | { |
||
| 3744 | if ($work = $this->getTempFile()) { |
||
| 3745 | if ($wfp = fopen($work, 'wb')) { |
||
| 3746 | if ($fp = $this->_fopen($path)) { |
||
| 3747 | while (! feof($fp)) { |
||
| 3748 | fwrite($wfp, fread($fp, 8192)); |
||
| 3749 | } |
||
| 3750 | $this->_fclose($fp, $path); |
||
| 3751 | fclose($wfp); |
||
| 3752 | |||
| 3753 | return $work; |
||
| 3754 | } |
||
| 3755 | } |
||
| 3756 | } |
||
| 3757 | |||
| 3758 | return false; |
||
| 3759 | } |
||
| 3760 | |||
| 3761 | /** |
||
| 3762 | * Delete dirctory trees. |
||
| 3763 | * |
||
| 3764 | * @param string $localpath path need convert encoding to server encoding |
||
| 3765 | * @return bool |
||
| 3766 | * @author Naoki Sawada |
||
| 3767 | */ |
||
| 3768 | protected function delTree($localpath) |
||
| 3769 | { |
||
| 3770 | foreach ($this->_scandir($localpath) as $p) { |
||
| 3771 | elFinder::extendTimeLimit(); |
||
| 3772 | $stat = $this->stat($this->convEncOut($p)); |
||
| 3773 | $this->convEncIn(); |
||
| 3774 | ($stat['mime'] === 'directory') ? $this->delTree($p) : $this->_unlink($p); |
||
| 3775 | } |
||
| 3776 | |||
| 3777 | return $this->_rmdir($localpath); |
||
| 3778 | } |
||
| 3779 | |||
| 3780 | /** |
||
| 3781 | * Copy items to a new temporary directory on the local server. |
||
| 3782 | * |
||
| 3783 | * @param array $hashes target hashes |
||
| 3784 | * @param string $dir destination directory (for recurcive) |
||
| 3785 | * @param string $canLink it can use link() (for recurcive) |
||
| 3786 | * @return string|false saved path name |
||
| 3787 | * @author Naoki Sawada |
||
| 3788 | */ |
||
| 3789 | protected function getItemsInHand($hashes, $dir = null, $canLink = null) |
||
| 3790 | { |
||
| 3791 | static $totalSize = 0; |
||
| 3792 | if (is_null($dir)) { |
||
| 3793 | $totalSize = 0; |
||
| 3794 | if (! $tmpDir = $this->getTempPath()) { |
||
| 3795 | return false; |
||
| 3796 | } |
||
| 3797 | $dir = tempnam($tmpDir, 'elf'); |
||
| 3798 | if (! unlink($dir) || ! mkdir($dir, 0700, true)) { |
||
| 3799 | return false; |
||
| 3800 | } |
||
| 3801 | register_shutdown_function([$this, 'rmdirRecursive'], $dir); |
||
| 3802 | } |
||
| 3803 | if (is_null($canLink)) { |
||
| 3804 | $canLink = ($this instanceof elFinderVolumeLocalFileSystem); |
||
| 3805 | } |
||
| 3806 | elFinder::extendTimeLimit(); |
||
| 3807 | $res = true; |
||
| 3808 | $files = []; |
||
| 3809 | foreach ($hashes as $hash) { |
||
| 3810 | if (($file = $this->file($hash)) == false) { |
||
| 3811 | continue; |
||
| 3812 | } |
||
| 3813 | if (! $file['read']) { |
||
| 3814 | continue; |
||
| 3815 | } |
||
| 3816 | |||
| 3817 | $name = $file['name']; |
||
| 3818 | // for call from search results |
||
| 3819 | if (isset($files[$name])) { |
||
| 3820 | $name = preg_replace('/^(.*?)(\..*)?$/', '$1_'.$files[$name]++.'$2', $name); |
||
| 3821 | } else { |
||
| 3822 | $files[$name] = 1; |
||
| 3823 | } |
||
| 3824 | $target = $dir.DIRECTORY_SEPARATOR.$name; |
||
| 3825 | |||
| 3826 | if ($file['mime'] === 'directory') { |
||
| 3827 | $chashes = []; |
||
| 3828 | $_files = $this->scandir($hash); |
||
| 3829 | foreach ($_files as $_file) { |
||
| 3830 | if ($file['read']) { |
||
| 3831 | $chashes[] = $_file['hash']; |
||
| 3832 | } |
||
| 3833 | } |
||
| 3834 | if (($res = mkdir($target, 0700, true)) && $chashes) { |
||
| 3835 | $res = $this->getItemsInHand($chashes, $target, $canLink); |
||
| 3836 | } |
||
| 3837 | if (! $res) { |
||
| 3838 | break; |
||
| 3839 | } |
||
| 3840 | ! empty($file['ts']) && touch($target, $file['ts']); |
||
| 3841 | } else { |
||
| 3842 | $path = $this->decode($hash); |
||
| 3843 | if (! $canLink || ! ($canLink = link($path, $target))) { |
||
| 3844 | if ($fp = $this->fopenCE($path)) { |
||
| 3845 | if ($tfp = fopen($target, 'wb')) { |
||
| 3846 | $totalSize += stream_copy_to_stream($fp, $tfp); |
||
| 3847 | fclose($tfp); |
||
| 3848 | } |
||
| 3849 | ! empty($file['ts']) && touch($target, $file['ts']); |
||
| 3850 | $this->fcloseCE($fp, $path); |
||
| 3851 | } |
||
| 3852 | } else { |
||
| 3853 | $totalSize += filesize($path); |
||
| 3854 | } |
||
| 3855 | if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $totalSize) { |
||
| 3856 | $res = $this->setError(elFinder::ERROR_ARC_MAXSIZE); |
||
| 3857 | } |
||
| 3858 | } |
||
| 3859 | } |
||
| 3860 | |||
| 3861 | return $res ? $dir : false; |
||
| 3862 | } |
||
| 3863 | |||
| 3864 | /*********************** file stat *********************/ |
||
| 3865 | |||
| 3866 | /** |
||
| 3867 | * Check file attribute. |
||
| 3868 | * |
||
| 3869 | * @param string $path file path |
||
| 3870 | * @param string $name attribute name (read|write|locked|hidden) |
||
| 3871 | * @param bool $val attribute value returned by file system |
||
| 3872 | * @param bool $isDir path is directory (true: directory, false: file) |
||
| 3873 | * @return bool |
||
| 3874 | * @author Dmitry (dio) Levashov |
||
| 3875 | **/ |
||
| 3876 | protected function attr($path, $name, $val = null, $isDir = null) |
||
| 3877 | { |
||
| 3878 | if (! isset($this->defaults[$name])) { |
||
| 3879 | return false; |
||
| 3880 | } |
||
| 3881 | |||
| 3882 | $relpath = $this->relpathCE($path); |
||
| 3883 | if ($this->separator !== '/') { |
||
| 3884 | $relpath = str_replace($this->separator, '/', $relpath); |
||
| 3885 | } |
||
| 3886 | $relpath = '/'.$relpath; |
||
| 3887 | |||
| 3888 | $perm = null; |
||
| 3889 | |||
| 3890 | if ($this->access) { |
||
| 3891 | $perm = call_user_func($this->access, $name, $path, $this->options['accessControlData'], $this, $isDir, $relpath); |
||
| 3892 | if ($perm !== null) { |
||
| 3893 | return (bool) $perm; |
||
| 3894 | } |
||
| 3895 | } |
||
| 3896 | |||
| 3897 | for ($i = 0, $c = count($this->attributes); $i < $c; $i++) { |
||
| 3898 | $attrs = $this->attributes[$i]; |
||
| 3899 | |||
| 3900 | if (isset($attrs[$name]) && isset($attrs['pattern']) && preg_match($attrs['pattern'], $relpath)) { |
||
| 3901 | $perm = $attrs[$name]; |
||
| 3902 | } |
||
| 3903 | } |
||
| 3904 | |||
| 3905 | return $perm === null ? (is_null($val) ? $this->defaults[$name] : $val) : (bool) $perm; |
||
| 3906 | } |
||
| 3907 | |||
| 3908 | /** |
||
| 3909 | * Return true if file with given name can be created in given folder. |
||
| 3910 | * |
||
| 3911 | * @param string $dir parent dir path |
||
| 3912 | * @param string $name new file name |
||
| 3913 | * @param null $isDir |
||
| 3914 | * @return bool |
||
| 3915 | * @author Dmitry (dio) Levashov |
||
| 3916 | */ |
||
| 3917 | protected function allowCreate($dir, $name, $isDir = null) |
||
| 3918 | { |
||
| 3919 | return $this->attr($this->joinPathCE($dir, $name), 'write', true, $isDir); |
||
| 3920 | } |
||
| 3921 | |||
| 3922 | /** |
||
| 3923 | * Return true if file MIME type can save with check uploadOrder config. |
||
| 3924 | * |
||
| 3925 | * @param string $mime |
||
| 3926 | * @return bool |
||
| 3927 | */ |
||
| 3928 | protected function allowPutMime($mime) |
||
| 3929 | { |
||
| 3930 | // logic based on http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order |
||
| 3931 | $allow = $this->mimeAccepted($mime, $this->uploadAllow, null); |
||
| 3932 | $deny = $this->mimeAccepted($mime, $this->uploadDeny, null); |
||
| 3933 | $res = true; // default to allow |
||
| 3934 | if (strtolower($this->uploadOrder[0]) == 'allow') { // array('allow', 'deny'), default is to 'deny' |
||
| 3935 | $res = false; // default is deny |
||
| 3936 | if (! $deny && ($allow === true)) { // match only allow |
||
| 3937 | $res = true; |
||
| 3938 | }// else (both match | no match | match only deny) { deny } |
||
| 3939 | } else { // array('deny', 'allow'), default is to 'allow' - this is the default rule |
||
| 3940 | $res = true; // default is allow |
||
| 3941 | if (($deny === true) && ! $allow) { // match only deny |
||
| 3942 | $res = false; |
||
| 3943 | } // else (both match | no match | match only allow) { allow } |
||
| 3944 | } |
||
| 3945 | |||
| 3946 | return $res; |
||
| 3947 | } |
||
| 3948 | |||
| 3949 | /** |
||
| 3950 | * Return fileinfo. |
||
| 3951 | * |
||
| 3952 | * @param string $path file cache |
||
| 3953 | * @return array |
||
| 3954 | * @author Dmitry (dio) Levashov |
||
| 3955 | **/ |
||
| 3956 | protected function stat($path) |
||
| 3957 | { |
||
| 3958 | if ($path === false || is_null($path)) { |
||
| 3959 | return false; |
||
| 3960 | } |
||
| 3961 | $is_root = ($path == $this->root); |
||
| 3962 | if ($is_root) { |
||
| 3963 | $rootKey = $this->getRootstatCachekey(); |
||
| 3964 | if ($this->sessionCaching['rootstat'] && ! isset($this->sessionCache['rootstat'])) { |
||
| 3965 | $this->sessionCache['rootstat'] = []; |
||
| 3966 | } |
||
| 3967 | if (! isset($this->cache[$path]) && ! $this->isMyReload()) { |
||
| 3968 | // need $path as key for netmount/netunmount |
||
| 3969 | if ($this->sessionCaching['rootstat'] && isset($this->sessionCache['rootstat'][$rootKey])) { |
||
| 3970 | if ($ret = $this->sessionCache['rootstat'][$rootKey]) { |
||
| 3971 | if ($this->options['rootRev'] === $ret['rootRev']) { |
||
| 3972 | View Code Duplication | if (isset($this->options['phash'])) { |
|
| 3973 | $ret['isroot'] = 1; |
||
| 3974 | $ret['phash'] = $this->options['phash']; |
||
| 3975 | } |
||
| 3976 | |||
| 3977 | return $ret; |
||
| 3978 | } |
||
| 3979 | } |
||
| 3980 | } |
||
| 3981 | } |
||
| 3982 | } |
||
| 3983 | $ret = isset($this->cache[$path]) |
||
| 3984 | ? $this->cache[$path] |
||
| 3985 | : $this->updateCache($path, $this->convEncOut($this->_stat($this->convEncIn($path)))); |
||
| 3986 | if ($is_root && $this->sessionCaching['rootstat']) { |
||
| 3987 | if ($ret) { |
||
| 3988 | $this->rootModified = false; |
||
| 3989 | $this->sessionCache['rootstat'][$rootKey] = $ret; |
||
| 3990 | View Code Duplication | if (isset($this->options['phash'])) { |
|
| 3991 | $ret['isroot'] = 1; |
||
| 3992 | $ret['phash'] = $this->options['phash']; |
||
| 3993 | } |
||
| 3994 | } else { |
||
| 3995 | unset($this->sessionCache['rootstat'][$rootKey]); |
||
| 3996 | } |
||
| 3997 | } |
||
| 3998 | |||
| 3999 | return $ret; |
||
| 4000 | } |
||
| 4001 | |||
| 4002 | /** |
||
| 4003 | * Get root stat extra key values. |
||
| 4004 | * |
||
| 4005 | * @return array stat extras |
||
| 4006 | * @author Naoki Sawada |
||
| 4007 | */ |
||
| 4008 | protected function getRootStatExtra() |
||
| 4009 | { |
||
| 4010 | $stat = []; |
||
| 4011 | if ($this->rootName) { |
||
| 4012 | $stat['name'] = $this->rootName; |
||
| 4013 | } |
||
| 4014 | $stat['rootRev'] = $this->options['rootRev']; |
||
| 4015 | $stat['options'] = $this->options(null); |
||
| 4016 | |||
| 4017 | return $stat; |
||
| 4018 | } |
||
| 4019 | |||
| 4020 | /** |
||
| 4021 | * Return fileinfo based on filename |
||
| 4022 | * For item ID based path file system |
||
| 4023 | * Please override if needed on each drivers. |
||
| 4024 | * |
||
| 4025 | * @param string $path file cache |
||
| 4026 | * @return array |
||
| 4027 | */ |
||
| 4028 | protected function isNameExists($path) |
||
| 4029 | { |
||
| 4030 | return $this->stat($path); |
||
| 4031 | } |
||
| 4032 | |||
| 4033 | /** |
||
| 4034 | * Put file stat in cache and return it. |
||
| 4035 | * |
||
| 4036 | * @param string $path file path |
||
| 4037 | * @param array $stat file stat |
||
| 4038 | * @return array |
||
| 4039 | * @author Dmitry (dio) Levashov |
||
| 4040 | **/ |
||
| 4041 | protected function updateCache($path, $stat) |
||
| 4042 | { |
||
| 4043 | if (empty($stat) || ! is_array($stat)) { |
||
| 4044 | return $this->cache[$path] = []; |
||
| 4045 | } |
||
| 4046 | |||
| 4047 | $stat['hash'] = $this->encode($path); |
||
| 4048 | |||
| 4049 | $root = $path == $this->root; |
||
| 4050 | $parent = ''; |
||
| 4051 | |||
| 4052 | if ($root) { |
||
| 4053 | $stat = array_merge($stat, $this->getRootStatExtra()); |
||
| 4054 | } else { |
||
| 4055 | if (! isset($stat['name']) || $stat['name'] === '') { |
||
| 4056 | $stat['name'] = $this->basenameCE($path); |
||
| 4057 | } |
||
| 4058 | if (empty($stat['phash'])) { |
||
| 4059 | $parent = $this->dirnameCE($path); |
||
| 4060 | $stat['phash'] = $this->encode($parent); |
||
| 4061 | } else { |
||
| 4062 | $parent = $this->decode($stat['phash']); |
||
| 4063 | } |
||
| 4064 | } |
||
| 4065 | |||
| 4066 | // name check |
||
| 4067 | if (! $jeName = json_encode($stat['name'])) { |
||
| 4068 | return $this->cache[$path] = []; |
||
| 4069 | } |
||
| 4070 | // fix name if required |
||
| 4071 | if ($this->options['utf8fix'] && $this->options['utf8patterns'] && $this->options['utf8replace']) { |
||
| 4072 | $stat['name'] = json_decode(str_replace($this->options['utf8patterns'], $this->options['utf8replace'], $jeName)); |
||
| 4073 | } |
||
| 4074 | |||
| 4075 | if (empty($stat['mime'])) { |
||
| 4076 | $stat['mime'] = $this->mimetype($stat['name'], true); |
||
| 4077 | } |
||
| 4078 | |||
| 4079 | // @todo move dateformat to client |
||
| 4080 | // $stat['date'] = isset($stat['ts']) |
||
| 4081 | // ? $this->formatDate($stat['ts']) |
||
| 4082 | // : 'unknown'; |
||
| 4083 | |||
| 4084 | if (! isset($stat['size'])) { |
||
| 4085 | $stat['size'] = 'unknown'; |
||
| 4086 | } |
||
| 4087 | |||
| 4088 | if ($isDir = ($stat['mime'] === 'directory')) { |
||
| 4089 | $stat['volumeid'] = $this->id; |
||
| 4090 | } |
||
| 4091 | |||
| 4092 | $stat['read'] = intval($this->attr($path, 'read', isset($stat['read']) ? (bool) $stat['read'] : null, $isDir)); |
||
| 4093 | $stat['write'] = intval($this->attr($path, 'write', isset($stat['write']) ? (bool) $stat['write'] : null, $isDir)); |
||
| 4094 | if ($root) { |
||
| 4095 | $stat['locked'] = 1; |
||
| 4096 | if ($this->options['type'] !== '') { |
||
| 4097 | $stat['type'] = $this->options['type']; |
||
| 4098 | } |
||
| 4099 | } else { |
||
| 4100 | // lock when parent directory is not writable |
||
| 4101 | if (! isset($stat['locked'])) { |
||
| 4102 | $pstat = $this->stat($parent); |
||
| 4103 | if (isset($pstat['write']) && ! $pstat['write']) { |
||
| 4104 | $stat['locked'] = true; |
||
| 4105 | } |
||
| 4106 | } |
||
| 4107 | if ($this->attr($path, 'locked', isset($stat['locked']) ? (bool) $stat['locked'] : null, $isDir)) { |
||
| 4108 | $stat['locked'] = 1; |
||
| 4109 | } else { |
||
| 4110 | unset($stat['locked']); |
||
| 4111 | } |
||
| 4112 | } |
||
| 4113 | |||
| 4114 | if ($root) { |
||
| 4115 | unset($stat['hidden']); |
||
| 4116 | } elseif ($this->attr($path, 'hidden', isset($stat['hidden']) ? (bool) $stat['hidden'] : null, $isDir) |
||
| 4117 | || ! $this->mimeAccepted($stat['mime'])) { |
||
| 4118 | $stat['hidden'] = 1; |
||
| 4119 | } else { |
||
| 4120 | unset($stat['hidden']); |
||
| 4121 | } |
||
| 4122 | |||
| 4123 | if ($stat['read'] && empty($stat['hidden'])) { |
||
| 4124 | if ($isDir) { |
||
| 4125 | // caching parent's subdirs |
||
| 4126 | if ($parent) { |
||
| 4127 | $this->updateSubdirsCache($parent, true); |
||
| 4128 | } |
||
| 4129 | // for dir - check for subdirs |
||
| 4130 | if ($this->options['checkSubfolders']) { |
||
| 4131 | if (! isset($stat['dirs']) && intval($this->options['checkSubfolders']) === -1) { |
||
| 4132 | $stat['dirs'] = -1; |
||
| 4133 | } |
||
| 4134 | if (isset($stat['dirs'])) { |
||
| 4135 | if ($stat['dirs']) { |
||
| 4136 | if ($stat['dirs'] == -1) { |
||
| 4137 | $stat['dirs'] = ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$path])) ? (int) $this->sessionCache['subdirs'][$path] : -1; |
||
| 4138 | } else { |
||
| 4139 | $stat['dirs'] = 1; |
||
| 4140 | } |
||
| 4141 | } else { |
||
| 4142 | unset($stat['dirs']); |
||
| 4143 | } |
||
| 4144 | } elseif (! empty($stat['alias']) && ! empty($stat['target'])) { |
||
| 4145 | $stat['dirs'] = isset($this->cache[$stat['target']]) |
||
| 4146 | ? intval(isset($this->cache[$stat['target']]['dirs'])) |
||
| 4147 | : $this->subdirsCE($stat['target']); |
||
| 4148 | } elseif ($this->subdirsCE($path)) { |
||
| 4149 | $stat['dirs'] = 1; |
||
| 4150 | } |
||
| 4151 | } else { |
||
| 4152 | $stat['dirs'] = 1; |
||
| 4153 | } |
||
| 4154 | if ($this->options['dirUrlOwn'] === true) { |
||
| 4155 | $stat['url'] = '#elf_'.$stat['hash']; |
||
| 4156 | } |
||
| 4157 | } else { |
||
| 4158 | // for files - check for thumbnails |
||
| 4159 | $p = isset($stat['target']) ? $stat['target'] : $path; |
||
| 4160 | if ($this->tmbURL && ! isset($stat['tmb']) && $this->canCreateTmb($p, $stat)) { |
||
| 4161 | $tmb = $this->gettmb($p, $stat); |
||
| 4162 | $stat['tmb'] = $tmb ? $tmb : 1; |
||
| 4163 | } |
||
| 4164 | } |
||
| 4165 | if (! isset($stat['url']) && $this->URL && $this->encoding) { |
||
| 4166 | $_path = str_replace($this->separator, '/', substr($path, strlen($this->root) + 1)); |
||
| 4167 | $stat['url'] = rtrim($this->URL, '/').'/'.str_replace('%2F', '/', rawurlencode((substr(PHP_OS, 0, 3) === 'WIN') ? $_path : $this->convEncIn($_path, true))); |
||
| 4168 | } |
||
| 4169 | } else { |
||
| 4170 | if ($isDir) { |
||
| 4171 | unset($stat['dirs']); |
||
| 4172 | } |
||
| 4173 | } |
||
| 4174 | |||
| 4175 | if (! empty($stat['alias']) && ! empty($stat['target'])) { |
||
| 4176 | $stat['thash'] = $this->encode($stat['target']); |
||
| 4177 | //$this->cache[$stat['target']] = $stat; |
||
| 4178 | unset($stat['target']); |
||
| 4179 | } |
||
| 4180 | |||
| 4181 | $this->cache[$path] = $stat; |
||
| 4182 | |||
| 4183 | if ($root && $this->sessionCaching['rootstat']) { |
||
| 4184 | // to update session cache |
||
| 4185 | $this->stat($path); |
||
| 4186 | } |
||
| 4187 | |||
| 4188 | return $stat; |
||
| 4189 | } |
||
| 4190 | |||
| 4191 | /** |
||
| 4192 | * Get stat for folder content and put in cache. |
||
| 4193 | * |
||
| 4194 | * @param string $path |
||
| 4195 | * @return void |
||
| 4196 | * @author Dmitry (dio) Levashov |
||
| 4197 | **/ |
||
| 4198 | protected function cacheDir($path) |
||
| 4199 | { |
||
| 4200 | $this->dirsCache[$path] = []; |
||
| 4201 | $hasDir = false; |
||
| 4202 | |||
| 4203 | foreach ($this->scandirCE($path) as $p) { |
||
| 4204 | if (($stat = $this->stat($p)) && empty($stat['hidden'])) { |
||
| 4205 | if (! $hasDir && $stat['mime'] === 'directory') { |
||
| 4206 | $hasDir = true; |
||
| 4207 | } |
||
| 4208 | $this->dirsCache[$path][] = $p; |
||
| 4209 | } |
||
| 4210 | } |
||
| 4211 | |||
| 4212 | $this->updateSubdirsCache($path, $hasDir); |
||
| 4213 | } |
||
| 4214 | |||
| 4215 | /** |
||
| 4216 | * Clean cache. |
||
| 4217 | * |
||
| 4218 | * @return void |
||
| 4219 | * @author Dmitry (dio) Levashov |
||
| 4220 | **/ |
||
| 4221 | protected function clearcache() |
||
| 4222 | { |
||
| 4223 | $this->cache = $this->dirsCache = []; |
||
| 4224 | } |
||
| 4225 | |||
| 4226 | /** |
||
| 4227 | * Return file mimetype. |
||
| 4228 | * |
||
| 4229 | * @param string $path file path |
||
| 4230 | * @param string|bool $name |
||
| 4231 | * @return string |
||
| 4232 | * @author Dmitry (dio) Levashov |
||
| 4233 | */ |
||
| 4234 | protected function mimetype($path, $name = '') |
||
| 4235 | { |
||
| 4236 | $type = ''; |
||
| 4237 | $nameCheck = false; |
||
| 4238 | |||
| 4239 | if ($name === '') { |
||
| 4240 | $name = $path; |
||
| 4241 | } elseif ($name === true) { |
||
| 4242 | $name = $path; |
||
| 4243 | $nameCheck = true; |
||
| 4244 | } |
||
| 4245 | $ext = (false === $pos = strrpos($name, '.')) ? '' : substr($name, $pos + 1); |
||
| 4246 | if (! $nameCheck && is_readable($path)) { |
||
| 4247 | if (filesize($path) > 0) { |
||
| 4248 | if ($this->mimeDetect == 'finfo') { |
||
| 4249 | if ($type = finfo_file($this->finfo, $path)) { |
||
| 4250 | if ($ext && preg_match('~^application/(?:octet-stream|(?:x-)?zip)~', $type)) { |
||
| 4251 | if (isset(self::$mimetypes[$ext])) { |
||
| 4252 | $type = self::$mimetypes[$ext]; |
||
| 4253 | } |
||
| 4254 | } elseif ($ext === 'js' && preg_match('~^text/~', $type)) { |
||
| 4255 | $type = 'text/javascript'; |
||
| 4256 | } |
||
| 4257 | } else { |
||
| 4258 | $type = 'unknown'; |
||
| 4259 | } |
||
| 4260 | } elseif ($this->mimeDetect == 'mime_content_type') { |
||
| 4261 | $type = mime_content_type($path); |
||
| 4262 | } |
||
| 4263 | } else { |
||
| 4264 | $type = 'text/plain'; |
||
| 4265 | } |
||
| 4266 | } |
||
| 4267 | if (! $type) { |
||
| 4268 | $type = self::mimetypeInternalDetect($path); |
||
| 4269 | } |
||
| 4270 | |||
| 4271 | if ($type === 'unknown' && $this->mimeDetect != 'internal') { |
||
| 4272 | $type = self::mimetypeInternalDetect($path); |
||
| 4273 | } |
||
| 4274 | |||
| 4275 | $type = explode(';', $type); |
||
| 4276 | $type = trim($type[0]); |
||
| 4277 | |||
| 4278 | if (in_array($type, ['application/x-empty', 'inode/x-empty'])) { |
||
| 4279 | // finfo return this mime for empty files |
||
| 4280 | $type = 'text/plain'; |
||
| 4281 | } |
||
| 4282 | |||
| 4283 | // mime type normalization |
||
| 4284 | $_checkKey = strtolower($ext.':'.$type); |
||
| 4285 | if (isset($this->options['mimeMap'][$_checkKey])) { |
||
| 4286 | $type = $this->options['mimeMap'][$_checkKey]; |
||
| 4287 | } else { |
||
| 4288 | $_checkKey = strtolower($ext.':*'); |
||
| 4289 | if (isset($this->options['mimeMap'][$_checkKey])) { |
||
| 4290 | $type = $this->options['mimeMap'][$_checkKey]; |
||
| 4291 | } |
||
| 4292 | } |
||
| 4293 | |||
| 4294 | return $type; |
||
| 4295 | } |
||
| 4296 | |||
| 4297 | /** |
||
| 4298 | * Detect file mimetype using "internal" method or Loading mime.types with $path = ''. |
||
| 4299 | * |
||
| 4300 | * @param string $path file path |
||
| 4301 | * @return string |
||
| 4302 | * @author Dmitry (dio) Levashov |
||
| 4303 | **/ |
||
| 4304 | protected static function mimetypeInternalDetect($path = '') |
||
| 4305 | { |
||
| 4306 | // load default MIME table file "mime.types" |
||
| 4307 | if (! self::$mimetypesLoaded) { |
||
| 4308 | self::$mimetypesLoaded = true; |
||
| 4309 | $file = elFinder::$defaultMimefile; |
||
| 4310 | if ($file === '' || ! is_readable($file)) { |
||
| 4311 | $file = dirname(__FILE__).DIRECTORY_SEPARATOR.'mime.types'; |
||
| 4312 | } |
||
| 4313 | View Code Duplication | if (is_readable($file)) { |
|
| 4314 | $mimecf = file($file); |
||
| 4315 | foreach ($mimecf as $line_num => $line) { |
||
| 4316 | if (! preg_match('/^\s*#/', $line)) { |
||
| 4317 | $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY); |
||
| 4318 | for ($i = 1, $size = count($mime); $i < $size; $i++) { |
||
| 4319 | if (! isset(self::$mimetypes[$mime[$i]])) { |
||
| 4320 | self::$mimetypes[$mime[$i]] = $mime[0]; |
||
| 4321 | } |
||
| 4322 | } |
||
| 4323 | } |
||
| 4324 | } |
||
| 4325 | } |
||
| 4326 | } |
||
| 4327 | $ext = ''; |
||
| 4328 | if ($path) { |
||
| 4329 | $pinfo = pathinfo($path); |
||
| 4330 | $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : ''; |
||
| 4331 | } |
||
| 4332 | |||
| 4333 | return ($ext && isset(self::$mimetypes[$ext])) ? self::$mimetypes[$ext] : 'unknown'; |
||
| 4334 | } |
||
| 4335 | |||
| 4336 | /** |
||
| 4337 | * Return file/total directory size. |
||
| 4338 | * |
||
| 4339 | * @param string $path file path |
||
| 4340 | * @return int |
||
| 4341 | * @author Dmitry (dio) Levashov |
||
| 4342 | **/ |
||
| 4343 | protected function countSize($path) |
||
| 4344 | { |
||
| 4345 | elFinder::extendTimeLimit(); |
||
| 4346 | |||
| 4347 | $result = ['size' => 0, 'files' => 0, 'dirs' => 0]; |
||
| 4348 | $stat = $this->stat($path); |
||
| 4349 | |||
| 4350 | if (empty($stat) || ! $stat['read'] || ! empty($stat['hidden'])) { |
||
| 4351 | $result['size'] = 'unknown'; |
||
| 4352 | |||
| 4353 | return $result; |
||
| 4354 | } |
||
| 4355 | |||
| 4356 | if ($stat['mime'] != 'directory') { |
||
| 4357 | $result['size'] = intval($stat['size']); |
||
| 4358 | $result['files'] = 1; |
||
| 4359 | |||
| 4360 | return $result; |
||
| 4361 | } |
||
| 4362 | |||
| 4363 | $subdirs = $this->options['checkSubfolders']; |
||
| 4364 | $this->options['checkSubfolders'] = true; |
||
| 4365 | foreach ($this->getScandir($path) as $stat) { |
||
| 4366 | if ($isDir = ($stat['mime'] === 'directory' && $stat['read'])) { |
||
| 4367 | $result['dirs']++; |
||
| 4368 | } else { |
||
| 4369 | $result['files']++; |
||
| 4370 | } |
||
| 4371 | $res = $isDir |
||
| 4372 | ? $this->countSize($this->decode($stat['hash'])) |
||
| 4373 | : (isset($stat['size']) ? ['size' => intval($stat['size'])] : []); |
||
| 4374 | View Code Duplication | if (! empty($res['size']) && is_numeric($res['size'])) { |
|
| 4375 | $result['size'] += $res['size']; |
||
| 4376 | } |
||
| 4377 | View Code Duplication | if (! empty($res['files']) && is_numeric($res['files'])) { |
|
| 4378 | $result['files'] += $res['files']; |
||
| 4379 | } |
||
| 4380 | View Code Duplication | if (! empty($res['dirs']) && is_numeric($res['dirs'])) { |
|
| 4381 | $result['dirs'] += $res['dirs']; |
||
| 4382 | } |
||
| 4383 | } |
||
| 4384 | $this->options['checkSubfolders'] = $subdirs; |
||
| 4385 | |||
| 4386 | return $result; |
||
| 4387 | } |
||
| 4388 | |||
| 4389 | /** |
||
| 4390 | * Return true if all mimes is directory or files. |
||
| 4391 | * |
||
| 4392 | * @param string $mime1 mimetype |
||
| 4393 | * @param string $mime2 mimetype |
||
| 4394 | * @return bool |
||
| 4395 | * @author Dmitry (dio) Levashov |
||
| 4396 | **/ |
||
| 4397 | protected function isSameType($mime1, $mime2) |
||
| 4398 | { |
||
| 4399 | return ($mime1 == 'directory' && $mime1 == $mime2) || ($mime1 != 'directory' && $mime2 != 'directory'); |
||
| 4400 | } |
||
| 4401 | |||
| 4402 | /** |
||
| 4403 | * If file has required attr == $val - return file path, |
||
| 4404 | * If dir has child with has required attr == $val - return child path. |
||
| 4405 | * |
||
| 4406 | * @param string $path file path |
||
| 4407 | * @param string $attr attribute name |
||
| 4408 | * @param bool $val attribute value |
||
| 4409 | * @return string|false |
||
| 4410 | * @author Dmitry (dio) Levashov |
||
| 4411 | **/ |
||
| 4412 | protected function closestByAttr($path, $attr, $val) |
||
| 4413 | { |
||
| 4414 | $stat = $this->stat($path); |
||
| 4415 | |||
| 4416 | if (empty($stat)) { |
||
| 4417 | return false; |
||
| 4418 | } |
||
| 4419 | |||
| 4420 | $v = isset($stat[$attr]) ? $stat[$attr] : false; |
||
| 4421 | |||
| 4422 | if ($v == $val) { |
||
| 4423 | return $path; |
||
| 4424 | } |
||
| 4425 | |||
| 4426 | return $stat['mime'] == 'directory' |
||
| 4427 | ? $this->childsByAttr($path, $attr, $val) |
||
| 4428 | : false; |
||
| 4429 | } |
||
| 4430 | |||
| 4431 | /** |
||
| 4432 | * Return first found children with required attr == $val. |
||
| 4433 | * |
||
| 4434 | * @param string $path file path |
||
| 4435 | * @param string $attr attribute name |
||
| 4436 | * @param bool $val attribute value |
||
| 4437 | * @return string|false |
||
| 4438 | * @author Dmitry (dio) Levashov |
||
| 4439 | **/ |
||
| 4440 | protected function childsByAttr($path, $attr, $val) |
||
| 4441 | { |
||
| 4442 | foreach ($this->scandirCE($path) as $p) { |
||
| 4443 | if (($_p = $this->closestByAttr($p, $attr, $val)) != false) { |
||
| 4444 | return $_p; |
||
| 4445 | } |
||
| 4446 | } |
||
| 4447 | |||
| 4448 | return false; |
||
| 4449 | } |
||
| 4450 | |||
| 4451 | protected function isMyReload($target = '', $ARGtarget = '') |
||
| 4452 | { |
||
| 4453 | if ($this->rootModified || (! empty($this->ARGS['cmd']) && $this->ARGS['cmd'] === 'parents')) { |
||
| 4454 | return true; |
||
| 4455 | } |
||
| 4456 | if (! empty($this->ARGS['reload'])) { |
||
| 4457 | if ($ARGtarget === '') { |
||
| 4458 | $ARGtarget = isset($this->ARGS['target']) ? $this->ARGS['target'] |
||
| 4459 | : ((isset($this->ARGS['targets']) && is_array($this->ARGS['targets']) && count($this->ARGS['targets']) === 1) ? |
||
| 4460 | $this->ARGS['targets'][0] : ''); |
||
| 4461 | } |
||
| 4462 | if ($ARGtarget !== '') { |
||
| 4463 | $ARGtarget = strval($ARGtarget); |
||
| 4464 | if ($target === '') { |
||
| 4465 | return strpos($ARGtarget, $this->id) === 0; |
||
| 4466 | } else { |
||
| 4467 | $target = strval($target); |
||
| 4468 | |||
| 4469 | return $target === $ARGtarget; |
||
| 4470 | } |
||
| 4471 | } |
||
| 4472 | } |
||
| 4473 | |||
| 4474 | return false; |
||
| 4475 | } |
||
| 4476 | |||
| 4477 | /** |
||
| 4478 | * Update subdirs cache data. |
||
| 4479 | * |
||
| 4480 | * @param string $path |
||
| 4481 | * @param bool $subdirs |
||
| 4482 | * |
||
| 4483 | * @returnv void |
||
| 4484 | */ |
||
| 4485 | protected function updateSubdirsCache($path, $subdirs) |
||
| 4486 | { |
||
| 4487 | if (isset($this->cache[$path])) { |
||
| 4488 | if ($subdirs) { |
||
| 4489 | $this->cache[$path]['dirs'] = 1; |
||
| 4490 | } else { |
||
| 4491 | unset($this->cache[$path]['dirs']); |
||
| 4492 | } |
||
| 4493 | } |
||
| 4494 | if ($this->sessionCaching['subdirs']) { |
||
| 4495 | $this->sessionCache['subdirs'][$path] = $subdirs; |
||
| 4496 | } |
||
| 4497 | if ($this->sessionCaching['rootstat'] && $path == $this->root) { |
||
| 4498 | unset($this->sessionCache['rootstat'][$this->getRootstatCachekey()]); |
||
| 4499 | } |
||
| 4500 | } |
||
| 4501 | |||
| 4502 | /***************** get content *******************/ |
||
| 4503 | |||
| 4504 | /** |
||
| 4505 | * Return required dir's files info. |
||
| 4506 | * If onlyMimes is set - return only dirs and files of required mimes. |
||
| 4507 | * |
||
| 4508 | * @param string $path dir path |
||
| 4509 | * @return array |
||
| 4510 | * @author Dmitry (dio) Levashov |
||
| 4511 | **/ |
||
| 4512 | protected function getScandir($path) |
||
| 4513 | { |
||
| 4514 | $files = []; |
||
| 4515 | |||
| 4516 | ! isset($this->dirsCache[$path]) && $this->cacheDir($path); |
||
| 4517 | |||
| 4518 | foreach ($this->dirsCache[$path] as $p) { |
||
| 4519 | if (($stat = $this->stat($p)) && empty($stat['hidden'])) { |
||
| 4520 | $files[] = $stat; |
||
| 4521 | } |
||
| 4522 | } |
||
| 4523 | |||
| 4524 | return $files; |
||
| 4525 | } |
||
| 4526 | |||
| 4527 | /** |
||
| 4528 | * Return subdirs tree. |
||
| 4529 | * |
||
| 4530 | * @param string $path parent dir path |
||
| 4531 | * @param int $deep tree deep |
||
| 4532 | * @param string $exclude |
||
| 4533 | * @return array |
||
| 4534 | * @author Dmitry (dio) Levashov |
||
| 4535 | */ |
||
| 4536 | protected function gettree($path, $deep, $exclude = '') |
||
| 4537 | { |
||
| 4538 | $dirs = []; |
||
| 4539 | |||
| 4540 | ! isset($this->dirsCache[$path]) && $this->cacheDir($path); |
||
| 4541 | |||
| 4542 | foreach ($this->dirsCache[$path] as $p) { |
||
| 4543 | $stat = $this->stat($p); |
||
| 4544 | |||
| 4545 | if ($stat && empty($stat['hidden']) && $p != $exclude && $stat['mime'] == 'directory') { |
||
| 4546 | $dirs[] = $stat; |
||
| 4547 | if ($deep > 0 && ! empty($stat['dirs'])) { |
||
| 4548 | $dirs = array_merge($dirs, $this->gettree($p, $deep - 1)); |
||
| 4549 | } |
||
| 4550 | } |
||
| 4551 | } |
||
| 4552 | |||
| 4553 | return $dirs; |
||
| 4554 | } |
||
| 4555 | |||
| 4556 | /** |
||
| 4557 | * Recursive files search. |
||
| 4558 | * |
||
| 4559 | * @param string $path dir path |
||
| 4560 | * @param string $q search string |
||
| 4561 | * @param array $mimes |
||
| 4562 | * @return array |
||
| 4563 | * @author Dmitry (dio) Levashov |
||
| 4564 | **/ |
||
| 4565 | protected function doSearch($path, $q, $mimes) |
||
| 4566 | { |
||
| 4567 | $result = []; |
||
| 4568 | |||
| 4569 | $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; |
||
| 4570 | View Code Duplication | if ($timeout && $timeout < time()) { |
|
| 4571 | $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); |
||
| 4572 | |||
| 4573 | return $result; |
||
| 4574 | } |
||
| 4575 | |||
| 4576 | foreach ($this->scandirCE($path) as $p) { |
||
| 4577 | elFinder::extendTimeLimit($this->options['searchTimeout'] + 30); |
||
| 4578 | |||
| 4579 | View Code Duplication | if ($timeout && ($this->error || $timeout < time())) { |
|
| 4580 | ! $this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); |
||
| 4581 | break; |
||
| 4582 | } |
||
| 4583 | |||
| 4584 | $stat = $this->stat($p); |
||
| 4585 | |||
| 4586 | if (! $stat) { // invalid links |
||
| 4587 | continue; |
||
| 4588 | } |
||
| 4589 | |||
| 4590 | if (! empty($stat['hidden']) || ! $this->mimeAccepted($stat['mime'], $mimes)) { |
||
| 4591 | continue; |
||
| 4592 | } |
||
| 4593 | |||
| 4594 | $name = $stat['name']; |
||
| 4595 | |||
| 4596 | View Code Duplication | if ($this->doSearchCurrentQuery['excludes']) { |
|
| 4597 | foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) { |
||
| 4598 | if ($this->stripos($name, $exclude) !== false) { |
||
| 4599 | continue 2; |
||
| 4600 | } |
||
| 4601 | } |
||
| 4602 | } |
||
| 4603 | |||
| 4604 | if ((! $mimes || $stat['mime'] !== 'directory') && $this->stripos($name, $q) !== false) { |
||
| 4605 | $stat['path'] = $this->path($stat['hash']); |
||
| 4606 | if ($this->URL && ! isset($stat['url'])) { |
||
| 4607 | $path = str_replace($this->separator, '/', substr($p, strlen($this->root) + 1)); |
||
| 4608 | if ($this->encoding) { |
||
| 4609 | $path = str_replace('%2F', '/', rawurlencode($this->convEncIn($path, true))); |
||
| 4610 | } else { |
||
| 4611 | $path = str_replace('%2F', '/', rawurlencode($path)); |
||
| 4612 | } |
||
| 4613 | $stat['url'] = $this->URL.$path; |
||
| 4614 | } |
||
| 4615 | |||
| 4616 | $result[] = $stat; |
||
| 4617 | } |
||
| 4618 | if ($stat['mime'] == 'directory' && $stat['read'] && ! isset($stat['alias'])) { |
||
| 4619 | if (! $this->options['searchExDirReg'] || ! preg_match($this->options['searchExDirReg'], $p)) { |
||
| 4620 | $result = array_merge($result, $this->doSearch($p, $q, $mimes)); |
||
| 4621 | } |
||
| 4622 | } |
||
| 4623 | } |
||
| 4624 | |||
| 4625 | return $result; |
||
| 4626 | } |
||
| 4627 | |||
| 4628 | /********************** manuipulations ******************/ |
||
| 4629 | |||
| 4630 | /** |
||
| 4631 | * Copy file/recursive copy dir only in current volume. |
||
| 4632 | * Return new file path or false. |
||
| 4633 | * |
||
| 4634 | * @param string $src source path |
||
| 4635 | * @param string $dst destination dir path |
||
| 4636 | * @param string $name new file name (optionaly) |
||
| 4637 | * @return string|false |
||
| 4638 | * @author Dmitry (dio) Levashov |
||
| 4639 | **/ |
||
| 4640 | protected function copy($src, $dst, $name) |
||
| 4641 | { |
||
| 4642 | elFinder::extendTimeLimit(); |
||
| 4643 | |||
| 4644 | $srcStat = $this->stat($src); |
||
| 4645 | |||
| 4646 | if (! empty($srcStat['thash'])) { |
||
| 4647 | $target = $this->decode($srcStat['thash']); |
||
| 4648 | if (! $this->inpathCE($target, $this->root)) { |
||
| 4649 | return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']), elFinder::ERROR_MKOUTLINK); |
||
| 4650 | } |
||
| 4651 | $stat = $this->stat($target); |
||
| 4652 | $this->clearcache(); |
||
| 4653 | |||
| 4654 | return $stat && $this->symlinkCE($target, $dst, $name) |
||
| 4655 | ? $this->joinPathCE($dst, $name) |
||
| 4656 | : $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash'])); |
||
| 4657 | } |
||
| 4658 | |||
| 4659 | if ($srcStat['mime'] === 'directory') { |
||
| 4660 | $testStat = $this->isNameExists($this->joinPathCE($dst, $name)); |
||
| 4661 | $this->clearcache(); |
||
| 4662 | |||
| 4663 | View Code Duplication | if (($testStat && $testStat['mime'] !== 'directory') || (! $testStat && ! $testStat = $this->mkdir($this->encode($dst), $name))) { |
|
| 4664 | return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash'])); |
||
| 4665 | } |
||
| 4666 | |||
| 4667 | $dst = $this->decode($testStat['hash']); |
||
| 4668 | |||
| 4669 | foreach ($this->getScandir($src) as $stat) { |
||
| 4670 | if (empty($stat['hidden'])) { |
||
| 4671 | $name = $stat['name']; |
||
| 4672 | $_src = $this->decode($stat['hash']); |
||
| 4673 | if (! $this->copy($_src, $dst, $name)) { |
||
| 4674 | $this->remove($dst, true); // fall back |
||
| 4675 | return $this->setError($this->error, elFinder::ERROR_COPY, $this->_path($src)); |
||
| 4676 | } |
||
| 4677 | } |
||
| 4678 | } |
||
| 4679 | |||
| 4680 | $this->added[] = $testStat; |
||
| 4681 | |||
| 4682 | return $dst; |
||
| 4683 | } |
||
| 4684 | |||
| 4685 | View Code Duplication | if ($this->options['copyJoin']) { |
|
| 4686 | $test = $this->joinPathCE($dst, $name); |
||
| 4687 | if ($testStat = $this->isNameExists($test)) { |
||
| 4688 | $this->remove($test); |
||
| 4689 | } |
||
| 4690 | } else { |
||
| 4691 | $testStat = false; |
||
| 4692 | } |
||
| 4693 | if ($res = $this->convEncOut($this->_copy($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)))) { |
||
| 4694 | $path = is_string($res) ? $res : $this->joinPathCE($dst, $name); |
||
| 4695 | $this->clearcache(); |
||
| 4696 | if ($this->ARGS['cmd'] !== 'duplicate') { |
||
| 4697 | $this->added[] = $this->stat($path); |
||
| 4698 | } |
||
| 4699 | |||
| 4700 | return $path; |
||
| 4701 | } |
||
| 4702 | |||
| 4703 | return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash'])); |
||
| 4704 | } |
||
| 4705 | |||
| 4706 | /** |
||
| 4707 | * Move file |
||
| 4708 | * Return new file path or false. |
||
| 4709 | * |
||
| 4710 | * @param string $src source path |
||
| 4711 | * @param string $dst destination dir path |
||
| 4712 | * @param string $name new file name |
||
| 4713 | * @return string|false |
||
| 4714 | * @author Dmitry (dio) Levashov |
||
| 4715 | **/ |
||
| 4716 | protected function move($src, $dst, $name) |
||
| 4717 | { |
||
| 4718 | $stat = $this->stat($src); |
||
| 4719 | $stat['realpath'] = $src; |
||
| 4720 | $this->rmTmb($stat); // can not do rmTmb() after _move() |
||
| 4721 | $this->clearcache(); |
||
| 4722 | |||
| 4723 | if ($res = $this->convEncOut($this->_move($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)))) { |
||
| 4724 | $this->removed[] = $stat; |
||
| 4725 | if ($stat['mime'] === 'directory') { |
||
| 4726 | $this->updateSubdirsCache($dst, true); |
||
| 4727 | } |
||
| 4728 | |||
| 4729 | return is_string($res) ? $res : $this->joinPathCE($dst, $name); |
||
| 4730 | } |
||
| 4731 | |||
| 4732 | return $this->setError(elFinder::ERROR_MOVE, $this->path($stat['hash'])); |
||
| 4733 | } |
||
| 4734 | |||
| 4735 | /** |
||
| 4736 | * Copy file from another volume. |
||
| 4737 | * Return new file path or false. |
||
| 4738 | * |
||
| 4739 | * @param object $volume source volume |
||
| 4740 | * @param string $src source file hash |
||
| 4741 | * @param string $destination destination dir path |
||
| 4742 | * @param string $name file name |
||
| 4743 | * @return string|false |
||
| 4744 | * @author Dmitry (dio) Levashov |
||
| 4745 | **/ |
||
| 4746 | protected function copyFrom($volume, $src, $destination, $name) |
||
| 4747 | { |
||
| 4748 | elFinder::extendTimeLimit(); |
||
| 4749 | |||
| 4750 | if (($source = $volume->file($src)) == false) { |
||
| 4751 | return $this->setError(elFinder::ERROR_COPY, '#'.$src, $volume->error()); |
||
| 4752 | } |
||
| 4753 | |||
| 4754 | $srcIsDir = ($source['mime'] === 'directory'); |
||
| 4755 | |||
| 4756 | $errpath = $volume->path($source['hash']); |
||
| 4757 | |||
| 4758 | if (! $this->nameAccepted($source['name'], $srcIsDir)) { |
||
| 4759 | return $this->setError(elFinder::ERROR_COPY, $errpath, $srcIsDir ? elFinder::ERROR_INVALID_DIRNAME : elFinder::ERROR_INVALID_NAME); |
||
| 4760 | } |
||
| 4761 | |||
| 4762 | if (! $source['read']) { |
||
| 4763 | return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED); |
||
| 4764 | } |
||
| 4765 | |||
| 4766 | if ($srcIsDir) { |
||
| 4767 | $test = $this->isNameExists($this->joinPathCE($destination, $name)); |
||
| 4768 | $this->clearcache(); |
||
| 4769 | |||
| 4770 | View Code Duplication | if (($test && $test['mime'] != 'directory') || (! $test && ! $test = $this->mkdir($this->encode($destination), $name))) { |
|
| 4771 | return $this->setError(elFinder::ERROR_COPY, $errpath); |
||
| 4772 | } |
||
| 4773 | |||
| 4774 | //$path = $this->joinPathCE($destination, $name); |
||
| 4775 | $path = $this->decode($test['hash']); |
||
| 4776 | |||
| 4777 | foreach ($volume->scandir($src) as $entr) { |
||
| 4778 | if (! $this->copyFrom($volume, $entr['hash'], $path, $entr['name'])) { |
||
| 4779 | $this->remove($path, true); // fall back |
||
| 4780 | return $this->setError($this->error, elFinder::ERROR_COPY, $errpath); |
||
| 4781 | } |
||
| 4782 | } |
||
| 4783 | |||
| 4784 | $this->added[] = $test; |
||
| 4785 | } else { |
||
| 4786 | // MIME check |
||
| 4787 | $mimeByName = $this->mimetype($source['name'], true); |
||
| 4788 | if ($source['mime'] === $mimeByName) { |
||
| 4789 | $mimeByName = ''; |
||
| 4790 | } |
||
| 4791 | View Code Duplication | if (! $this->allowPutMime($source['mime']) || ($mimeByName && ! $this->allowPutMime($mimeByName))) { |
|
| 4792 | return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $errpath); |
||
| 4793 | } |
||
| 4794 | |||
| 4795 | if (strpos($source['mime'], 'image') === 0 && ($dim = $volume->dimensions($src))) { |
||
| 4796 | $s = explode('x', $dim); |
||
| 4797 | $source['width'] = $s[0]; |
||
| 4798 | $source['height'] = $s[1]; |
||
| 4799 | } |
||
| 4800 | |||
| 4801 | if (($fp = $volume->open($src)) == false |
||
| 4802 | || ($path = $this->saveCE($fp, $destination, $name, $source)) == false) { |
||
| 4803 | $fp && $volume->close($fp, $src); |
||
| 4804 | |||
| 4805 | return $this->setError(elFinder::ERROR_COPY, $errpath); |
||
| 4806 | } |
||
| 4807 | $volume->close($fp, $src); |
||
| 4808 | |||
| 4809 | $this->added[] = $this->stat($path); |
||
| 4810 | } |
||
| 4811 | |||
| 4812 | return $path; |
||
| 4813 | } |
||
| 4814 | |||
| 4815 | /** |
||
| 4816 | * Remove file/ recursive remove dir. |
||
| 4817 | * |
||
| 4818 | * @param string $path file path |
||
| 4819 | * @param bool $force try to remove even if file locked |
||
| 4820 | * @return bool |
||
| 4821 | * @author Dmitry (dio) Levashov |
||
| 4822 | **/ |
||
| 4823 | protected function remove($path, $force = false) |
||
| 4824 | { |
||
| 4825 | $stat = $this->stat($path); |
||
| 4826 | |||
| 4827 | if (empty($stat)) { |
||
| 4828 | return $this->setError(elFinder::ERROR_RM, $path, elFinder::ERROR_FILE_NOT_FOUND); |
||
| 4829 | } |
||
| 4830 | |||
| 4831 | $stat['realpath'] = $path; |
||
| 4832 | $this->rmTmb($stat); |
||
| 4833 | $this->clearcache(); |
||
| 4834 | |||
| 4835 | if (! $force && ! empty($stat['locked'])) { |
||
| 4836 | return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash'])); |
||
| 4837 | } |
||
| 4838 | |||
| 4839 | if ($stat['mime'] == 'directory' && empty($stat['thash'])) { |
||
| 4840 | $ret = $this->delTree($this->convEncIn($path)); |
||
| 4841 | $this->convEncOut(); |
||
| 4842 | if (! $ret) { |
||
| 4843 | return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash'])); |
||
| 4844 | } |
||
| 4845 | View Code Duplication | } else { |
|
| 4846 | if ($this->convEncOut(! $this->_unlink($this->convEncIn($path)))) { |
||
| 4847 | return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash'])); |
||
| 4848 | } |
||
| 4849 | } |
||
| 4850 | |||
| 4851 | $this->removed[] = $stat; |
||
| 4852 | |||
| 4853 | return true; |
||
| 4854 | } |
||
| 4855 | |||
| 4856 | /************************* thumbnails **************************/ |
||
| 4857 | |||
| 4858 | /** |
||
| 4859 | * Return thumbnail file name for required file. |
||
| 4860 | * |
||
| 4861 | * @param array $stat file stat |
||
| 4862 | * @return string |
||
| 4863 | * @author Dmitry (dio) Levashov |
||
| 4864 | **/ |
||
| 4865 | protected function tmbname($stat) |
||
| 4866 | { |
||
| 4867 | return $stat['hash'].$stat['ts'].'.png'; |
||
| 4868 | } |
||
| 4869 | |||
| 4870 | /** |
||
| 4871 | * Return thumnbnail name if exists. |
||
| 4872 | * |
||
| 4873 | * @param string $path file path |
||
| 4874 | * @param array $stat file stat |
||
| 4875 | * @return string|false |
||
| 4876 | * @author Dmitry (dio) Levashov |
||
| 4877 | **/ |
||
| 4878 | protected function gettmb($path, $stat) |
||
| 4879 | { |
||
| 4880 | if ($this->tmbURL && $this->tmbPath) { |
||
| 4881 | // file itself thumnbnail |
||
| 4882 | if (strpos($path, $this->tmbPath) === 0) { |
||
| 4883 | return basename($path); |
||
| 4884 | } |
||
| 4885 | |||
| 4886 | $name = $this->tmbname($stat); |
||
| 4887 | if (file_exists($this->tmbPath.DIRECTORY_SEPARATOR.$name)) { |
||
| 4888 | return $name; |
||
| 4889 | } |
||
| 4890 | } |
||
| 4891 | |||
| 4892 | return false; |
||
| 4893 | } |
||
| 4894 | |||
| 4895 | /** |
||
| 4896 | * Return true if thumnbnail for required file can be created. |
||
| 4897 | * |
||
| 4898 | * @param string $path thumnbnail path |
||
| 4899 | * @param array $stat file stat |
||
| 4900 | * @param bool $checkTmbPath |
||
| 4901 | * @return string|bool |
||
| 4902 | * @author Dmitry (dio) Levashov |
||
| 4903 | **/ |
||
| 4904 | protected function canCreateTmb($path, $stat, $checkTmbPath = true) |
||
| 4905 | { |
||
| 4906 | if ((! $checkTmbPath || $this->tmbPathWritable) |
||
| 4907 | && (! $this->tmbPath || strpos($path, $this->tmbPath) === false) // do not create thumnbnail for thumnbnail |
||
| 4908 | ) { |
||
| 4909 | $mime = strtolower($stat['mime']); |
||
| 4910 | list($type) = explode('/', $mime); |
||
| 4911 | if (! empty($this->imgConverter)) { |
||
| 4912 | if (isset($this->imgConverter[$mime])) { |
||
| 4913 | return true; |
||
| 4914 | } |
||
| 4915 | if (isset($this->imgConverter[$type])) { |
||
| 4916 | return true; |
||
| 4917 | } |
||
| 4918 | } |
||
| 4919 | |||
| 4920 | return $this->imgLib |
||
| 4921 | && ($type === 'image') |
||
| 4922 | && ($this->imgLib == 'gd' ? in_array($stat['mime'], ['image/jpeg', 'image/png', 'image/gif', 'image/x-ms-bmp']) : true); |
||
| 4923 | } |
||
| 4924 | |||
| 4925 | return false; |
||
| 4926 | } |
||
| 4927 | |||
| 4928 | /** |
||
| 4929 | * Return true if required file can be resized. |
||
| 4930 | * By default - the same as canCreateTmb. |
||
| 4931 | * |
||
| 4932 | * @param string $path thumnbnail path |
||
| 4933 | * @param array $stat file stat |
||
| 4934 | * @return string|bool |
||
| 4935 | * @author Dmitry (dio) Levashov |
||
| 4936 | **/ |
||
| 4937 | protected function canResize($path, $stat) |
||
| 4938 | { |
||
| 4939 | return $this->canCreateTmb($path, $stat, false); |
||
| 4940 | } |
||
| 4941 | |||
| 4942 | /** |
||
| 4943 | * Create thumnbnail and return it's URL on success. |
||
| 4944 | * |
||
| 4945 | * @param string $path file path |
||
| 4946 | * @param $stat |
||
| 4947 | * @return false|string |
||
| 4948 | * @internal param string $mime file mime type |
||
| 4949 | * @author Dmitry (dio) Levashov |
||
| 4950 | */ |
||
| 4951 | protected function createTmb($path, $stat) |
||
| 4952 | { |
||
| 4953 | if (! $stat || ! $this->canCreateTmb($path, $stat)) { |
||
| 4954 | return false; |
||
| 4955 | } |
||
| 4956 | |||
| 4957 | $name = $this->tmbname($stat); |
||
| 4958 | $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name; |
||
| 4959 | |||
| 4960 | $maxlength = -1; |
||
| 4961 | $imgConverter = null; |
||
| 4962 | |||
| 4963 | // check imgConverter |
||
| 4964 | $mime = strtolower($stat['mime']); |
||
| 4965 | list($type) = explode('/', $mime); |
||
| 4966 | if (isset($this->imgConverter[$mime])) { |
||
| 4967 | $imgConverter = $this->imgConverter[$mime]['func']; |
||
| 4968 | View Code Duplication | if (! empty($this->imgConverter[$mime]['maxlen'])) { |
|
| 4969 | $maxlength = intval($this->imgConverter[$mime]['maxlen']); |
||
| 4970 | } |
||
| 4971 | } elseif (isset($this->imgConverter[$type])) { |
||
| 4972 | $imgConverter = $this->imgConverter[$type]['func']; |
||
| 4973 | View Code Duplication | if (! empty($this->imgConverter[$type]['maxlen'])) { |
|
| 4974 | $maxlength = intval($this->imgConverter[$type]['maxlen']); |
||
| 4975 | } |
||
| 4976 | } |
||
| 4977 | if ($imgConverter && ! is_callable($imgConverter)) { |
||
| 4978 | return false; |
||
| 4979 | } |
||
| 4980 | |||
| 4981 | // copy image into tmbPath so some drivers does not store files on local fs |
||
| 4982 | if (($src = $this->fopenCE($path, 'rb')) == false) { |
||
| 4983 | return false; |
||
| 4984 | } |
||
| 4985 | |||
| 4986 | if (($trg = fopen($tmb, 'wb')) == false) { |
||
| 4987 | $this->fcloseCE($src, $path); |
||
| 4988 | |||
| 4989 | return false; |
||
| 4990 | } |
||
| 4991 | |||
| 4992 | stream_copy_to_stream($src, $trg, $maxlength); |
||
| 4993 | |||
| 4994 | $this->fcloseCE($src, $path); |
||
| 4995 | fclose($trg); |
||
| 4996 | |||
| 4997 | // call imgConverter |
||
| 4998 | if ($imgConverter) { |
||
| 4999 | if (! call_user_func_array($imgConverter, [$tmb, $stat, $this])) { |
||
| 5000 | file_exists($tmb) && unlink($tmb); |
||
| 5001 | |||
| 5002 | return false; |
||
| 5003 | } |
||
| 5004 | } |
||
| 5005 | |||
| 5006 | $result = false; |
||
| 5007 | |||
| 5008 | $tmbSize = $this->tmbSize; |
||
| 5009 | |||
| 5010 | if ($this->imgLib === 'imagick') { |
||
| 5011 | try { |
||
| 5012 | $imagickTest = new imagick($tmb); |
||
| 5013 | $imagickTest->clear(); |
||
| 5014 | $imagickTest = true; |
||
| 5015 | } catch (Exception $e) { |
||
| 5016 | $imagickTest = false; |
||
| 5017 | } |
||
| 5018 | } |
||
| 5019 | |||
| 5020 | if (($this->imgLib === 'imagick' && ! $imagickTest) || ($s = getimagesize($tmb)) === false) { |
||
| 5021 | if ($this->imgLib === 'imagick') { |
||
| 5022 | $bgcolor = $this->options['tmbBgColor']; |
||
| 5023 | if ($bgcolor === 'transparent') { |
||
| 5024 | $bgcolor = 'rgba(255, 255, 255, 0.0)'; |
||
| 5025 | } |
||
| 5026 | try { |
||
| 5027 | $imagick = new imagick(); |
||
| 5028 | $imagick->setBackgroundColor(new ImagickPixel($bgcolor)); |
||
| 5029 | $imagick->readImage($this->getExtentionByMime($stat['mime'], ':').$tmb); |
||
| 5030 | $imagick->setImageFormat('png'); |
||
| 5031 | $imagick->writeImage($tmb); |
||
| 5032 | $imagick->clear(); |
||
| 5033 | if (($s = getimagesize($tmb)) !== false) { |
||
| 5034 | $result = true; |
||
| 5035 | } |
||
| 5036 | } catch (Exception $e) { |
||
| 5037 | } |
||
| 5038 | } |
||
| 5039 | if (! $result) { |
||
| 5040 | file_exists($tmb) && unlink($tmb); |
||
| 5041 | |||
| 5042 | return false; |
||
| 5043 | } |
||
| 5044 | $result = false; |
||
| 5045 | } |
||
| 5046 | |||
| 5047 | /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ |
||
| 5048 | if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { |
||
| 5049 | $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); |
||
| 5050 | } else { |
||
| 5051 | if ($this->options['tmbCrop']) { |
||
| 5052 | $result = $tmb; |
||
| 5053 | /* Resize and crop if image bigger than thumbnail */ |
||
| 5054 | if (! (($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { |
||
| 5055 | $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); |
||
| 5056 | } |
||
| 5057 | |||
| 5058 | if ($result && ($s = getimagesize($tmb)) != false) { |
||
| 5059 | $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0; |
||
| 5060 | $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0; |
||
| 5061 | $result = $this->imgCrop($result, $tmbSize, $tmbSize, $x, $y, 'png'); |
||
| 5062 | } else { |
||
| 5063 | $result = false; |
||
| 5064 | } |
||
| 5065 | } else { |
||
| 5066 | $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); |
||
| 5067 | } |
||
| 5068 | |||
| 5069 | if ($result) { |
||
| 5070 | if ($s = getimagesize($tmb)) { |
||
| 5071 | if ($s[0] !== $tmbSize || $s[1] !== $tmbSize) { |
||
| 5072 | $result = $this->imgSquareFit($result, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); |
||
| 5073 | } |
||
| 5074 | } |
||
| 5075 | } |
||
| 5076 | } |
||
| 5077 | |||
| 5078 | if (! $result) { |
||
| 5079 | unlink($tmb); |
||
| 5080 | |||
| 5081 | return false; |
||
| 5082 | } |
||
| 5083 | |||
| 5084 | return $name; |
||
| 5085 | } |
||
| 5086 | |||
| 5087 | /** |
||
| 5088 | * Resize image. |
||
| 5089 | * |
||
| 5090 | * @param string $path image file |
||
| 5091 | * @param int $width new width |
||
| 5092 | * @param int $height new height |
||
| 5093 | * @param bool $keepProportions crop image |
||
| 5094 | * @param bool $resizeByBiggerSide resize image based on bigger side if true |
||
| 5095 | * @param string $destformat image destination format |
||
| 5096 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 5097 | * @param array $options Other extra options |
||
| 5098 | * @return string|false |
||
| 5099 | * @author Dmitry (dio) Levashov |
||
| 5100 | * @author Alexey Sukhotin |
||
| 5101 | **/ |
||
| 5102 | protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null, $jpgQuality = null, $options = []) |
||
| 5103 | { |
||
| 5104 | if (($s = getimagesize($path)) == false) { |
||
| 5105 | return false; |
||
| 5106 | } |
||
| 5107 | |||
| 5108 | $result = false; |
||
| 5109 | |||
| 5110 | if (! $jpgQuality) { |
||
| 5111 | $jpgQuality = $this->options['jpgQuality']; |
||
| 5112 | } |
||
| 5113 | |||
| 5114 | list($orig_w, $orig_h) = [$s[0], $s[1]]; |
||
| 5115 | list($size_w, $size_h) = [$width, $height]; |
||
| 5116 | |||
| 5117 | if (empty($options['unenlarge']) || $orig_w > $size_w || $orig_h > $size_h) { |
||
| 5118 | if ($keepProportions == true) { |
||
| 5119 | /* Resizing by biggest side */ |
||
| 5120 | if ($resizeByBiggerSide) { |
||
| 5121 | View Code Duplication | if ($orig_w > $orig_h) { |
|
| 5122 | $size_h = round($orig_h * $width / $orig_w); |
||
| 5123 | $size_w = $width; |
||
| 5124 | } else { |
||
| 5125 | $size_w = round($orig_w * $height / $orig_h); |
||
| 5126 | $size_h = $height; |
||
| 5127 | } |
||
| 5128 | View Code Duplication | } else { |
|
| 5129 | if ($orig_w > $orig_h) { |
||
| 5130 | $size_w = round($orig_w * $height / $orig_h); |
||
| 5131 | $size_h = $height; |
||
| 5132 | } else { |
||
| 5133 | $size_h = round($orig_h * $width / $orig_w); |
||
| 5134 | $size_w = $width; |
||
| 5135 | } |
||
| 5136 | } |
||
| 5137 | } |
||
| 5138 | } else { |
||
| 5139 | $size_w = $orig_w; |
||
| 5140 | $size_h = $orig_h; |
||
| 5141 | } |
||
| 5142 | |||
| 5143 | elFinder::extendTimeLimit(300); |
||
| 5144 | switch ($this->imgLib) { |
||
| 5145 | case 'imagick': |
||
| 5146 | |||
| 5147 | try { |
||
| 5148 | $img = new imagick($path); |
||
| 5149 | } catch (Exception $e) { |
||
| 5150 | return false; |
||
| 5151 | } |
||
| 5152 | |||
| 5153 | // Imagick::FILTER_BOX faster than FILTER_LANCZOS so use for createTmb |
||
| 5154 | // resize bench: http://app-mgng.rhcloud.com/9 |
||
| 5155 | // resize sample: http://www.dylanbeattie.net/magick/filters/result.html |
||
| 5156 | $filter = ($destformat === 'png' /* createTmb */) ? Imagick::FILTER_BOX : Imagick::FILTER_LANCZOS; |
||
| 5157 | |||
| 5158 | $ani = ($img->getNumberImages() > 1); |
||
| 5159 | if ($ani && is_null($destformat)) { |
||
| 5160 | $img = $img->coalesceImages(); |
||
| 5161 | do { |
||
| 5162 | $img->resizeImage($size_w, $size_h, $filter, 1); |
||
| 5163 | } while ($img->nextImage()); |
||
| 5164 | $img = $img->optimizeImageLayers(); |
||
| 5165 | $result = $img->writeImages($path, true); |
||
| 5166 | } else { |
||
| 5167 | if ($ani) { |
||
| 5168 | $img->setFirstIterator(); |
||
| 5169 | } |
||
| 5170 | if (strtoupper($img->getImageFormat()) === 'JPEG') { |
||
| 5171 | $img->setImageCompression(imagick::COMPRESSION_JPEG); |
||
| 5172 | $img->setImageCompressionQuality($jpgQuality); |
||
| 5173 | if (isset($options['preserveExif']) && ! $options['preserveExif']) { |
||
| 5174 | try { |
||
| 5175 | $orientation = $img->getImageOrientation(); |
||
| 5176 | } catch (ImagickException $e) { |
||
| 5177 | $orientation = 0; |
||
| 5178 | } |
||
| 5179 | $img->stripImage(); |
||
| 5180 | if ($orientation) { |
||
| 5181 | $img->setImageOrientation($orientation); |
||
| 5182 | } |
||
| 5183 | } |
||
| 5184 | } |
||
| 5185 | $img->resizeImage($size_w, $size_h, $filter, true); |
||
| 5186 | if ($destformat) { |
||
| 5187 | $result = $this->imagickImage($img, $path, $destformat, $jpgQuality); |
||
| 5188 | } else { |
||
| 5189 | $result = $img->writeImage($path); |
||
| 5190 | } |
||
| 5191 | } |
||
| 5192 | |||
| 5193 | $img->clear(); |
||
| 5194 | |||
| 5195 | return $result ? $path : false; |
||
| 5196 | |||
| 5197 | break; |
||
| 5198 | |||
| 5199 | case 'convert': |
||
| 5200 | extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); |
||
| 5201 | $filter = ($destformat === 'png' /* createTmb */) ? '-filter Box' : '-filter Lanczos'; |
||
| 5202 | $strip = (isset($options['preserveExif']) && ! $options['preserveExif']) ? ' -strip' : ''; |
||
| 5203 | //$cmd = sprintf('convert%s%s +repage %s -resize %dx%d +repage%s %s %s', $coalesce, $jpgQuality, $filter, $size_w, $size_h, $deconstruct, $quotedPath, $quotedDstPath); |
||
| 5204 | $cmd = sprintf('convert %s%s%s %s -geometry %dx%d! %s %s', $quotedPath, $coalesce, $jpgQuality, $filter, $size_w, $size_h, $deconstruct, $quotedDstPath); |
||
| 5205 | |||
| 5206 | $result = false; |
||
| 5207 | if ($this->procExec($cmd) === 0) { |
||
| 5208 | $result = true; |
||
| 5209 | } |
||
| 5210 | |||
| 5211 | return $result ? $path : false; |
||
| 5212 | |||
| 5213 | break; |
||
| 5214 | |||
| 5215 | case 'gd': |
||
| 5216 | $img = $this->gdImageCreate($path, $s['mime']); |
||
| 5217 | |||
| 5218 | if ($img && false != ($tmp = imagecreatetruecolor($size_w, $size_h))) { |
||
| 5219 | $bgNum = false; |
||
| 5220 | View Code Duplication | if ($s[2] === IMAGETYPE_GIF && (! $destformat || $destformat === 'gif')) { |
|
| 5221 | $bgIdx = imagecolortransparent($img); |
||
| 5222 | if ($bgIdx !== -1) { |
||
| 5223 | $c = imagecolorsforindex($img, $bgIdx); |
||
| 5224 | $bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']); |
||
| 5225 | imagefill($tmp, 0, 0, $bgNum); |
||
| 5226 | imagecolortransparent($tmp, $bgNum); |
||
| 5227 | } |
||
| 5228 | } |
||
| 5229 | if ($bgNum === false) { |
||
| 5230 | $this->gdImageBackground($tmp, 'transparent'); |
||
| 5231 | } |
||
| 5232 | |||
| 5233 | if (! imagecopyresampled($tmp, $img, 0, 0, 0, 0, $size_w, $size_h, $s[0], $s[1])) { |
||
| 5234 | return false; |
||
| 5235 | } |
||
| 5236 | |||
| 5237 | $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); |
||
| 5238 | |||
| 5239 | imagedestroy($img); |
||
| 5240 | imagedestroy($tmp); |
||
| 5241 | |||
| 5242 | return $result ? $path : false; |
||
| 5243 | } |
||
| 5244 | break; |
||
| 5245 | } |
||
| 5246 | |||
| 5247 | return false; |
||
| 5248 | } |
||
| 5249 | |||
| 5250 | /** |
||
| 5251 | * Crop image. |
||
| 5252 | * |
||
| 5253 | * @param string $path image file |
||
| 5254 | * @param int $width crop width |
||
| 5255 | * @param int $height crop height |
||
| 5256 | * @param bool $x crop left offset |
||
| 5257 | * @param bool $y crop top offset |
||
| 5258 | * @param string $destformat image destination format |
||
| 5259 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 5260 | * @return string|false |
||
| 5261 | * @author Dmitry (dio) Levashov |
||
| 5262 | * @author Alexey Sukhotin |
||
| 5263 | **/ |
||
| 5264 | protected function imgCrop($path, $width, $height, $x, $y, $destformat = null, $jpgQuality = null) |
||
| 5265 | { |
||
| 5266 | if (($s = getimagesize($path)) == false) { |
||
| 5267 | return false; |
||
| 5268 | } |
||
| 5269 | |||
| 5270 | $result = false; |
||
| 5271 | |||
| 5272 | if (! $jpgQuality) { |
||
| 5273 | $jpgQuality = $this->options['jpgQuality']; |
||
| 5274 | } |
||
| 5275 | |||
| 5276 | elFinder::extendTimeLimit(300); |
||
| 5277 | switch ($this->imgLib) { |
||
| 5278 | case 'imagick': |
||
| 5279 | |||
| 5280 | try { |
||
| 5281 | $img = new imagick($path); |
||
| 5282 | } catch (Exception $e) { |
||
| 5283 | return false; |
||
| 5284 | } |
||
| 5285 | |||
| 5286 | $ani = ($img->getNumberImages() > 1); |
||
| 5287 | if ($ani && is_null($destformat)) { |
||
| 5288 | $img = $img->coalesceImages(); |
||
| 5289 | do { |
||
| 5290 | $img->setImagePage($s[0], $s[1], 0, 0); |
||
| 5291 | $img->cropImage($width, $height, $x, $y); |
||
| 5292 | $img->setImagePage($width, $height, 0, 0); |
||
| 5293 | } while ($img->nextImage()); |
||
| 5294 | $img = $img->optimizeImageLayers(); |
||
| 5295 | $result = $img->writeImages($path, true); |
||
| 5296 | } else { |
||
| 5297 | if ($ani) { |
||
| 5298 | $img->setFirstIterator(); |
||
| 5299 | } |
||
| 5300 | $img->setImagePage($s[0], $s[1], 0, 0); |
||
| 5301 | $img->cropImage($width, $height, $x, $y); |
||
| 5302 | $img->setImagePage($width, $height, 0, 0); |
||
| 5303 | $result = $this->imagickImage($img, $path, $destformat, $jpgQuality); |
||
| 5304 | } |
||
| 5305 | |||
| 5306 | $img->clear(); |
||
| 5307 | |||
| 5308 | return $result ? $path : false; |
||
| 5309 | |||
| 5310 | break; |
||
| 5311 | |||
| 5312 | case 'convert': |
||
| 5313 | extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); |
||
| 5314 | $cmd = sprintf('convert %s%s%s -crop %dx%d+%d+%d%s %s', $quotedPath, $coalesce, $jpgQuality, $width, $height, $x, $y, $deconstruct, $quotedDstPath); |
||
| 5315 | |||
| 5316 | $result = false; |
||
| 5317 | if ($this->procExec($cmd) === 0) { |
||
| 5318 | $result = true; |
||
| 5319 | } |
||
| 5320 | |||
| 5321 | return $result ? $path : false; |
||
| 5322 | |||
| 5323 | break; |
||
| 5324 | |||
| 5325 | case 'gd': |
||
| 5326 | $img = $this->gdImageCreate($path, $s['mime']); |
||
| 5327 | |||
| 5328 | if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { |
||
| 5329 | $bgNum = false; |
||
| 5330 | View Code Duplication | if ($s[2] === IMAGETYPE_GIF && (! $destformat || $destformat === 'gif')) { |
|
| 5331 | $bgIdx = imagecolortransparent($img); |
||
| 5332 | if ($bgIdx !== -1) { |
||
| 5333 | $c = imagecolorsforindex($img, $bgIdx); |
||
| 5334 | $bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']); |
||
| 5335 | imagefill($tmp, 0, 0, $bgNum); |
||
| 5336 | imagecolortransparent($tmp, $bgNum); |
||
| 5337 | } |
||
| 5338 | } |
||
| 5339 | if ($bgNum === false) { |
||
| 5340 | $this->gdImageBackground($tmp, 'transparent'); |
||
| 5341 | } |
||
| 5342 | |||
| 5343 | $size_w = $width; |
||
| 5344 | $size_h = $height; |
||
| 5345 | |||
| 5346 | if ($s[0] < $width || $s[1] < $height) { |
||
| 5347 | $size_w = $s[0]; |
||
| 5348 | $size_h = $s[1]; |
||
| 5349 | } |
||
| 5350 | |||
| 5351 | if (! imagecopy($tmp, $img, 0, 0, $x, $y, $size_w, $size_h)) { |
||
| 5352 | return false; |
||
| 5353 | } |
||
| 5354 | |||
| 5355 | $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); |
||
| 5356 | |||
| 5357 | imagedestroy($img); |
||
| 5358 | imagedestroy($tmp); |
||
| 5359 | |||
| 5360 | return $result ? $path : false; |
||
| 5361 | } |
||
| 5362 | break; |
||
| 5363 | } |
||
| 5364 | |||
| 5365 | return false; |
||
| 5366 | } |
||
| 5367 | |||
| 5368 | /** |
||
| 5369 | * Put image to square. |
||
| 5370 | * |
||
| 5371 | * @param string $path image file |
||
| 5372 | * @param int $width square width |
||
| 5373 | * @param int $height square height |
||
| 5374 | * @param int|string $align reserved |
||
| 5375 | * @param int|string $valign reserved |
||
| 5376 | * @param string $bgcolor square background color in #rrggbb format |
||
| 5377 | * @param string $destformat image destination format |
||
| 5378 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 5379 | * @return false|string |
||
| 5380 | * @author Dmitry (dio) Levashov |
||
| 5381 | * @author Alexey Sukhotin |
||
| 5382 | */ |
||
| 5383 | protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null, $jpgQuality = null) |
||
| 5384 | { |
||
| 5385 | if (($s = getimagesize($path)) == false) { |
||
| 5386 | return false; |
||
| 5387 | } |
||
| 5388 | |||
| 5389 | $result = false; |
||
| 5390 | |||
| 5391 | /* Coordinates for image over square aligning */ |
||
| 5392 | $y = ceil(abs($height - $s[1]) / 2); |
||
| 5393 | $x = ceil(abs($width - $s[0]) / 2); |
||
| 5394 | |||
| 5395 | if (! $jpgQuality) { |
||
| 5396 | $jpgQuality = $this->options['jpgQuality']; |
||
| 5397 | } |
||
| 5398 | |||
| 5399 | elFinder::extendTimeLimit(300); |
||
| 5400 | switch ($this->imgLib) { |
||
| 5401 | case 'imagick': |
||
| 5402 | try { |
||
| 5403 | $img = new imagick($path); |
||
| 5404 | } catch (Exception $e) { |
||
| 5405 | return false; |
||
| 5406 | } |
||
| 5407 | |||
| 5408 | if ($bgcolor === 'transparent') { |
||
| 5409 | $bgcolor = 'rgba(255, 255, 255, 0.0)'; |
||
| 5410 | } |
||
| 5411 | $ani = ($img->getNumberImages() > 1); |
||
| 5412 | if ($ani && is_null($destformat)) { |
||
| 5413 | $img1 = new Imagick(); |
||
| 5414 | $img1->setFormat('gif'); |
||
| 5415 | $img = $img->coalesceImages(); |
||
| 5416 | do { |
||
| 5417 | $gif = new Imagick(); |
||
| 5418 | $gif->newImage($width, $height, new ImagickPixel($bgcolor)); |
||
| 5419 | $gif->setImageColorspace($img->getImageColorspace()); |
||
| 5420 | $gif->setImageFormat('gif'); |
||
| 5421 | $gif->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); |
||
| 5422 | $gif->setImageDelay($img->getImageDelay()); |
||
| 5423 | $gif->setImageIterations($img->getImageIterations()); |
||
| 5424 | $img1->addImage($gif); |
||
| 5425 | $gif->clear(); |
||
| 5426 | } while ($img->nextImage()); |
||
| 5427 | $img1 = $img1->optimizeImageLayers(); |
||
| 5428 | $result = $img1->writeImages($path, true); |
||
| 5429 | } else { |
||
| 5430 | if ($ani) { |
||
| 5431 | $img->setFirstIterator(); |
||
| 5432 | } |
||
| 5433 | $img1 = new Imagick(); |
||
| 5434 | $img1->newImage($width, $height, new ImagickPixel($bgcolor)); |
||
| 5435 | $img1->setImageColorspace($img->getImageColorspace()); |
||
| 5436 | $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); |
||
| 5437 | $result = $this->imagickImage($img1, $path, $destformat, $jpgQuality); |
||
| 5438 | } |
||
| 5439 | |||
| 5440 | $img1->clear(); |
||
| 5441 | $img->clear(); |
||
| 5442 | |||
| 5443 | return $result ? $path : false; |
||
| 5444 | |||
| 5445 | break; |
||
| 5446 | |||
| 5447 | case 'convert': |
||
| 5448 | extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); |
||
| 5449 | if ($bgcolor === 'transparent') { |
||
| 5450 | $bgcolor = 'rgba(255, 255, 255, 0.0)'; |
||
| 5451 | } |
||
| 5452 | $cmd = sprintf('convert -size %dx%d "xc:%s" png:- | convert%s%s png:- %s -geometry +%d+%d -compose over -composite%s %s', $width, $height, $bgcolor, $coalesce, $jpgQuality, $quotedPath, $x, $y, $deconstruct, $quotedDstPath); |
||
| 5453 | |||
| 5454 | $result = false; |
||
| 5455 | if ($this->procExec($cmd) === 0) { |
||
| 5456 | $result = true; |
||
| 5457 | } |
||
| 5458 | |||
| 5459 | return $result ? $path : false; |
||
| 5460 | |||
| 5461 | break; |
||
| 5462 | |||
| 5463 | case 'gd': |
||
| 5464 | $img = $this->gdImageCreate($path, $s['mime']); |
||
| 5465 | |||
| 5466 | if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { |
||
| 5467 | $this->gdImageBackground($tmp, $bgcolor); |
||
| 5468 | if ($bgcolor === 'transparent' && ($destformat === 'png' || $s[2] === IMAGETYPE_PNG)) { |
||
| 5469 | $bgNum = imagecolorallocatealpha($tmp, 255, 255, 255, 127); |
||
| 5470 | imagefill($tmp, 0, 0, $bgNum); |
||
| 5471 | } |
||
| 5472 | |||
| 5473 | if (! imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { |
||
| 5474 | return false; |
||
| 5475 | } |
||
| 5476 | |||
| 5477 | $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); |
||
| 5478 | |||
| 5479 | imagedestroy($img); |
||
| 5480 | imagedestroy($tmp); |
||
| 5481 | |||
| 5482 | return $result ? $path : false; |
||
| 5483 | } |
||
| 5484 | break; |
||
| 5485 | } |
||
| 5486 | |||
| 5487 | return false; |
||
| 5488 | } |
||
| 5489 | |||
| 5490 | /** |
||
| 5491 | * Rotate image. |
||
| 5492 | * |
||
| 5493 | * @param string $path image file |
||
| 5494 | * @param int $degree rotete degrees |
||
| 5495 | * @param string $bgcolor square background color in #rrggbb format |
||
| 5496 | * @param string $destformat image destination format |
||
| 5497 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 5498 | * @return string|false |
||
| 5499 | * @author nao-pon |
||
| 5500 | * @author Troex Nevelin |
||
| 5501 | **/ |
||
| 5502 | protected function imgRotate($path, $degree, $bgcolor = '#ffffff', $destformat = null, $jpgQuality = null) |
||
| 5503 | { |
||
| 5504 | if (($s = getimagesize($path)) == false || $degree % 360 === 0) { |
||
| 5505 | return false; |
||
| 5506 | } |
||
| 5507 | |||
| 5508 | $result = false; |
||
| 5509 | |||
| 5510 | // try lossless rotate |
||
| 5511 | if ($degree % 90 === 0 && in_array($s[2], [IMAGETYPE_JPEG, IMAGETYPE_JPEG2000])) { |
||
| 5512 | $count = ($degree / 90) % 4; |
||
| 5513 | $exiftran = [ |
||
| 5514 | 1 => '-9', |
||
| 5515 | 2 => '-1', |
||
| 5516 | 3 => '-2', |
||
| 5517 | ]; |
||
| 5518 | $jpegtran = [ |
||
| 5519 | 1 => '90', |
||
| 5520 | 2 => '180', |
||
| 5521 | 3 => '270', |
||
| 5522 | ]; |
||
| 5523 | $quotedPath = escapeshellarg($path); |
||
| 5524 | $cmds = []; |
||
| 5525 | if ($this->procExec('exiftran -h') === 0) { |
||
| 5526 | $cmds[] = 'exiftran -i '.$exiftran[$count].' '.$path; |
||
| 5527 | } |
||
| 5528 | if ($this->procExec('jpegtran -version') === 0) { |
||
| 5529 | $cmds[] = 'jpegtran -rotate '.$jpegtran[$count].' -copy all -outfile '.$quotedPath.' '.$quotedPath; |
||
| 5530 | } |
||
| 5531 | foreach ($cmds as $cmd) { |
||
| 5532 | if ($this->procExec($cmd) === 0) { |
||
| 5533 | $result = true; |
||
| 5534 | break; |
||
| 5535 | } |
||
| 5536 | } |
||
| 5537 | if ($result) { |
||
| 5538 | return $path; |
||
| 5539 | } |
||
| 5540 | } |
||
| 5541 | |||
| 5542 | if (! $jpgQuality) { |
||
| 5543 | $jpgQuality = $this->options['jpgQuality']; |
||
| 5544 | } |
||
| 5545 | |||
| 5546 | elFinder::extendTimeLimit(300); |
||
| 5547 | switch ($this->imgLib) { |
||
| 5548 | case 'imagick': |
||
| 5549 | try { |
||
| 5550 | $img = new imagick($path); |
||
| 5551 | } catch (Exception $e) { |
||
| 5552 | return false; |
||
| 5553 | } |
||
| 5554 | |||
| 5555 | View Code Duplication | if ($s[2] === IMAGETYPE_GIF || $s[2] === IMAGETYPE_PNG) { |
|
| 5556 | $bgcolor = 'rgba(255, 255, 255, 0.0)'; |
||
| 5557 | } |
||
| 5558 | if ($img->getNumberImages() > 1) { |
||
| 5559 | $img = $img->coalesceImages(); |
||
| 5560 | do { |
||
| 5561 | $img->rotateImage(new ImagickPixel($bgcolor), $degree); |
||
| 5562 | } while ($img->nextImage()); |
||
| 5563 | $img = $img->optimizeImageLayers(); |
||
| 5564 | $result = $img->writeImages($path, true); |
||
| 5565 | } else { |
||
| 5566 | $img->rotateImage(new ImagickPixel($bgcolor), $degree); |
||
| 5567 | $result = $this->imagickImage($img, $path, $destformat, $jpgQuality); |
||
| 5568 | } |
||
| 5569 | $img->clear(); |
||
| 5570 | |||
| 5571 | return $result ? $path : false; |
||
| 5572 | |||
| 5573 | break; |
||
| 5574 | |||
| 5575 | case 'convert': |
||
| 5576 | extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); |
||
| 5577 | View Code Duplication | if ($s[2] === IMAGETYPE_GIF || $s[2] === IMAGETYPE_PNG) { |
|
| 5578 | $bgcolor = 'rgba(255, 255, 255, 0.0)'; |
||
| 5579 | } |
||
| 5580 | $cmd = sprintf('convert %s%s%s -background "%s" -rotate %d%s %s', $quotedPath, $coalesce, $jpgQuality, $bgcolor, $degree, $deconstruct, $quotedDstPath); |
||
| 5581 | |||
| 5582 | $result = false; |
||
| 5583 | if ($this->procExec($cmd) === 0) { |
||
| 5584 | $result = true; |
||
| 5585 | } |
||
| 5586 | |||
| 5587 | return $result ? $path : false; |
||
| 5588 | |||
| 5589 | break; |
||
| 5590 | |||
| 5591 | case 'gd': |
||
| 5592 | $img = $this->gdImageCreate($path, $s['mime']); |
||
| 5593 | |||
| 5594 | $degree = 360 - $degree; |
||
| 5595 | |||
| 5596 | $bgNum = -1; |
||
| 5597 | $bgIdx = false; |
||
| 5598 | if ($s[2] === IMAGETYPE_GIF) { |
||
| 5599 | $bgIdx = imagecolortransparent($img); |
||
| 5600 | if ($bgIdx !== -1) { |
||
| 5601 | $c = imagecolorsforindex($img, $bgIdx); |
||
| 5602 | $w = imagesx($img); |
||
| 5603 | $h = imagesy($img); |
||
| 5604 | $newImg = imagecreatetruecolor($w, $h); |
||
| 5605 | imagepalettecopy($newImg, $img); |
||
| 5606 | $bgNum = imagecolorallocate($newImg, $c['red'], $c['green'], $c['blue']); |
||
| 5607 | imagefill($newImg, 0, 0, $bgNum); |
||
| 5608 | imagecolortransparent($newImg, $bgNum); |
||
| 5609 | imagecopy($newImg, $img, 0, 0, 0, 0, $w, $h); |
||
| 5610 | imagedestroy($img); |
||
| 5611 | $img = $newImg; |
||
| 5612 | $newImg = null; |
||
| 5613 | } |
||
| 5614 | } elseif ($s[2] === IMAGETYPE_PNG) { |
||
| 5615 | $bgNum = imagecolorallocatealpha($img, 255, 255, 255, 127); |
||
| 5616 | } |
||
| 5617 | View Code Duplication | if ($bgNum === -1) { |
|
| 5618 | list($r, $g, $b) = sscanf($bgcolor, '#%02x%02x%02x'); |
||
| 5619 | $bgNum = imagecolorallocate($img, $r, $g, $b); |
||
| 5620 | } |
||
| 5621 | |||
| 5622 | $tmp = imagerotate($img, $degree, $bgNum); |
||
| 5623 | if ($bgIdx !== -1) { |
||
| 5624 | imagecolortransparent($tmp, $bgNum); |
||
| 5625 | } |
||
| 5626 | |||
| 5627 | $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); |
||
| 5628 | |||
| 5629 | imagedestroy($img); |
||
| 5630 | imagedestroy($tmp); |
||
| 5631 | |||
| 5632 | return $result ? $path : false; |
||
| 5633 | |||
| 5634 | break; |
||
| 5635 | } |
||
| 5636 | |||
| 5637 | return false; |
||
| 5638 | } |
||
| 5639 | |||
| 5640 | /** |
||
| 5641 | * Execute shell command. |
||
| 5642 | * |
||
| 5643 | * @param string $command command line |
||
| 5644 | * @param array $output stdout strings |
||
| 5645 | * @param array|int $return_var process exit code |
||
| 5646 | * @param array $error_output stderr strings |
||
| 5647 | * @return int exit code |
||
| 5648 | * @author Alexey Sukhotin |
||
| 5649 | */ |
||
| 5650 | protected function procExec($command, array &$output = null, &$return_var = -1, array &$error_output = null) |
||
| 5651 | { |
||
| 5652 | static $allowed = null; |
||
| 5653 | |||
| 5654 | if ($allowed === null) { |
||
| 5655 | if ($allowed = function_exists('proc_open')) { |
||
| 5656 | if ($disabled = ini_get('disable_functions')) { |
||
| 5657 | $funcs = array_map('trim', explode(',', $disabled)); |
||
| 5658 | $allowed = ! in_array('proc_open', $funcs); |
||
| 5659 | } |
||
| 5660 | } |
||
| 5661 | } |
||
| 5662 | |||
| 5663 | if (! $allowed) { |
||
| 5664 | $return_var = -1; |
||
| 5665 | |||
| 5666 | return $return_var; |
||
| 5667 | } |
||
| 5668 | |||
| 5669 | if (! $command) { |
||
| 5670 | $return_var = 0; |
||
| 5671 | |||
| 5672 | return $return_var; |
||
| 5673 | } |
||
| 5674 | |||
| 5675 | $descriptorspec = [ |
||
| 5676 | 0 => ['pipe', 'r'], // stdin |
||
| 5677 | 1 => ['pipe', 'w'], // stdout |
||
| 5678 | 2 => ['pipe', 'w'], // stderr |
||
| 5679 | ]; |
||
| 5680 | |||
| 5681 | $process = proc_open($command, $descriptorspec, $pipes, null, null); |
||
| 5682 | |||
| 5683 | if (is_resource($process)) { |
||
| 5684 | fclose($pipes[0]); |
||
| 5685 | |||
| 5686 | $tmpout = ''; |
||
| 5687 | $tmperr = ''; |
||
| 5688 | |||
| 5689 | $output = stream_get_contents($pipes[1]); |
||
| 5690 | $error_output = stream_get_contents($pipes[2]); |
||
| 5691 | |||
| 5692 | fclose($pipes[1]); |
||
| 5693 | fclose($pipes[2]); |
||
| 5694 | $return_var = proc_close($process); |
||
| 5695 | } else { |
||
| 5696 | $return_var = -1; |
||
| 5697 | } |
||
| 5698 | |||
| 5699 | return $return_var; |
||
| 5700 | } |
||
| 5701 | |||
| 5702 | /** |
||
| 5703 | * Remove thumbnail, also remove recursively if stat is directory. |
||
| 5704 | * |
||
| 5705 | * @param string $stat file stat |
||
| 5706 | * @return void |
||
| 5707 | * @author Dmitry (dio) Levashov |
||
| 5708 | * @author Naoki Sawada |
||
| 5709 | * @author Troex Nevelin |
||
| 5710 | **/ |
||
| 5711 | protected function rmTmb($stat) |
||
| 5712 | { |
||
| 5713 | if ($stat['mime'] === 'directory') { |
||
| 5714 | foreach ($this->scandirCE($this->decode($stat['hash'])) as $p) { |
||
| 5715 | elFinder::extendTimeLimit(30); |
||
| 5716 | $name = $this->basenameCE($p); |
||
| 5717 | $name != '.' && $name != '..' && $this->rmTmb($this->stat($p)); |
||
| 5718 | } |
||
| 5719 | } elseif (! empty($stat['tmb']) && $stat['tmb'] != '1') { |
||
| 5720 | $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$stat['tmb']; |
||
| 5721 | file_exists($tmb) && unlink($tmb); |
||
| 5722 | clearstatcache(); |
||
| 5723 | } |
||
| 5724 | } |
||
| 5725 | |||
| 5726 | /** |
||
| 5727 | * Create an gd image according to the specified mime type. |
||
| 5728 | * |
||
| 5729 | * @param string $path image file |
||
| 5730 | * @param string $mime |
||
| 5731 | * @return gd image resource identifier |
||
| 5732 | */ |
||
| 5733 | protected function gdImageCreate($path, $mime) |
||
| 5734 | { |
||
| 5735 | switch ($mime) { |
||
| 5736 | case 'image/jpeg': |
||
| 5737 | return imagecreatefromjpeg($path); |
||
| 5738 | |||
| 5739 | case 'image/png': |
||
| 5740 | return imagecreatefrompng($path); |
||
| 5741 | |||
| 5742 | case 'image/gif': |
||
| 5743 | return imagecreatefromgif($path); |
||
| 5744 | |||
| 5745 | case 'image/x-ms-bmp': |
||
| 5746 | if (! function_exists('imagecreatefrombmp')) { |
||
| 5747 | include_once dirname(__FILE__).'/libs/GdBmp.php'; |
||
| 5748 | } |
||
| 5749 | |||
| 5750 | return imagecreatefrombmp($path); |
||
| 5751 | |||
| 5752 | case 'image/xbm': |
||
| 5753 | return imagecreatefromxbm($path); |
||
| 5754 | |||
| 5755 | case 'image/xpm': |
||
| 5756 | return imagecreatefromxpm($path); |
||
| 5757 | } |
||
| 5758 | |||
| 5759 | return false; |
||
| 5760 | } |
||
| 5761 | |||
| 5762 | /** |
||
| 5763 | * Output gd image to file. |
||
| 5764 | * |
||
| 5765 | * @param resource $image gd image resource |
||
| 5766 | * @param string $filename The path to save the file to. |
||
| 5767 | * @param string $destformat The Image type to use for $filename |
||
| 5768 | * @param string $mime The original image mime type |
||
| 5769 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 5770 | * @return bool |
||
| 5771 | */ |
||
| 5772 | protected function gdImage($image, $filename, $destformat, $mime, $jpgQuality = null) |
||
| 5773 | { |
||
| 5774 | if (! $jpgQuality) { |
||
| 5775 | $jpgQuality = $this->options['jpgQuality']; |
||
| 5776 | } |
||
| 5777 | if ($destformat) { |
||
| 5778 | switch ($destformat) { |
||
| 5779 | case 'jpg': |
||
| 5780 | $mime = 'image/jpeg'; |
||
| 5781 | break; |
||
| 5782 | case 'gif': |
||
| 5783 | $mime = 'image/gif'; |
||
| 5784 | break; |
||
| 5785 | case 'png': |
||
| 5786 | default: |
||
| 5787 | $mime = 'image/png'; |
||
| 5788 | break; |
||
| 5789 | } |
||
| 5790 | } |
||
| 5791 | switch ($mime) { |
||
| 5792 | case 'image/gif': |
||
| 5793 | return imagegif($image, $filename); |
||
| 5794 | case 'image/jpeg': |
||
| 5795 | return imagejpeg($image, $filename, $jpgQuality); |
||
| 5796 | case 'image/wbmp': |
||
| 5797 | return imagewbmp($image, $filename); |
||
| 5798 | case 'image/png': |
||
| 5799 | default: |
||
| 5800 | return imagepng($image, $filename); |
||
| 5801 | } |
||
| 5802 | } |
||
| 5803 | |||
| 5804 | /** |
||
| 5805 | * Output imagick image to file. |
||
| 5806 | * |
||
| 5807 | * @param resource $img imagick image resource |
||
| 5808 | * @param string $filename The path to save the file to. |
||
| 5809 | * @param string $destformat The Image type to use for $filename |
||
| 5810 | * @param int $jpgQuality JEPG quality (1-100) |
||
| 5811 | * @return bool |
||
| 5812 | */ |
||
| 5813 | protected function imagickImage($img, $filename, $destformat, $jpgQuality = null) |
||
| 5814 | { |
||
| 5815 | if (! $jpgQuality) { |
||
| 5816 | $jpgQuality = $this->options['jpgQuality']; |
||
| 5817 | } |
||
| 5818 | |||
| 5819 | try { |
||
| 5820 | if ($destformat) { |
||
| 5821 | if ($destformat === 'gif') { |
||
| 5822 | $img->setImageFormat('gif'); |
||
| 5823 | } elseif ($destformat === 'png') { |
||
| 5824 | $img->setImageFormat('png'); |
||
| 5825 | } elseif ($destformat === 'jpg') { |
||
| 5826 | $img->setImageFormat('jpeg'); |
||
| 5827 | } |
||
| 5828 | } |
||
| 5829 | if (strtoupper($img->getImageFormat()) === 'JPEG') { |
||
| 5830 | $img->setImageCompression(imagick::COMPRESSION_JPEG); |
||
| 5831 | $img->setImageCompressionQuality($jpgQuality); |
||
| 5832 | try { |
||
| 5833 | $orientation = $img->getImageOrientation(); |
||
| 5834 | } catch (ImagickException $e) { |
||
| 5835 | $orientation = 0; |
||
| 5836 | } |
||
| 5837 | $img->stripImage(); |
||
| 5838 | if ($orientation) { |
||
| 5839 | $img->setImageOrientation($orientation); |
||
| 5840 | } |
||
| 5841 | } |
||
| 5842 | $result = $img->writeImage($filename); |
||
| 5843 | } catch (Exception $e) { |
||
| 5844 | $result = false; |
||
| 5845 | } |
||
| 5846 | |||
| 5847 | return $result; |
||
| 5848 | } |
||
| 5849 | |||
| 5850 | /** |
||
| 5851 | * Assign the proper background to a gd image. |
||
| 5852 | * |
||
| 5853 | * @param resource $image gd image resource |
||
| 5854 | * @param string $bgcolor background color in #rrggbb format |
||
| 5855 | */ |
||
| 5856 | protected function gdImageBackground($image, $bgcolor) |
||
| 5857 | { |
||
| 5858 | if ($bgcolor === 'transparent') { |
||
| 5859 | imagealphablending($image, false); |
||
| 5860 | imagesavealpha($image, true); |
||
| 5861 | View Code Duplication | } else { |
|
| 5862 | list($r, $g, $b) = sscanf($bgcolor, '#%02x%02x%02x'); |
||
| 5863 | $bgcolor1 = imagecolorallocate($image, $r, $g, $b); |
||
| 5864 | imagefill($image, 0, 0, $bgcolor1); |
||
| 5865 | } |
||
| 5866 | } |
||
| 5867 | |||
| 5868 | /** |
||
| 5869 | * Prepare variables for exec convert of ImageMagick. |
||
| 5870 | * |
||
| 5871 | * @param string $path |
||
| 5872 | * @param string $destformat |
||
| 5873 | * @param int $jpgQuality |
||
| 5874 | * @param array $imageSize |
||
| 5875 | * @return array |
||
| 5876 | */ |
||
| 5877 | protected function imageMagickConvertPrepare($path, $destformat, $jpgQuality, $imageSize = null) |
||
| 5878 | { |
||
| 5879 | if (is_null($imageSize)) { |
||
| 5880 | $imageSize = getimagesize($path); |
||
| 5881 | } |
||
| 5882 | if (! $imageSize) { |
||
| 5883 | return []; |
||
| 5884 | } |
||
| 5885 | $srcType = $this->getExtentionByMime($imageSize['mime'], ':'); |
||
| 5886 | $ani = false; |
||
| 5887 | $cmd = 'identify '.escapeshellarg($srcType.$path); |
||
| 5888 | if ($this->procExec($cmd, $o) === 0) { |
||
| 5889 | $ani = preg_split('/(?:\r\n|\n|\r)/', trim($o)); |
||
| 5890 | if (count($ani) < 2) { |
||
| 5891 | $ani = false; |
||
| 5892 | } |
||
| 5893 | } |
||
| 5894 | $coalesce = $index = ''; |
||
| 5895 | $deconstruct = ' +repage'; |
||
| 5896 | if ($ani) { |
||
| 5897 | if (is_null($destformat)) { |
||
| 5898 | $coalesce = ' -coalesce -repage 0x0'; |
||
| 5899 | $deconstruct = ' +repage -deconstruct -layers optimize'; |
||
| 5900 | } else { |
||
| 5901 | $index = '[0]'; |
||
| 5902 | if ($srcType === 'ico:') { |
||
| 5903 | foreach ($ani as $_i => $_info) { |
||
| 5904 | if (preg_match('/ (\d+)x(\d+) /', $_info, $m)) { |
||
| 5905 | if ($m[1] == $imageSize[0] && $m[2] == $imageSize[1]) { |
||
| 5906 | $index = '['.$_i.']'; |
||
| 5907 | break; |
||
| 5908 | } |
||
| 5909 | } |
||
| 5910 | } |
||
| 5911 | } |
||
| 5912 | } |
||
| 5913 | } |
||
| 5914 | if ($imageSize[2] === IMAGETYPE_JPEG || $imageSize[2] === IMAGETYPE_JPEG2000) { |
||
| 5915 | $jpgQuality = ' -quality '.$jpgQuality; |
||
| 5916 | } else { |
||
| 5917 | $jpgQuality = ''; |
||
| 5918 | } |
||
| 5919 | $quotedPath = escapeshellarg($srcType.$path.$index); |
||
| 5920 | $quotedDstPath = escapeshellarg(($destformat ? ($destformat.':') : $srcType).$path); |
||
| 5921 | |||
| 5922 | return compact('ani', 'index', 'coalesce', 'deconstruct', 'jpgQuality', 'quotedPath', 'quotedDstPath'); |
||
| 5923 | } |
||
| 5924 | |||
| 5925 | /*********************** misc *************************/ |
||
| 5926 | |||
| 5927 | /** |
||
| 5928 | * Return smart formatted date. |
||
| 5929 | * |
||
| 5930 | * @param int $ts file timestamp |
||
| 5931 | * @return string |
||
| 5932 | * @author Dmitry (dio) Levashov |
||
| 5933 | **/ |
||
| 5934 | // protected function formatDate($ts) { |
||
| 5935 | // if ($ts > $this->today) { |
||
| 5936 | // return 'Today '.date($this->options['timeFormat'], $ts); |
||
| 5937 | // } |
||
| 5938 | // |
||
| 5939 | // if ($ts > $this->yesterday) { |
||
| 5940 | // return 'Yesterday '.date($this->options['timeFormat'], $ts); |
||
| 5941 | // } |
||
| 5942 | // |
||
| 5943 | // return date($this->options['dateFormat'], $ts); |
||
| 5944 | // } |
||
| 5945 | |||
| 5946 | /** |
||
| 5947 | * Find position of first occurrence of string in a string with multibyte support. |
||
| 5948 | * |
||
| 5949 | * @param string $haystack The string being checked. |
||
| 5950 | * @param string $needle The string to find in haystack. |
||
| 5951 | * @param int $offset The search offset. If it is not specified, 0 is used. |
||
| 5952 | * @return int|bool |
||
| 5953 | * @author Alexey Sukhotin |
||
| 5954 | **/ |
||
| 5955 | protected function stripos($haystack, $needle, $offset = 0) |
||
| 5956 | { |
||
| 5957 | if (function_exists('mb_stripos')) { |
||
| 5958 | return mb_stripos($haystack, $needle, $offset, 'UTF-8'); |
||
| 5959 | } elseif (function_exists('mb_strtolower') && function_exists('mb_strpos')) { |
||
| 5960 | return mb_strpos(mb_strtolower($haystack, 'UTF-8'), mb_strtolower($needle, 'UTF-8'), $offset); |
||
| 5961 | } |
||
| 5962 | |||
| 5963 | return stripos($haystack, $needle, $offset); |
||
| 5964 | } |
||
| 5965 | |||
| 5966 | /** |
||
| 5967 | * Get server side available archivers. |
||
| 5968 | * |
||
| 5969 | * @param bool $use_cache |
||
| 5970 | * @return array |
||
| 5971 | */ |
||
| 5972 | protected function getArchivers($use_cache = true) |
||
| 5973 | { |
||
| 5974 | $sessionKey = 'ARCHIVERS_CACHE'; |
||
| 5975 | if ($use_cache && isset($this->sessionCache[$sessionKey]) && is_array($this->sessionCache[$sessionKey])) { |
||
| 5976 | return $this->sessionCache[$sessionKey]; |
||
| 5977 | } |
||
| 5978 | |||
| 5979 | $arcs = [ |
||
| 5980 | 'create' => [], |
||
| 5981 | 'extract' => [], |
||
| 5982 | ]; |
||
| 5983 | |||
| 5984 | if ($this->procExec('') === 0) { |
||
| 5985 | $this->procExec('tar --version', $o, $ctar); |
||
| 5986 | |||
| 5987 | if ($ctar == 0) { |
||
| 5988 | $arcs['create']['application/x-tar'] = ['cmd' => 'tar', 'argc' => '-cf', 'ext' => 'tar']; |
||
| 5989 | $arcs['extract']['application/x-tar'] = ['cmd' => 'tar', 'argc' => '-xf', 'ext' => 'tar', 'toSpec' => '-C ']; |
||
| 5990 | unset($o); |
||
| 5991 | $this->procExec('gzip --version', $o, $c); |
||
| 5992 | View Code Duplication | if ($c == 0) { |
|
| 5993 | $arcs['create']['application/x-gzip'] = ['cmd' => 'tar', 'argc' => '-czf', 'ext' => 'tgz']; |
||
| 5994 | $arcs['extract']['application/x-gzip'] = ['cmd' => 'tar', 'argc' => '-xzf', 'ext' => 'tgz', 'toSpec' => '-C ']; |
||
| 5995 | } |
||
| 5996 | unset($o); |
||
| 5997 | $this->procExec('bzip2 --version', $o, $c); |
||
| 5998 | View Code Duplication | if ($c == 0) { |
|
| 5999 | $arcs['create']['application/x-bzip2'] = ['cmd' => 'tar', 'argc' => '-cjf', 'ext' => 'tbz']; |
||
| 6000 | $arcs['extract']['application/x-bzip2'] = ['cmd' => 'tar', 'argc' => '-xjf', 'ext' => 'tbz', 'toSpec' => '-C ']; |
||
| 6001 | } |
||
| 6002 | unset($o); |
||
| 6003 | $this->procExec('xz --version', $o, $c); |
||
| 6004 | View Code Duplication | if ($c == 0) { |
|
| 6005 | $arcs['create']['application/x-xz'] = ['cmd' => 'tar', 'argc' => '-cJf', 'ext' => 'xz']; |
||
| 6006 | $arcs['extract']['application/x-xz'] = ['cmd' => 'tar', 'argc' => '-xJf', 'ext' => 'xz', 'toSpec' => '-C ']; |
||
| 6007 | } |
||
| 6008 | } |
||
| 6009 | unset($o); |
||
| 6010 | $this->procExec('zip -v', $o, $c); |
||
| 6011 | View Code Duplication | if ($c == 0) { |
|
| 6012 | $arcs['create']['application/zip'] = ['cmd' => 'zip', 'argc' => '-r9', 'ext' => 'zip']; |
||
| 6013 | } |
||
| 6014 | unset($o); |
||
| 6015 | $this->procExec('unzip --help', $o, $c); |
||
| 6016 | View Code Duplication | if ($c == 0) { |
|
| 6017 | $arcs['extract']['application/zip'] = ['cmd' => 'unzip', 'argc' => '', 'ext' => 'zip', 'toSpec' => '-d ']; |
||
| 6018 | } |
||
| 6019 | unset($o); |
||
| 6020 | $this->procExec('rar --version', $o, $c); |
||
| 6021 | View Code Duplication | if ($c == 0 || $c == 7) { |
|
| 6022 | $arcs['create']['application/x-rar'] = ['cmd' => 'rar', 'argc' => 'a -inul', 'ext' => 'rar']; |
||
| 6023 | } |
||
| 6024 | unset($o); |
||
| 6025 | $this->procExec('unrar', $o, $c); |
||
| 6026 | View Code Duplication | if ($c == 0 || $c == 7) { |
|
| 6027 | $arcs['extract']['application/x-rar'] = ['cmd' => 'unrar', 'argc' => 'x -y', 'ext' => 'rar', 'toSpec' => '']; |
||
| 6028 | } |
||
| 6029 | unset($o); |
||
| 6030 | $this->procExec('7za --help', $o, $c); |
||
| 6031 | if ($c == 0) { |
||
| 6032 | $arcs['create']['application/x-7z-compressed'] = ['cmd' => '7za', 'argc' => 'a', 'ext' => '7z']; |
||
| 6033 | $arcs['extract']['application/x-7z-compressed'] = ['cmd' => '7za', 'argc' => 'x -y', 'ext' => '7z', 'toSpec' => '-o']; |
||
| 6034 | |||
| 6035 | if (empty($arcs['create']['application/zip'])) { |
||
| 6036 | $arcs['create']['application/zip'] = ['cmd' => '7za', 'argc' => 'a -tzip', 'ext' => 'zip']; |
||
| 6037 | } |
||
| 6038 | View Code Duplication | if (empty($arcs['extract']['application/zip'])) { |
|
| 6039 | $arcs['extract']['application/zip'] = ['cmd' => '7za', 'argc' => 'x -tzip -y', 'ext' => 'zip', 'toSpec' => '-o']; |
||
| 6040 | } |
||
| 6041 | if (empty($arcs['create']['application/x-tar'])) { |
||
| 6042 | $arcs['create']['application/x-tar'] = ['cmd' => '7za', 'argc' => 'a -ttar', 'ext' => 'tar']; |
||
| 6043 | } |
||
| 6044 | View Code Duplication | if (empty($arcs['extract']['application/x-tar'])) { |
|
| 6045 | $arcs['extract']['application/x-tar'] = ['cmd' => '7za', 'argc' => 'x -ttar -y', 'ext' => 'tar', 'toSpec' => '-o']; |
||
| 6046 | } |
||
| 6047 | } elseif (substr(PHP_OS, 0, 3) === 'WIN') { |
||
| 6048 | // check `7z` for Windows server. |
||
| 6049 | unset($o); |
||
| 6050 | $this->procExec('7z', $o, $c); |
||
| 6051 | if ($c == 0) { |
||
| 6052 | $arcs['create']['application/x-7z-compressed'] = ['cmd' => '7z', 'argc' => 'a', 'ext' => '7z']; |
||
| 6053 | $arcs['extract']['application/x-7z-compressed'] = ['cmd' => '7z', 'argc' => 'x -y', 'ext' => '7z', 'toSpec' => '-o']; |
||
| 6054 | |||
| 6055 | if (empty($arcs['create']['application/zip'])) { |
||
| 6056 | $arcs['create']['application/zip'] = ['cmd' => '7z', 'argc' => 'a -tzip', 'ext' => 'zip']; |
||
| 6057 | } |
||
| 6058 | View Code Duplication | if (empty($arcs['extract']['application/zip'])) { |
|
| 6059 | $arcs['extract']['application/zip'] = ['cmd' => '7z', 'argc' => 'x -tzip -y', 'ext' => 'zip', 'toSpec' => '-o']; |
||
| 6060 | } |
||
| 6061 | if (empty($arcs['create']['application/x-tar'])) { |
||
| 6062 | $arcs['create']['application/x-tar'] = ['cmd' => '7z', 'argc' => 'a -ttar', 'ext' => 'tar']; |
||
| 6063 | } |
||
| 6064 | View Code Duplication | if (empty($arcs['extract']['application/x-tar'])) { |
|
| 6065 | $arcs['extract']['application/x-tar'] = ['cmd' => '7z', 'argc' => 'x -ttar -y', 'ext' => 'tar', 'toSpec' => '-o']; |
||
| 6066 | } |
||
| 6067 | View Code Duplication | if (empty($arcs['extract']['application/x-rar'])) { |
|
| 6068 | $arcs['extract']['application/x-rar'] = ['cmd' => '7z', 'argc' => 'x -trar -y', 'ext' => 'rar', 'toSpec' => '-o']; |
||
| 6069 | } |
||
| 6070 | } |
||
| 6071 | } |
||
| 6072 | } |
||
| 6073 | |||
| 6074 | // Use PHP ZipArchive Class |
||
| 6075 | if (class_exists('ZipArchive', false)) { |
||
| 6076 | if (empty($arcs['create']['application/zip'])) { |
||
| 6077 | $arcs['create']['application/zip'] = ['cmd' => 'phpfunction', 'argc' => ['self', 'zipArchiveZip'], 'ext' => 'zip']; |
||
| 6078 | } |
||
| 6079 | if (empty($arcs['extract']['application/zip'])) { |
||
| 6080 | $arcs['extract']['application/zip'] = ['cmd' => 'phpfunction', 'argc' => ['self', 'zipArchiveUnzip'], 'ext' => 'zip']; |
||
| 6081 | } |
||
| 6082 | } |
||
| 6083 | |||
| 6084 | $this->sessionCache[$sessionKey] = $arcs; |
||
| 6085 | |||
| 6086 | return $arcs; |
||
| 6087 | } |
||
| 6088 | |||
| 6089 | /** |
||
| 6090 | * Resolve relative / (Unix-like)absolute path. |
||
| 6091 | * |
||
| 6092 | * @param string $path target path |
||
| 6093 | * @param string $base base path |
||
| 6094 | * @return string |
||
| 6095 | */ |
||
| 6096 | protected function getFullPath($path, $base) |
||
| 6097 | { |
||
| 6098 | $separator = $this->separator; |
||
| 6099 | $systemroot = $this->systemRoot; |
||
| 6100 | |||
| 6101 | if ($base[0] === $separator && strpos($base, 0, strlen($systemroot)) !== $systemroot) { |
||
| 6102 | $base = $systemroot.substr($base, 1); |
||
| 6103 | } |
||
| 6104 | |||
| 6105 | // 'Here' |
||
| 6106 | if ($path === '' || $path === '.'.$separator) { |
||
| 6107 | return $base; |
||
| 6108 | } |
||
| 6109 | |||
| 6110 | $sepquoted = preg_quote($separator, '#'); |
||
| 6111 | |||
| 6112 | if (substr($path, 0, 3) === '..'.$separator) { |
||
| 6113 | $path = $base.$separator.$path; |
||
| 6114 | } |
||
| 6115 | // normalize `/../` |
||
| 6116 | $normreg = '#('.$sepquoted.')[^'.$sepquoted.']+'.$sepquoted.'\.\.'.$sepquoted.'#'; // '#(/)[^\/]+/\.\./#' |
||
| 6117 | while (preg_match($normreg, $path)) { |
||
| 6118 | $path = preg_replace($normreg, '$1', $path, 1); |
||
| 6119 | } |
||
| 6120 | |||
| 6121 | // Absolute path |
||
| 6122 | if ($path[0] === $separator || strpos($path, $systemroot) === 0) { |
||
| 6123 | return $path; |
||
| 6124 | } |
||
| 6125 | |||
| 6126 | $preg_separator = '#'.$sepquoted.'#'; |
||
| 6127 | |||
| 6128 | // Relative path from 'Here' |
||
| 6129 | if (substr($path, 0, 2) === '.'.$separator || $path[0] !== '.') { |
||
| 6130 | $arrn = preg_split($preg_separator, $path, -1, PREG_SPLIT_NO_EMPTY); |
||
| 6131 | if ($arrn[0] !== '.') { |
||
| 6132 | array_unshift($arrn, '.'); |
||
| 6133 | } |
||
| 6134 | $arrn[0] = $base; |
||
| 6135 | |||
| 6136 | return implode($separator, $arrn); |
||
| 6137 | } |
||
| 6138 | |||
| 6139 | return $path; |
||
| 6140 | } |
||
| 6141 | |||
| 6142 | /** |
||
| 6143 | * Create archive and return its path. |
||
| 6144 | * |
||
| 6145 | * @param string $dir target dir |
||
| 6146 | * @param array $files files names list |
||
| 6147 | * @param string $name archive name |
||
| 6148 | * @param array $arc archiver options |
||
| 6149 | * @return string|bool |
||
| 6150 | * @author Dmitry (dio) Levashov, |
||
| 6151 | * @author Alexey Sukhotin |
||
| 6152 | * @author Naoki Sawada |
||
| 6153 | **/ |
||
| 6154 | protected function makeArchive($dir, $files, $name, $arc) |
||
| 6155 | { |
||
| 6156 | if ($arc['cmd'] === 'phpfunction') { |
||
| 6157 | View Code Duplication | if (is_callable($arc['argc'])) { |
|
| 6158 | call_user_func_array($arc['argc'], [$dir, $files, $name]); |
||
| 6159 | } |
||
| 6160 | } else { |
||
| 6161 | $cwd = getcwd(); |
||
| 6162 | if (chdir($dir)) { |
||
| 6163 | foreach ($files as $i => $file) { |
||
| 6164 | $files[$i] = '.'.DIRECTORY_SEPARATOR.$file; |
||
| 6165 | } |
||
| 6166 | $files = array_map('escapeshellarg', $files); |
||
| 6167 | |||
| 6168 | $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($name).' '.implode(' ', $files); |
||
| 6169 | $this->procExec($cmd, $o, $c); |
||
| 6170 | chdir($cwd); |
||
| 6171 | } else { |
||
| 6172 | return false; |
||
| 6173 | } |
||
| 6174 | } |
||
| 6175 | $path = $dir.DIRECTORY_SEPARATOR.$name; |
||
| 6176 | |||
| 6177 | return file_exists($path) ? $path : false; |
||
| 6178 | } |
||
| 6179 | |||
| 6180 | /** |
||
| 6181 | * Unpack archive. |
||
| 6182 | * |
||
| 6183 | * @param string $path archive path |
||
| 6184 | * @param array $arc archiver command and arguments (same as in $this->archivers) |
||
| 6185 | * @param bool|string $mode bool: remove archive ( unlink($path) ) | string: extract to directory |
||
| 6186 | * @return void |
||
| 6187 | * @author Dmitry (dio) Levashov |
||
| 6188 | * @author Alexey Sukhotin |
||
| 6189 | * @author Naoki Sawada |
||
| 6190 | **/ |
||
| 6191 | protected function unpackArchive($path, $arc, $mode = true) |
||
| 6192 | { |
||
| 6193 | if (is_string($mode)) { |
||
| 6194 | $dir = $mode; |
||
| 6195 | $chdir = null; |
||
| 6196 | $remove = false; |
||
| 6197 | } else { |
||
| 6198 | $dir = dirname($path); |
||
| 6199 | $chdir = $dir; |
||
| 6200 | $remove = $mode; |
||
| 6201 | } |
||
| 6202 | $dir = realpath($dir); |
||
| 6203 | $path = realpath($path); |
||
| 6204 | if ($arc['cmd'] === 'phpfunction') { |
||
| 6205 | View Code Duplication | if (is_callable($arc['argc'])) { |
|
| 6206 | call_user_func_array($arc['argc'], [$path, $dir]); |
||
| 6207 | } |
||
| 6208 | } else { |
||
| 6209 | $cwd = getcwd(); |
||
| 6210 | if (! $chdir || chdir($dir)) { |
||
| 6211 | if ($chdir) { |
||
| 6212 | $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg(basename($path)); |
||
| 6213 | } else { |
||
| 6214 | $cmd = $arc['cmd'].' '.$arc['argc'].' '.escapeshellarg($path).' '.$arc['toSpec'].escapeshellarg($dir); |
||
| 6215 | } |
||
| 6216 | $this->procExec($cmd, $o, $c); |
||
| 6217 | $chdir && chdir($cwd); |
||
| 6218 | } |
||
| 6219 | } |
||
| 6220 | $remove && unlink($path); |
||
| 6221 | } |
||
| 6222 | |||
| 6223 | /** |
||
| 6224 | * Check and filter the extracted items. |
||
| 6225 | * |
||
| 6226 | * @param string $path target local path |
||
| 6227 | * @param array $checks types to check default: ['symlink', 'name', 'writable', 'mime'] |
||
| 6228 | * @return array ['symlinks' => [], 'names' => [], 'writables' => [], 'mimes' => [], 'rmNames' => [], 'totalSize' => 0] |
||
| 6229 | * @author Naoki Sawada |
||
| 6230 | */ |
||
| 6231 | protected function checkExtractItems($path, $checks = null) |
||
| 6232 | { |
||
| 6233 | if (is_null($checks) || ! is_array($checks)) { |
||
| 6234 | $checks = ['symlink', 'name', 'writable', 'mime']; |
||
| 6235 | } |
||
| 6236 | $chkSymlink = in_array('symlink', $checks); |
||
| 6237 | $chkName = in_array('name', $checks); |
||
| 6238 | $chkWritable = in_array('writable', $checks); |
||
| 6239 | $chkMime = in_array('mime', $checks); |
||
| 6240 | |||
| 6241 | $res = [ |
||
| 6242 | 'symlinks' => [], |
||
| 6243 | 'names' => [], |
||
| 6244 | 'writables' => [], |
||
| 6245 | 'mimes' => [], |
||
| 6246 | 'rmNames' => [], |
||
| 6247 | 'totalSize' => 0, |
||
| 6248 | ]; |
||
| 6249 | |||
| 6250 | if (is_dir($path)) { |
||
| 6251 | foreach (self::localScandir($path) as $name) { |
||
| 6252 | $p = $path.DIRECTORY_SEPARATOR.$name; |
||
| 6253 | if ($chkSymlink && is_link($p)) { |
||
| 6254 | self::localRmdirRecursive($p); |
||
| 6255 | $res['symlinks'][] = $p; |
||
| 6256 | $res['rmNames'][] = $name; |
||
| 6257 | continue; |
||
| 6258 | } |
||
| 6259 | $isDir = is_dir($p); |
||
| 6260 | if ($chkName && ! $this->nameAccepted($name, $isDir)) { |
||
| 6261 | self::localRmdirRecursive($p); |
||
| 6262 | $res['names'][] = $p; |
||
| 6263 | $res['rmNames'][] = $name; |
||
| 6264 | continue; |
||
| 6265 | } |
||
| 6266 | if ($chkWritable && ! $this->attr($p, 'write', null, $isDir)) { |
||
| 6267 | self::localRmdirRecursive($p); |
||
| 6268 | $res['writables'][] = $p; |
||
| 6269 | $res['rmNames'][] = $name; |
||
| 6270 | continue; |
||
| 6271 | } |
||
| 6272 | View Code Duplication | if ($chkMime && ($mimeByName = self::mimetypeInternalDetect($name)) && $mimeByName !== 'unknown' && ! $this->allowPutMime($mimeByName)) { |
|
| 6273 | self::localRmdirRecursive($p); |
||
| 6274 | $res['mimes'][] = $p; |
||
| 6275 | $res['rmNames'][] = $name; |
||
| 6276 | continue; |
||
| 6277 | } |
||
| 6278 | if ($isDir) { |
||
| 6279 | $cRes = $this->checkExtractItems($p, $checks); |
||
| 6280 | foreach ($cRes as $k => $v) { |
||
| 6281 | if (is_array($v)) { |
||
| 6282 | $res[$k] = array_merge($res[$k], $cRes[$k]); |
||
| 6283 | } else { |
||
| 6284 | $res[$k] += $cRes[$k]; |
||
| 6285 | } |
||
| 6286 | } |
||
| 6287 | } else { |
||
| 6288 | $res['totalSize'] += sprintf('%u', filesize($p)); |
||
| 6289 | } |
||
| 6290 | } |
||
| 6291 | $res['rmNames'] = array_unique($res['rmNames']); |
||
| 6292 | } else { |
||
| 6293 | if ($chkSymlink && is_link($path)) { |
||
| 6294 | unlink($path); |
||
| 6295 | $res['symlinks'][] = $path; |
||
| 6296 | $res['rmNames'][] = basename($path); |
||
| 6297 | } elseif ($chkName && ! $this->nameAccepted($name, false)) { |
||
| 6298 | unlink($path); |
||
| 6299 | $res['names'][] = $path; |
||
| 6300 | $res['rmNames'][] = $name; |
||
| 6301 | } elseif ($chkWritable && ! $this->attr($path, 'write', null, $isDir)) { |
||
| 6302 | unlink($path); |
||
| 6303 | $res['writables'][] = $path; |
||
| 6304 | $res['rmNames'][] = $name; |
||
| 6305 | View Code Duplication | } elseif ($chkMime && ($mimeByName = self::mimetypeInternalDetect($name)) && $mimeByName !== 'unknown' && ! $this->allowPutMime($mimeByName)) { |
|
| 6306 | unlink($path); |
||
| 6307 | $res['mimes'][] = $path; |
||
| 6308 | $res['rmNames'][] = $name; |
||
| 6309 | } else { |
||
| 6310 | $res['totalSize'] += sprintf('%u', filesize($path)); |
||
| 6311 | } |
||
| 6312 | } |
||
| 6313 | |||
| 6314 | return $res; |
||
| 6315 | } |
||
| 6316 | |||
| 6317 | /** |
||
| 6318 | * Return files of target directory that is dotfiles excludes. |
||
| 6319 | * |
||
| 6320 | * @param string $dir target directory path |
||
| 6321 | * @return array |
||
| 6322 | * @throws Exception |
||
| 6323 | * @author Naoki Sawada |
||
| 6324 | */ |
||
| 6325 | protected static function localScandir($dir) |
||
| 6326 | { |
||
| 6327 | // PHP function scandir() is not work well in specific environment. I dont know why. |
||
| 6328 | // ref. https://github.com/Studio-42/elFinder/issues/1248 |
||
| 6329 | $files = []; |
||
| 6330 | if ($dh = opendir($dir)) { |
||
| 6331 | while (false !== ($file = readdir($dh))) { |
||
| 6332 | if ($file !== '.' && $file !== '..') { |
||
| 6333 | $files[] = $file; |
||
| 6334 | } |
||
| 6335 | } |
||
| 6336 | closedir($dh); |
||
| 6337 | } else { |
||
| 6338 | throw new Exception('Can not open local directory.'); |
||
| 6339 | } |
||
| 6340 | |||
| 6341 | return $files; |
||
| 6342 | } |
||
| 6343 | |||
| 6344 | /** |
||
| 6345 | * Remove directory recursive on local file system. |
||
| 6346 | * |
||
| 6347 | * @param string $dir Target dirctory path |
||
| 6348 | * @return bool |
||
| 6349 | * @author Naoki Sawada |
||
| 6350 | */ |
||
| 6351 | protected static function localRmdirRecursive($dir) |
||
| 6352 | { |
||
| 6353 | if (! is_link($dir) && is_dir($dir)) { |
||
| 6354 | chmod($dir, 0777); |
||
| 6355 | if ($handle = opendir($dir)) { |
||
| 6356 | while (false !== ($file = readdir($handle))) { |
||
| 6357 | if ($file === '.' || $file === '..') { |
||
| 6358 | continue; |
||
| 6359 | } |
||
| 6360 | elFinder::extendTimeLimit(30); |
||
| 6361 | $path = $dir.DIRECTORY_SEPARATOR.$file; |
||
| 6362 | if (! is_link($dir) && is_dir($path)) { |
||
| 6363 | self::localRmdirRecursive($path); |
||
| 6364 | } else { |
||
| 6365 | chmod($path, 0666); |
||
| 6366 | unlink($path); |
||
| 6367 | } |
||
| 6368 | } |
||
| 6369 | closedir($handle); |
||
| 6370 | } |
||
| 6371 | |||
| 6372 | return rmdir($dir); |
||
| 6373 | } elseif (is_file($dir) || is_link($dir)) { |
||
| 6374 | chmod($dir, 0666); |
||
| 6375 | |||
| 6376 | return unlink($dir); |
||
| 6377 | } |
||
| 6378 | |||
| 6379 | return false; |
||
| 6380 | } |
||
| 6381 | |||
| 6382 | /** |
||
| 6383 | * Move item recursive on local file system. |
||
| 6384 | * |
||
| 6385 | * @param string $src |
||
| 6386 | * @param string $target |
||
| 6387 | * @param string $overWrite |
||
| 6388 | * @param string $copyJoin |
||
| 6389 | * @return bool |
||
| 6390 | * @author Naoki Sawada |
||
| 6391 | */ |
||
| 6392 | protected static function localMoveRecursive($src, $target, $overWrite = true, $copyJoin = true) |
||
| 6393 | { |
||
| 6394 | $res = false; |
||
| 6395 | if (! file_exists($target)) { |
||
| 6396 | return rename($src, $target); |
||
| 6397 | } |
||
| 6398 | if (! $copyJoin || ! is_dir($target)) { |
||
| 6399 | if ($overWrite) { |
||
| 6400 | if (is_dir($target)) { |
||
| 6401 | $del = self::localRmdirRecursive($target); |
||
| 6402 | } else { |
||
| 6403 | $del = unlink($target); |
||
| 6404 | } |
||
| 6405 | if ($del) { |
||
| 6406 | return rename($src, $target); |
||
| 6407 | } |
||
| 6408 | } |
||
| 6409 | } else { |
||
| 6410 | foreach (self::localScandir($src) as $item) { |
||
| 6411 | $res |= self::localMoveRecursive($src.DIRECTORY_SEPARATOR.$item, $target.DIRECTORY_SEPARATOR.$item, $overWrite, $copyJoin); |
||
| 6412 | } |
||
| 6413 | } |
||
| 6414 | |||
| 6415 | return (bool) $res; |
||
| 6416 | } |
||
| 6417 | |||
| 6418 | /** |
||
| 6419 | * Create Zip archive using PHP class ZipArchive. |
||
| 6420 | * |
||
| 6421 | * @param string $dir target dir |
||
| 6422 | * @param array $files files names list |
||
| 6423 | * @param string|object $zipPath Zip archive name |
||
| 6424 | * @return bool |
||
| 6425 | * @author Naoki Sawada |
||
| 6426 | */ |
||
| 6427 | protected static function zipArchiveZip($dir, $files, $zipPath) |
||
| 6428 | { |
||
| 6429 | try { |
||
| 6430 | if ($start = is_string($zipPath)) { |
||
| 6431 | $zip = new ZipArchive(); |
||
| 6432 | if ($zip->open($dir.DIRECTORY_SEPARATOR.$zipPath, ZipArchive::CREATE) !== true) { |
||
| 6433 | $zip = false; |
||
| 6434 | } |
||
| 6435 | } else { |
||
| 6436 | $zip = $zipPath; |
||
| 6437 | } |
||
| 6438 | if ($zip) { |
||
| 6439 | foreach ($files as $file) { |
||
| 6440 | $path = $dir.DIRECTORY_SEPARATOR.$file; |
||
| 6441 | if (is_dir($path)) { |
||
| 6442 | $zip->addEmptyDir($file); |
||
| 6443 | $_files = []; |
||
| 6444 | if ($handle = opendir($path)) { |
||
| 6445 | while (false !== ($entry = readdir($handle))) { |
||
| 6446 | if ($entry !== '.' && $entry !== '..') { |
||
| 6447 | $_files[] = $file.DIRECTORY_SEPARATOR.$entry; |
||
| 6448 | } |
||
| 6449 | } |
||
| 6450 | closedir($handle); |
||
| 6451 | } |
||
| 6452 | if ($_files) { |
||
| 6453 | self::zipArchiveZip($dir, $_files, $zip); |
||
| 6454 | } |
||
| 6455 | } else { |
||
| 6456 | $zip->addFile($path, $file); |
||
| 6457 | } |
||
| 6458 | } |
||
| 6459 | $start && $zip->close(); |
||
| 6460 | } |
||
| 6461 | } catch (Exception $e) { |
||
| 6462 | return false; |
||
| 6463 | } |
||
| 6464 | |||
| 6465 | return true; |
||
| 6466 | } |
||
| 6467 | |||
| 6468 | /** |
||
| 6469 | * Unpack Zip archive using PHP class ZipArchive. |
||
| 6470 | * |
||
| 6471 | * @param string $zipPath Zip archive name |
||
| 6472 | * @param string $toDir Extract to path |
||
| 6473 | * @return bool |
||
| 6474 | * @author Naoki Sawada |
||
| 6475 | */ |
||
| 6476 | protected static function zipArchiveUnzip($zipPath, $toDir) |
||
| 6477 | { |
||
| 6478 | try { |
||
| 6479 | $zip = new ZipArchive(); |
||
| 6480 | if ($zip->open($zipPath) === true) { |
||
| 6481 | $zip->extractTo($toDir); |
||
| 6482 | $zip->close(); |
||
| 6483 | } |
||
| 6484 | } catch (Exception $e) { |
||
| 6485 | return false; |
||
| 6486 | } |
||
| 6487 | |||
| 6488 | return true; |
||
| 6489 | } |
||
| 6490 | |||
| 6491 | /** |
||
| 6492 | * Recursive symlinks search. |
||
| 6493 | * |
||
| 6494 | * @param string $path file/dir path |
||
| 6495 | * @return bool |
||
| 6496 | * @author Dmitry (dio) Levashov |
||
| 6497 | **/ |
||
| 6498 | protected static function localFindSymlinks($path) |
||
| 6499 | { |
||
| 6500 | if (is_link($path)) { |
||
| 6501 | return true; |
||
| 6502 | } |
||
| 6503 | |||
| 6504 | if (is_dir($path)) { |
||
| 6505 | foreach (self::localScandir($path) as $name) { |
||
| 6506 | $p = $path.DIRECTORY_SEPARATOR.$name; |
||
| 6507 | if (is_link($p)) { |
||
| 6508 | return true; |
||
| 6509 | } |
||
| 6510 | if (is_dir($p) && $this->_findSymlinks($p)) { |
||
| 6511 | return true; |
||
| 6512 | } |
||
| 6513 | } |
||
| 6514 | } |
||
| 6515 | |||
| 6516 | return false; |
||
| 6517 | } |
||
| 6518 | |||
| 6519 | /**==================================* abstract methods *====================================**/ |
||
| 6520 | |||
| 6521 | /*********************** paths/urls *************************/ |
||
| 6522 | |||
| 6523 | /** |
||
| 6524 | * Return parent directory path. |
||
| 6525 | * |
||
| 6526 | * @param string $path file path |
||
| 6527 | * @return string |
||
| 6528 | * @author Dmitry (dio) Levashov |
||
| 6529 | **/ |
||
| 6530 | abstract protected function _dirname($path); |
||
| 6531 | |||
| 6532 | /** |
||
| 6533 | * Return file name. |
||
| 6534 | * |
||
| 6535 | * @param string $path file path |
||
| 6536 | * @return string |
||
| 6537 | * @author Dmitry (dio) Levashov |
||
| 6538 | **/ |
||
| 6539 | abstract protected function _basename($path); |
||
| 6540 | |||
| 6541 | /** |
||
| 6542 | * Join dir name and file name and return full path. |
||
| 6543 | * Some drivers (db) use int as path - so we give to concat path to driver itself. |
||
| 6544 | * |
||
| 6545 | * @param string $dir dir path |
||
| 6546 | * @param string $name file name |
||
| 6547 | * @return string |
||
| 6548 | * @author Dmitry (dio) Levashov |
||
| 6549 | **/ |
||
| 6550 | abstract protected function _joinPath($dir, $name); |
||
| 6551 | |||
| 6552 | /** |
||
| 6553 | * Return normalized path. |
||
| 6554 | * |
||
| 6555 | * @param string $path file path |
||
| 6556 | * @return string |
||
| 6557 | * @author Dmitry (dio) Levashov |
||
| 6558 | **/ |
||
| 6559 | abstract protected function _normpath($path); |
||
| 6560 | |||
| 6561 | /** |
||
| 6562 | * Return file path related to root dir. |
||
| 6563 | * |
||
| 6564 | * @param string $path file path |
||
| 6565 | * @return string |
||
| 6566 | * @author Dmitry (dio) Levashov |
||
| 6567 | **/ |
||
| 6568 | abstract protected function _relpath($path); |
||
| 6569 | |||
| 6570 | /** |
||
| 6571 | * Convert path related to root dir into real path. |
||
| 6572 | * |
||
| 6573 | * @param string $path rel file path |
||
| 6574 | * @return string |
||
| 6575 | * @author Dmitry (dio) Levashov |
||
| 6576 | **/ |
||
| 6577 | abstract protected function _abspath($path); |
||
| 6578 | |||
| 6579 | /** |
||
| 6580 | * Return fake path started from root dir. |
||
| 6581 | * Required to show path on client side. |
||
| 6582 | * |
||
| 6583 | * @param string $path file path |
||
| 6584 | * @return string |
||
| 6585 | * @author Dmitry (dio) Levashov |
||
| 6586 | **/ |
||
| 6587 | abstract protected function _path($path); |
||
| 6588 | |||
| 6589 | /** |
||
| 6590 | * Return true if $path is children of $parent. |
||
| 6591 | * |
||
| 6592 | * @param string $path path to check |
||
| 6593 | * @param string $parent parent path |
||
| 6594 | * @return bool |
||
| 6595 | * @author Dmitry (dio) Levashov |
||
| 6596 | **/ |
||
| 6597 | abstract protected function _inpath($path, $parent); |
||
| 6598 | |||
| 6599 | /** |
||
| 6600 | * Return stat for given path. |
||
| 6601 | * Stat contains following fields: |
||
| 6602 | * - (int) size file size in b. required |
||
| 6603 | * - (int) ts file modification time in unix time. required |
||
| 6604 | * - (string) mime mimetype. required for folders, others - optionally |
||
| 6605 | * - (bool) read read permissions. required |
||
| 6606 | * - (bool) write write permissions. required |
||
| 6607 | * - (bool) locked is object locked. optionally |
||
| 6608 | * - (bool) hidden is object hidden. optionally |
||
| 6609 | * - (string) alias for symlinks - link target path relative to root path. optionally |
||
| 6610 | * - (string) target for symlinks - link target path. optionally. |
||
| 6611 | * |
||
| 6612 | * If file does not exists - returns empty array or false. |
||
| 6613 | * |
||
| 6614 | * @param string $path file path |
||
| 6615 | * @return array|false |
||
| 6616 | * @author Dmitry (dio) Levashov |
||
| 6617 | **/ |
||
| 6618 | abstract protected function _stat($path); |
||
| 6619 | |||
| 6620 | /***************** file stat ********************/ |
||
| 6621 | |||
| 6622 | /** |
||
| 6623 | * Return true if path is dir and has at least one childs directory. |
||
| 6624 | * |
||
| 6625 | * @param string $path dir path |
||
| 6626 | * @return bool |
||
| 6627 | * @author Dmitry (dio) Levashov |
||
| 6628 | **/ |
||
| 6629 | abstract protected function _subdirs($path); |
||
| 6630 | |||
| 6631 | /** |
||
| 6632 | * Return object width and height |
||
| 6633 | * Ususaly used for images, but can be realize for video etc... |
||
| 6634 | * |
||
| 6635 | * @param string $path file path |
||
| 6636 | * @param string $mime file mime type |
||
| 6637 | * @return string |
||
| 6638 | * @author Dmitry (dio) Levashov |
||
| 6639 | **/ |
||
| 6640 | abstract protected function _dimensions($path, $mime); |
||
| 6641 | |||
| 6642 | /******************** file/dir content *********************/ |
||
| 6643 | |||
| 6644 | /** |
||
| 6645 | * Return files list in directory. |
||
| 6646 | * |
||
| 6647 | * @param string $path dir path |
||
| 6648 | * @return array |
||
| 6649 | * @author Dmitry (dio) Levashov |
||
| 6650 | **/ |
||
| 6651 | abstract protected function _scandir($path); |
||
| 6652 | |||
| 6653 | /** |
||
| 6654 | * Open file and return file pointer. |
||
| 6655 | * |
||
| 6656 | * @param string $path file path |
||
| 6657 | * @param string $mode open mode |
||
| 6658 | * @return resource|false |
||
| 6659 | * @author Dmitry (dio) Levashov |
||
| 6660 | **/ |
||
| 6661 | abstract protected function _fopen($path, $mode = 'rb'); |
||
| 6662 | |||
| 6663 | /** |
||
| 6664 | * Close opened file. |
||
| 6665 | * |
||
| 6666 | * @param resource $fp file pointer |
||
| 6667 | * @param string $path file path |
||
| 6668 | * @return bool |
||
| 6669 | * @author Dmitry (dio) Levashov |
||
| 6670 | **/ |
||
| 6671 | abstract protected function _fclose($fp, $path = ''); |
||
| 6672 | |||
| 6673 | /******************** file/dir manipulations *************************/ |
||
| 6674 | |||
| 6675 | /** |
||
| 6676 | * Create dir and return created dir path or false on failed. |
||
| 6677 | * |
||
| 6678 | * @param string $path parent dir path |
||
| 6679 | * @param string $name new directory name |
||
| 6680 | * @return string|bool |
||
| 6681 | * @author Dmitry (dio) Levashov |
||
| 6682 | **/ |
||
| 6683 | abstract protected function _mkdir($path, $name); |
||
| 6684 | |||
| 6685 | /** |
||
| 6686 | * Create file and return it's path or false on failed. |
||
| 6687 | * |
||
| 6688 | * @param string $path parent dir path |
||
| 6689 | * @param string $name new file name |
||
| 6690 | * @return string|bool |
||
| 6691 | * @author Dmitry (dio) Levashov |
||
| 6692 | **/ |
||
| 6693 | abstract protected function _mkfile($path, $name); |
||
| 6694 | |||
| 6695 | /** |
||
| 6696 | * Create symlink. |
||
| 6697 | * |
||
| 6698 | * @param string $source file to link to |
||
| 6699 | * @param string $targetDir folder to create link in |
||
| 6700 | * @param string $name symlink name |
||
| 6701 | * @return bool |
||
| 6702 | * @author Dmitry (dio) Levashov |
||
| 6703 | **/ |
||
| 6704 | abstract protected function _symlink($source, $targetDir, $name); |
||
| 6705 | |||
| 6706 | /** |
||
| 6707 | * Copy file into another file (only inside one volume). |
||
| 6708 | * |
||
| 6709 | * @param string $source source file path |
||
| 6710 | * @param $targetDir |
||
| 6711 | * @param string $name file name |
||
| 6712 | * @return bool|string |
||
| 6713 | * @internal param string $target target dir path |
||
| 6714 | * @author Dmitry (dio) Levashov |
||
| 6715 | */ |
||
| 6716 | abstract protected function _copy($source, $targetDir, $name); |
||
| 6717 | |||
| 6718 | /** |
||
| 6719 | * Move file into another parent dir. |
||
| 6720 | * Return new file path or false. |
||
| 6721 | * |
||
| 6722 | * @param string $source source file path |
||
| 6723 | * @param $targetDir |
||
| 6724 | * @param string $name file name |
||
| 6725 | * @return bool|string |
||
| 6726 | * @internal param string $target target dir path |
||
| 6727 | * @author Dmitry (dio) Levashov |
||
| 6728 | */ |
||
| 6729 | abstract protected function _move($source, $targetDir, $name); |
||
| 6730 | |||
| 6731 | /** |
||
| 6732 | * Remove file. |
||
| 6733 | * |
||
| 6734 | * @param string $path file path |
||
| 6735 | * @return bool |
||
| 6736 | * @author Dmitry (dio) Levashov |
||
| 6737 | **/ |
||
| 6738 | abstract protected function _unlink($path); |
||
| 6739 | |||
| 6740 | /** |
||
| 6741 | * Remove dir. |
||
| 6742 | * |
||
| 6743 | * @param string $path dir path |
||
| 6744 | * @return bool |
||
| 6745 | * @author Dmitry (dio) Levashov |
||
| 6746 | **/ |
||
| 6747 | abstract protected function _rmdir($path); |
||
| 6748 | |||
| 6749 | /** |
||
| 6750 | * Create new file and write into it from file pointer. |
||
| 6751 | * Return new file path or false on error. |
||
| 6752 | * |
||
| 6753 | * @param resource $fp file pointer |
||
| 6754 | * @param string $dir target dir path |
||
| 6755 | * @param string $name file name |
||
| 6756 | * @param array $stat file stat (required by some virtual fs) |
||
| 6757 | * @return bool|string |
||
| 6758 | * @author Dmitry (dio) Levashov |
||
| 6759 | **/ |
||
| 6760 | abstract protected function _save($fp, $dir, $name, $stat); |
||
| 6761 | |||
| 6762 | /** |
||
| 6763 | * Get file contents. |
||
| 6764 | * |
||
| 6765 | * @param string $path file path |
||
| 6766 | * @return string|false |
||
| 6767 | * @author Dmitry (dio) Levashov |
||
| 6768 | **/ |
||
| 6769 | abstract protected function _getContents($path); |
||
| 6770 | |||
| 6771 | /** |
||
| 6772 | * Write a string to a file. |
||
| 6773 | * |
||
| 6774 | * @param string $path file path |
||
| 6775 | * @param string $content new file content |
||
| 6776 | * @return bool |
||
| 6777 | * @author Dmitry (dio) Levashov |
||
| 6778 | **/ |
||
| 6779 | abstract protected function _filePutContents($path, $content); |
||
| 6780 | |||
| 6781 | /** |
||
| 6782 | * Extract files from archive. |
||
| 6783 | * |
||
| 6784 | * @param string $path file path |
||
| 6785 | * @param array $arc archiver options |
||
| 6786 | * @return bool |
||
| 6787 | * @author Dmitry (dio) Levashov, |
||
| 6788 | * @author Alexey Sukhotin |
||
| 6789 | **/ |
||
| 6790 | abstract protected function _extract($path, $arc); |
||
| 6791 | |||
| 6792 | /** |
||
| 6793 | * Create archive and return its path. |
||
| 6794 | * |
||
| 6795 | * @param string $dir target dir |
||
| 6796 | * @param array $files files names list |
||
| 6797 | * @param string $name archive name |
||
| 6798 | * @param array $arc archiver options |
||
| 6799 | * @return string|bool |
||
| 6800 | * @author Dmitry (dio) Levashov, |
||
| 6801 | * @author Alexey Sukhotin |
||
| 6802 | **/ |
||
| 6803 | abstract protected function _archive($dir, $files, $name, $arc); |
||
| 6804 | |||
| 6805 | /** |
||
| 6806 | * Detect available archivers. |
||
| 6807 | * |
||
| 6808 | * @return void |
||
| 6809 | * @author Dmitry (dio) Levashov, |
||
| 6810 | * @author Alexey Sukhotin |
||
| 6811 | **/ |
||
| 6812 | abstract protected function _checkArchivers(); |
||
| 6813 | |||
| 6814 | /** |
||
| 6815 | * Change file mode (chmod). |
||
| 6816 | * |
||
| 6817 | * @param string $path file path |
||
| 6818 | * @param string $mode octal string such as '0755' |
||
| 6819 | * @return bool |
||
| 6820 | * @author David Bartle, |
||
| 6821 | **/ |
||
| 6822 | abstract protected function _chmod($path, $mode); |
||
| 6823 | } // END class |
||
| 6824 |
You can fix this by adding a namespace to your class:
When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.