├── LICENSE.md ├── README.md └── chomik.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Rafal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ChomikDownloader 2 | ================ 3 | 4 | Scripts for downloading files from chomikuj.pl 5 | 6 | Usage 7 | ===== 8 | 9 | php chomik.php -u USER -p PASSWORD --url="http://chomikuj.pl/PATH" [optional options] destination 10 | 11 | Required Options: 12 | --user=USER Uses specified user name for authentication. 13 | --password=PASSWORD Uses specified user password for authentication. 14 | --hash=HASH Uses specified user password hash for authentication. 15 | --url=URL Downloads files from the specified URL. 16 | 17 | Optional Options: 18 | --ext=EXTENSIONS Downloads only files of the specified extensions, separated by comma. 19 | -r, --recursive Downloads also all subdirectories. 20 | -s, --structure Creates full folder structure. 21 | -o, --overwrite Overwrites existing files. 22 | -h, --help, /? Shows this help. 23 | 24 | NOTE: 25 | - To log in you may use password OR hash. 26 | - URLs must start with "http://chomikuj.pl/" and must NOT end with a slash. 27 | - By default the script downloads files into the folder from where it was run. 28 | 29 | Examples: 30 | php chomik.php --user=chomikoryba --password=ryba123 --url="http://chomikuj.pl/chomikoryba" -r -s downloads 31 | php chomik.php --user=chomikoryba --hash=233b5774ada09b36458f69a04c9718e9 --url="http://chomikuj.pl/chomikoryba/Myriad+Pro+%28CE%29-TTF" -r --ext="ttf,otf" fonts 32 | -------------------------------------------------------------------------------- /chomik.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 14 | * 'username', // Chomikuj user name. 17 | * 'hash' => 'MD5HASH', // Chomikuj user MD5-hashed password. 18 | * 'recursive' => TRUE, // Recurse into subdirectories. 19 | * 'structure' => TRUE, // Create folder structure. 20 | * 'overwrite' => FALSE, // Overwrite existing files. 21 | * ); 22 | * $chomikuj = new Chomikuj($args); 23 | * 24 | * $chomikuj->downloadFiles( 25 | * 26 | * // Required. List of URLs. 27 | * array( 28 | * 'http://chomikuj.pl/chomikoryba', 29 | * ), 30 | * 31 | * // Optional. Destination folder. May be empty. Defaults to current directory. 32 | * 'downloads', 33 | * 34 | * // Optional. Recurses into subdirectories. Defaults to TRUE. 35 | * TRUE, 36 | * 37 | * // Optional. Creates folder structure. Defaults to TRUE. 38 | * TRUE, 39 | * 40 | * // Optional. Will not overwrite existing files. Defaults to FALSE. 41 | * FALSE, 42 | * 43 | * // Optional. Will not print download progress. 44 | * TRUE, 45 | * 46 | * ); 47 | * ?> 48 | * 49 | */ 50 | class Chomikuj 51 | { 52 | /** 53 | * @var string $userName 54 | * Name of the user. 55 | */ 56 | protected $userName; 57 | 58 | /** 59 | * @var string $userPasswordHash 60 | * Hashed user password. 61 | */ 62 | protected $userPasswordHash; 63 | 64 | /** 65 | * @var string $authToken 66 | * Authentication token retrieved from chomikbox service. 67 | */ 68 | protected $authToken; 69 | 70 | /** 71 | * @var array $log 72 | * Debugging log lines. 73 | */ 74 | protected $log = array(); 75 | 76 | /** 77 | * @var integer $lastLoginStamp 78 | * Last login timestamp. 79 | */ 80 | protected $lastLoginStamp = 0; 81 | 82 | /** 83 | * @var array $fileInfoCache 84 | * Associative array of file ID/file ULR to file information array. 85 | */ 86 | protected $fileInfoCache = array(); 87 | 88 | /** 89 | * @var number $stamp 90 | * Message sequence stamp. We need to increase it for every request. 91 | */ 92 | protected $stamp = 0; 93 | 94 | /** 95 | * @var array $args 96 | * Array of parameters pass to the script. 97 | */ 98 | protected $args = array(); 99 | 100 | /** 101 | * @var array $exts 102 | * Array of extensions allowed to download. 103 | */ 104 | protected $exts = array(); 105 | 106 | /** 107 | * Constructor 108 | * 109 | * @param array $args 110 | * Array of parameters pass to the script. 111 | * 112 | */ 113 | public function __construct ($args) { 114 | $this->args = $args; 115 | $this->userName = $args['user']; 116 | $userPassword = !empty($args['hash']) ? $args['hash'] : $args['password']; // Chomikuj user password or MD5-hashed password. 117 | $passwordHashed = !empty($args['hash']); // Boolean indicating whether specified password is a MD5 version of password(used to prevent showin password in plain text). 118 | $this->userPasswordHash = $passwordHashed ? $userPassword : strtolower(md5($userPassword)); 119 | $this->exts = isset($args['ext']) ? (explode(',', $args['ext'])) : array(); 120 | 121 | } 122 | 123 | /** 124 | * Logins or relogins user. Called automatically before download. 125 | * 126 | * @return boolean 127 | * True if login passed. 128 | */ 129 | public function login () { 130 | 131 | if ($this->lastLoginStamp !== 0 && time() < ($this->lastLoginStamp + 300)) 132 | // Already logged in. 133 | return TRUE; 134 | 135 | if (php_sapi_name() === 'cli') 136 | $log = "Logging in to chomikbox service as \"$this->userName\"... "; 137 | 138 | $response = $this->request( 139 | 140 | // URL 141 | 'http://box.chomikuj.pl/services/ChomikBoxService.svc', 142 | 143 | // GET params. 144 | array(), 145 | 146 | // Method 147 | 'POST', 148 | 149 | // Request data 150 | $data = 151 | '' . 152 | '' . 153 | '' . 154 | '' . 155 | '' . $this->userName . '' . 156 | '' . $this->userPasswordHash . '' . 157 | '4' . 158 | '' . 159 | 'chomikbox' . 160 | '2.0.7.9' . 161 | '' . 162 | '' . 163 | '' . 164 | '', 165 | 166 | // Headers. 167 | array( 168 | 'POST /services/ChomikBoxService.svc HTTP/1.1', 169 | 'SOAPAction: http://chomikuj.pl/IChomikBoxService/Auth', 170 | 'Content-Type: text/xml;charset=utf-8', 171 | 'Content-Length: ' . strlen($data), 172 | 'Connection: Keep-Alive', 173 | 'Accept-Language: pl-PL,en,*', 174 | 'User-Agent: Mozilla/5.0', 175 | 'Host: box.chomikuj.pl', 176 | ) 177 | ); 178 | 179 | if (!$response) { 180 | // If response fails, it indicates probably some temporary network issue. 181 | return FALSE; 182 | } 183 | 184 | preg_match('/\(.*?)\<\/a:token\>/', $response, $matches); 185 | 186 | $this->authToken = @$matches[1]; 187 | $this->lastLoginStamp = time (); 188 | 189 | if (php_sapi_name() === 'cli') { 190 | preg_match('/(.*?)<\/a:status>/sm', $response, $matches); 191 | $status = strtoupper($matches[1]); 192 | 193 | $log .= $status . ".\n"; 194 | 195 | if (php_sapi_name() === 'cli') { 196 | if ($status === 'OK') 197 | echo $log; 198 | else 199 | fwrite(STDERR, $log); 200 | } 201 | } 202 | 203 | return !empty($this->authToken); 204 | } 205 | 206 | /** 207 | * Retrieves file information about given URLs. 208 | * 209 | * @param string $urls 210 | * Urls to the files. 211 | * 212 | * @return array 213 | * List of file information. 214 | */ 215 | public function downloadFilesInformation ($urls, $recursive = TRUE) { 216 | 217 | if (!$this->login()) 218 | // Cannot login, nothing to do. 219 | return FALSE; 220 | 221 | if (php_sapi_name() === 'cli') { 222 | echo " Downloading files information for specified URLs:\n"; 223 | 224 | foreach ($urls as $url) { 225 | echo " - $url\n"; 226 | } 227 | } 228 | 229 | $filesInfo = array(); 230 | 231 | foreach ($urls as $index => &$url) { 232 | if (count($urls) > 1 && pathinfo($url, PATHINFO_EXTENSION) == '') { 233 | 234 | if (php_sapi_name() === 'cli') { 235 | echo " It's a folder, merging its content\n"; 236 | } 237 | 238 | // Folders are downloaded individually. 239 | $filesInfo = array_merge($filesInfo, $this->downloadFilesInformation(array($url), $recursive)); 240 | $url = NULL; 241 | } 242 | } 243 | 244 | /** 245 | * Requesting information about files. 246 | */ 247 | 248 | if (php_sapi_name() === 'cli') { 249 | echo " Preparing request to get information about files..."; 250 | } 251 | 252 | $entries = ''; 253 | $numEntries = 0; 254 | 255 | foreach ($urls as $url) { 256 | if ($url === NULL) 257 | // Entry skipped. 258 | continue; 259 | 260 | $entries .= 261 | '' . 262 | '/' . substr($url, strlen('http://chomikuj.pl/')) . '' . 263 | ''; 264 | 265 | ++$numEntries; 266 | } 267 | 268 | if (php_sapi_name() === 'cli') { 269 | echo " OK.\n"; 270 | } 271 | 272 | $response = $this->request( 273 | 274 | // URL 275 | 'http://box.chomikuj.pl/services/ChomikBoxService.svc', 276 | 277 | // GET params. 278 | array(), 279 | 280 | // Method 281 | 'POST', 282 | 283 | // Request data 284 | $data = 285 | '' . 286 | '' . 287 | '' . 288 | '' . 289 | '' . $this->authToken . '' . 290 | '' . 291 | '' . ($this->stamp++) . '' . 292 | '0' . 293 | '1' . 294 | '' . 295 | 'download' . 296 | '' . 297 | $entries . 298 | '' . 299 | '' . 300 | '' . 301 | '', 302 | 303 | // Headers. 304 | array( 305 | 'POST /services/ChomikBoxService.svc HTTP/1.1', 306 | 'SOAPAction: http://chomikuj.pl/IChomikBoxService/Download', 307 | 'Content-Type: text/xml;charset=utf-8', 308 | 'Content-Length: ' . strlen($data), 309 | 'Connection: Keep-Alive', 310 | 'Accept-Language: pl-PL,en,*', 311 | 'User-Agent: Mozilla/5.0', 312 | 'Host: box.chomikuj.pl', 313 | ) 314 | ); 315 | 316 | preg_match_all('/(\d+)<\/id>.*?(.*?)<\/name>(\d+)<\/cost><\/AgreementInfo>.*?(.*?)<\/realId>.*?(.*?)<\/name>(.*?)<\/size>.*?<\/FileEntry>/', $response, $matches); 317 | 318 | $numMatches = count ($matches[1]); 319 | 320 | php_sapi_name() === 'cli' ? print " Received $numMatches records with information about files.\n" : NULL; 321 | 322 | for ($i = 0; $i < $numMatches; ++$i) { 323 | $name = $matches[5][$i]; 324 | $size = $matches[6][$i]; 325 | $ext = pathinfo($name, PATHINFO_EXTENSION); 326 | 327 | if (!empty($this->exts) && !in_array($ext, $this->exts)) { 328 | php_sapi_name() === 'cli' ? print "Skipping file ($name), because of extension ($ext).\n" : NULL; 329 | // Skipping file. 330 | continue; 331 | } 332 | 333 | if (!empty($this->args['max-size']) && $size > $this->args['max-size']) { 334 | // Skipping file. 335 | php_sapi_name() === 'cli' ? print "Skipping file ($name), because of size limit ($size).\n" : NULL; 336 | continue; 337 | } 338 | 339 | $filesInfo[] = $this->fileInfoCache[$matches[1][$i]] = array( 340 | 'id' => $matches[1][$i], 341 | 'agreement' => $matches[2][$i], 342 | 'cost' => $matches[3][$i], 343 | 'realId' => $matches[4][$i], 344 | 'name' => $name, 345 | 'size' => $size, 346 | ); 347 | } 348 | $totalFiles = count($filesInfo); 349 | php_sapi_name() === 'cli' ? print " Total of $totalFiles files added to download queue.\n" : NULL; 350 | 351 | return $filesInfo; 352 | } 353 | 354 | /** 355 | * Downloads specified file into the destination folder. 356 | * 357 | * @param string $urls 358 | * List of file URLs. 359 | * 360 | * @param boolean $recursive 361 | * True to download also subfolders. 362 | * 363 | * @param boolean $structure 364 | * True to create full folder structure. 365 | * 366 | * @param boolean $overwrite 367 | * True to overwrite existing files. 368 | * 369 | * @param boolean $noprogress 370 | * Do not print progress 371 | * 372 | * @return boolean 373 | * True if sucessfully downloaded all files. 374 | */ 375 | public function downloadFiles ($urls, $destinationFolder = '', $recursive = TRUE, $structure = TRUE, $overwrite = FALSE, $noprogress = FALSE) { 376 | 377 | if (empty($urls)) 378 | // Nothing to do. 379 | { 380 | if (php_sapi_name() === 'cli') { 381 | echo " No URLs given to download.\n"; 382 | } 383 | 384 | return TRUE; 385 | } 386 | 387 | if (!$this->login()) 388 | // Cannot login, nothing to do. 389 | return FALSE; 390 | 391 | // Loading files information. 392 | $filesInfo = $this->downloadFilesInformation($urls, $recursive); 393 | 394 | $iterationSize = 1; 395 | 396 | // Maximum of $iterationSize files per request. 397 | for ($iteration = 0; $iteration < count($filesInfo) / $iterationSize; ++$iteration) { 398 | 399 | if (php_sapi_name() === 'cli') { 400 | echo " Download iteration " . ($iteration + 1) . " / " . (int) count($filesInfo) / $iterationSize . "\n"; 401 | } 402 | 403 | /** 404 | * Requesting information about files. 405 | */ 406 | 407 | $entries = ''; 408 | $numEntries = 0; 409 | 410 | foreach (array_slice($filesInfo, $iteration * $iterationSize, $iterationSize) as $index => $fileInfo) { 411 | $entries .= 412 | '' . 413 | '' . $fileInfo['id'] . '' . 414 | '' . 415 | '' . $fileInfo['agreement'] . ''; 416 | 417 | if ($fileInfo['agreement'] !== 'small') { 418 | $entries .= '' . $fileInfo['cost'] . ''; 419 | } 420 | 421 | $entries .= 422 | '' . 423 | '' . 424 | ''; 425 | 426 | ++$numEntries; 427 | 428 | if ($numEntries > $iterationSize) 429 | break; 430 | } 431 | 432 | $response = $this->request( 433 | 434 | // URL 435 | 'http://box.chomikuj.pl/services/ChomikBoxService.svc', 436 | 437 | // GET params. 438 | array(), 439 | 440 | // Method 441 | 'POST', 442 | 443 | // Request data 444 | $data = 445 | '' . 446 | '' . 447 | '' . 448 | '' . 449 | '' . $this->authToken . '' . 450 | '' . 451 | '' . ($this->stamp++) . '' . 452 | '0' . 453 | '1' . 454 | '' . 455 | 'download' . 456 | '' . 457 | $entries . 458 | '' . 459 | '' . 460 | '' . 461 | '', 462 | 463 | // Headers. 464 | array( 465 | 'POST /services/ChomikBoxService.svc HTTP/1.1', 466 | 'SOAPAction: http://chomikuj.pl/IChomikBoxService/Download', 467 | 'Content-Type: text/xml;charset=utf-8', 468 | 'Content-Length: ' . strlen($data), 469 | 'Connection: Keep-Alive', 470 | 'Accept-Language: pl-PL,en,*', 471 | 'User-Agent: Mozilla/5.0', 472 | 'Host: box.chomikuj.pl', 473 | ) 474 | ); 475 | 476 | preg_match_all('/(.*?)<\/globalId>/', $response, $matches); 477 | 478 | $path = @substr($matches[1][0], 1); 479 | 480 | // Removing non-ascii characters. 481 | $path = preg_replace('/[^(\x20-\x7F)]*/', '', $path); 482 | 483 | preg_match_all('/.*?(.*?)<\/id>.*?(.*?)<\/realId>.*?(.*?)<\/name>(.*?)<\/size>.*?(|(.*?)<\/url>).*?<\/FileEntry>/', $response, $matches); 484 | 485 | 486 | $numMatches = count ($matches[1]); 487 | $files = array(); 488 | 489 | for ($i = 0; $i < $numMatches; ++$i) { 490 | $name = $matches[3][$i]; 491 | $ext = pathinfo($name, PATHINFO_EXTENSION); 492 | $size = $matches[4][$i]; 493 | 494 | if (!empty($this->exts) && !in_array($ext, $this->exts)) { 495 | php_sapi_name() === 'cli' ? print "Skipping file ($name), because of extension ($ext).\n" : NULL; 496 | // Skipping file. 497 | continue; 498 | } 499 | 500 | if (!empty($this->args['max-size']) && $size > $this->args['max-size']) { 501 | // Skipping file. 502 | php_sapi_name() === 'cli' ? print "Skipping file ($name), because of size limit ($size).\n" : NULL; 503 | continue; 504 | } 505 | 506 | $files[] = array( 507 | 'name' => $name, 508 | 'size' => $matches[4][$i], 509 | 'url' => htmlspecialchars_decode($matches[6][$i]), 510 | 'destination' => $destinationFolder . '/' . ($structure ? ($path . '/') : '') . $name, 511 | 'path' => $path, 512 | ); 513 | } 514 | 515 | /** 516 | * Downloading files. 517 | */ 518 | 519 | $curl = curl_init(); 520 | 521 | curl_setopt($curl, CURLOPT_HTTPHEADER, array( 522 | 'Icy-MetaData: 1', 523 | 'Connection: Keep-Alive', 524 | 'Accept-Language: pl-PL,en,*', 525 | 'User-Agent: Mozilla/5.0', 526 | )); 527 | 528 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); 529 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET"); 530 | 531 | 532 | foreach ($files as $file) { 533 | 534 | if (php_sapi_name() === 'cli') { 535 | $url_limited = strlen($file['url']) > 80 ? (substr($file['url'], 0, 20) . '...' . substr($file['url'], -60)) : $file['url']; 536 | echo "Downloading URL \"{$url_limited}\" ({$file['size']} bytes). "; 537 | } 538 | 539 | curl_setopt($curl, CURLOPT_URL, $file['url']); 540 | 541 | if ($structure && !file_exists(dirname($file['destination']))) { 542 | @mkdir(dirname($file['destination']), 0777, true); 543 | } 544 | 545 | if (file_exists($file['destination'])) { 546 | 547 | if ($structure && !$overwrite) { // Creating new file has no sense, so skipping it. 548 | if (php_sapi_name() === 'cli') { 549 | echo "Already downloaded, skipping.\n"; 550 | } 551 | 552 | continue; 553 | } 554 | 555 | if ($overwrite) { 556 | // Removing destination file. 557 | 558 | if (php_sapi_name() === 'cli') 559 | echo "Will Overwrite. "; 560 | 561 | unlink($file['destination']); 562 | } else { 563 | // Generating better name. 564 | $path = $file['destination']; 565 | 566 | do { 567 | $file_name = pathinfo($path, PATHINFO_FILENAME); 568 | preg_match('/\((\d+)\)$/', $file_name, $matches); 569 | 570 | if (@is_numeric($matches[1])) { 571 | $number = $matches[1] + 1; // Incrementing value in "(...)". 572 | $file_name = substr($file_name, 0, strlen($file_name) - strlen($number) - 2); // Removing "(...)" from the end of file name. 573 | } else { 574 | // Starting from "...(2)". 575 | $number = 2; 576 | } 577 | 578 | $ext = pathinfo($path, PATHINFO_EXTENSION); 579 | $path = pathinfo($path, PATHINFO_DIRNAME) . '/' . $file_name . '(' . $number . ')' . ($ext ? ('.' . $ext) : ''); // Constructing file path as "filename(NUMBER).ext". 580 | 581 | // If file path already exist, we will need to generate another path. 582 | } while (file_exists($path)); 583 | $file['destination'] = $path; 584 | } 585 | } 586 | 587 | if (file_exists($file['destination'] . '.part')) { // File is not complete. 588 | 589 | $fileSize = filesize($file['destination'] . '.part'); 590 | if ($fileSize < $file['size']) { 591 | // Destination file already exist and is not fully downloaded, resuming download. 592 | curl_setopt($curl, CURLOPT_RANGE, $fileSize . "-"); 593 | 594 | if (php_sapi_name() === 'cli') 595 | echo "Resuming part $fileSize - {$file['size']}... "; 596 | 597 | $fileHandle = fopen($file['destination'] . '.part', "a"); 598 | } else { 599 | // Destination file is already fully downloaded, renaming and going to the next file. 600 | 601 | if (php_sapi_name() === 'cli') 602 | echo "Already downloaded, skipping.\n"; 603 | 604 | // Removing ".part" from file name. 605 | rename($file['destination'] . '.part', $file['destination']); 606 | 607 | continue; 608 | } 609 | } else { 610 | // Starting download. 611 | curl_setopt($curl, CURLOPT_RANGE, '0-'); 612 | 613 | @$fileHandle = fopen($file['destination'] . '.part', "a"); 614 | 615 | if (php_sapi_name() === 'cli') 616 | echo "Downloading... "; 617 | } 618 | 619 | if (!$fileHandle) { 620 | // Could not open handle 621 | 622 | echo "ERROR.\n"; 623 | fwrite(STDERR, "Could not create file \"{$file['destination']}\" for chomikbox file download, exiting."); 624 | 625 | return FALSE; 626 | } 627 | 628 | curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1); 629 | curl_setopt($curl, CURLOPT_FILE, $fileHandle); 630 | if (!$noprogress) { 631 | curl_setopt($curl, CURLOPT_NOPROGRESS, 0); 632 | } 633 | 634 | $result = curl_exec($curl); 635 | $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 636 | fclose ($fileHandle); 637 | 638 | if ($http_code == 404) { 639 | // We don't need zero-sized file. 640 | unlink($file['destination']); 641 | } else { 642 | // Removing ".part" from file name. 643 | rename($file['destination'] . '.part', $file['destination']); 644 | } 645 | 646 | if (php_sapi_name() === 'cli') 647 | echo "Done.\n"; 648 | } 649 | 650 | curl_close($curl); 651 | } 652 | 653 | if ($recursive) { 654 | 655 | if (php_sapi_name() === 'cli') { 656 | echo " Recursing into given URLs...\n"; 657 | } 658 | 659 | // We will try to download subfolders. 660 | foreach ($urls as $url) { 661 | $response = $this->request($url, array(), 'GET', '', array()); 662 | 663 | // Searching for folder names. 664 | preg_match_all('/
(.*?)<\/div>/sm', $response, $matches); 665 | 666 | if (@$matches[0][0]) { 667 | // We have some folders. 668 | preg_match_all('/href="(.*?)"/sm', $matches[0][0], $matches); 669 | 670 | foreach ($matches[1] as &$match) { 671 | $match = 'http://chomikuj.pl' . $match; 672 | } 673 | 674 | // Downloading subfolders' files. 675 | $this->downloadFiles($matches[1], $destinationFolder, $recursive, $structure, $overwrite); 676 | } 677 | } 678 | } 679 | 680 | return $filesInfo; 681 | } 682 | 683 | /** 684 | * Creates and invokes a GET/POST request. 685 | * 686 | * @param string $url 687 | * URL. 688 | * 689 | * @param array $params 690 | * GET params array. 691 | * 692 | * @param string $method 693 | * Request method, e.g. "GET", "POST", "DELETE". 694 | * 695 | * @param string $data 696 | * Data string. 697 | * 698 | * @param array $headers 699 | * Custom HTTP headers. 700 | */ 701 | public function request ($url, $params, $method = 'POST', $data = "", $headers = array()) { 702 | 703 | $curl = curl_init($url); 704 | 705 | if ($method == 'POST') 706 | curl_setopt($curl, CURLOPT_POST, 1); 707 | else 708 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); 709 | 710 | curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 711 | curl_setopt($curl, CURLOPT_HEADER, false); 712 | curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); 713 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); 714 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 715 | curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 0); 716 | 717 | if (!empty($data)) 718 | curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 719 | 720 | $result = curl_exec($curl); 721 | 722 | curl_close($curl); 723 | 724 | preg_match('/(\d+)<\/stamp>/', $result, $matches); 725 | 726 | if (!empty($matches[1])) { 727 | $this->stamp = $matches[1] + 1000; 728 | } 729 | 730 | return $result; 731 | } 732 | } 733 | 734 | /** 735 | * CLI Support. 736 | */ 737 | 738 | if (php_sapi_name() === 'cli') { 739 | 740 | /** 741 | * parseArgs Command Line Interface (CLI) utility function. 742 | * @author Patrick Fisher 743 | * @see http://github.com/pwfisher/CommandLine.php 744 | */ 745 | function parseArgs($argv) { 746 | $argv = $argv ? $argv : $_SERVER['argv']; array_shift($argv); $o = array(); 747 | foreach ($argv as $a) { 748 | if (substr($a, 0, 2) == '--') { $eq = strpos($a, '='); 749 | if ($eq !== false) { $o[substr($a, 2, $eq - 2)] = substr($a, $eq + 1); } 750 | else { $k = substr($a, 2); if (!isset($o[$k])) { $o[$k] = true; } } } 751 | else if (substr($a, 0, 1) == '-') { 752 | if (substr($a, 2, 1) == '=') { $o[substr($a, 1, 1)] = substr($a, 3); } 753 | else { foreach (str_split(substr($a, 1)) as $k) { if (!isset($o[$k])) { $o[$k] = true; } } } } 754 | else { $o[] = $a; } } 755 | return $o; 756 | } 757 | 758 | $args = parseArgs($argv); 759 | 760 | if (empty($args['recursive'])) 761 | $args['recursive'] = isset($args['r']) ? $args['r'] : FALSE; 762 | 763 | if (empty($args['structure'])) 764 | $args['structure'] = isset($args['s']) ? $args['s'] : FALSE; 765 | 766 | if (empty($args['overwrite'])) 767 | $args['overwrite'] = isset($args['o']) ? $args['o'] : FALSE; 768 | 769 | if (empty($args['noprogress'])) 770 | $args['noprogress'] = isset($args['n']) ? $args['n'] : FALSE; 771 | 772 | if (empty($args['help'])) 773 | $args['help'] = isset($args['h']) ? $args['h'] : FALSE; 774 | 775 | if (empty($args['help'])) 776 | $args['help'] = in_array('/?', $args, TRUE); 777 | 778 | if (empty($args) || !empty($args['help']) || empty($args['user']) || (empty($args['password']) && empty($args['hash'])) || empty($args['url'])) { 779 | echo 780 | "\nChomikuj Downloader\nVersion 0.1\n\nUsage:\n" . 781 | " php " . $argv[0] . " --user=USER --password=PASSWORD --url=\"http://chomikuj.pl/PATH\" [optional options] destination\n" . 782 | " php " . $argv[0] . " --user=USER --hash=MD5_PASSWORD --url=\"http://chomikuj.pl/PATH\" [optional options] destination\n\n" . 783 | "Required Options:\n" . 784 | " --user=USER Uses specified user name for authentication.\n" . 785 | " --password=PASSWORD Uses specified user password for authentication.\n" . 786 | " --hash=HASH Uses specified user password hash for authentication.\n" . 787 | " --url=URL Downloads files from the specified URL.\n\n" . 788 | "Optional Options:\n" . 789 | " -r, --recursive Downloads also all subdirectories.\n" . 790 | " -s, --structure Creates full folder structure.\n" . 791 | " -o, --overwrite Overwrites existing files.\n" . 792 | " -n, --noprogress Do not print progress.\n" . 793 | " --ext=EXTENSIONS Downloads files only with the specified extensions, separated by comma.\n" . 794 | " --max-limit=SIZE Do not download files with size greater than specified max (in bytes).\n" . 795 | " -h, --help, /? Shows this help.\n\n" . 796 | "NOTE:\n" . 797 | " - To log in you may use password OR hash.\n" . 798 | " - URLs must start with \"http://chomikuj.pl/\" and must NOT end with a slash.\n" . 799 | " - By default the script downloads files into the folder from where it was run.\n\n" . 800 | "Examples:\n" . 801 | " php " . $argv[0] . " --user=chomikoryba --password=ryba123 --url=\"http://chomikuj.pl/chomikoryba\" -r -s downloads\n" . 802 | " php " . $argv[0] . " --user=chomikoryba --hash=233b5774ada09b36458f69a04c9718e9 --url=\"http://chomikuj.pl/chomikoryba/Myriad+Pro+%28CE%29-TTF\" -r --ext=\"ttf,otf\" fonts\n" . 803 | "\n"; 804 | 805 | exit; 806 | } 807 | 808 | if (empty($args[0])) 809 | // No destination folder. 810 | $args[0] = './'; 811 | 812 | $chomikuj = new Chomikuj($args); 813 | 814 | $chomikuj->downloadFiles( 815 | // List of URLs. Single URL accepted. 816 | array($args['url']), 817 | 818 | // Destination folder. 819 | $args[0], 820 | 821 | // Recurse into subdirectories. 822 | !empty($args['recursive']), 823 | 824 | // Create folder structure. 825 | !empty($args['structure']), 826 | 827 | // Overwrite existing files. 828 | !empty($args['overwrite']), 829 | 830 | // Do not print progress 831 | !empty($args['noprogress']), 832 | 833 | // Pass original arguments. 834 | $args 835 | ); 836 | } 837 | --------------------------------------------------------------------------------